def frame(data, type = nil, code = nil)
return nil if @closed
is_text = (String === data)
opcode = OPCODES[type || (is_text ? :text : :binary)]
buffer = data.respond_to?(:bytes) ? data.bytes.to_a : data
insert = code ? 2 : 0
length = buffer.size + insert
header = (length <= 125) ? 2 : (length <= 65535 ? 4 : 10)
offset = header + (@masking ? 4 : 0)
masked = @masking ? MASK : 0
frame = Array.new(offset)
frame[0] = FIN | opcode
if length <= 125
frame[1] = masked | length
elsif length <= 65535
frame[1] = masked | 126
frame[2] = (length >> 8) & BYTE
frame[3] = length & BYTE
else
frame[1] = masked | 127
frame[2] = (length >> 56) & BYTE
frame[3] = (length >> 48) & BYTE
frame[4] = (length >> 40) & BYTE
frame[5] = (length >> 32) & BYTE
frame[6] = (length >> 24) & BYTE
frame[7] = (length >> 16) & BYTE
frame[8] = (length >> 8) & BYTE
frame[9] = length & BYTE
end
if code
buffer = [(code >> 8) & BYTE, code & BYTE] + buffer
end
if @masking
mask = [rand(256), rand(256), rand(256), rand(256)]
frame[header...offset] = mask
buffer = WebSocketMask.mask(buffer, mask)
end
frame.concat(buffer)
WebSocket.encode(frame)
end