Skip to content

Instantly share code, notes, and snippets.

@gdyr
Last active January 17, 2023 22:50
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save gdyr/cea5ef01015dbd5750b98ccb3dd5d95d to your computer and use it in GitHub Desktop.
Save gdyr/cea5ef01015dbd5750b98ccb3dd5d95d to your computer and use it in GitHub Desktop.
S = TcpSocket.New();
S.EventHandler = print;
S:Connect(<HOST>, 80);
S.ReconnectTimeout = 0;
function randomWebSocketKey()
return Crypto.Base64Encode(('x'):rep(16):gsub('.', function() return string.char(math.random(0,255)) end));
end;
S.Connected = function()
Mode = 'HTTP';
print('CONNECTED');
S:Write(table.concat({
'GET / HTTP/1.1',
'Host: <HOST>',
'Connection: Upgrade',
'Upgrade: websocket',
'Sec-WebSocket-Version: 13',
'Sec-WebSocket-Key: ' .. randomWebSocketKey()
}, '\r\n').. '\r\n\r\n');
end;
function send(data)
print('> ' .. data);
local len, epl = #data, '';
if len > 125 and len <= 0xffff then epl = bitstring.pack('16:int', len); len = 126;
elseif len > 125 and len < 2^53 then epl = bitstring.pack('64:int', len); len = 127; end
local frame = bitstring.pack('1:int, 3:int, 4:int 1:int 7:int', 1, 0, 1, 1, len) .. epl .. '\0\0\0\0' .. data;
S:Write(frame);
end;
Mode = 'HTTP';
S.Data = function(sock)
if(Mode == 'HTTP') then
for http in function() return sock:ReadLine(TcpSocket.EOL.Custom, '\r\n\r\n'); end do
local code = http:match('^[^ ]+ (%d+)');
if(code == '101') then
Mode = 'WS-INIT';
send(<ON-CONNECT MESSAGE>);
end;
end;
end;
while(true) do
if(Mode == 'WS-INIT') then
if(sock.BufferLength < 2) then return; end;
local fin, rsv, opcode, mask, len = bitstring.unpack('1:int 3:int 4:int 1:int 7:int', sock:Read(2));
local sbuf = Packet and Packet.fin and Packet.buf or nil;
Packet = { fin=fin, rsv=rsv, opcode=opcode, mask=mask, len=len };
if(len > 125) then Mode = 'WS-EPL';
else Mode = 'WS-PAYLOAD'; end;
end;
if(Mode == 'WS-EPL') then
if(Packet.len == 126) then
if(sock.BufferLength < 2) then return; end;
Packet.len = bitstring.unpack('16:int', sock:Read(2));
Mode = 'WS-PAYLOAD';
elseif(Packet.len == 127) then
if(sock.BufferLength < 8) then return; end;
Packet.len = bitstring.unpack('64:int', sock:Read(8));
end;
end;
if(Mode == 'WS-PAYLOAD') then
if(sock.BufferLength < Packet.len) then return; end;
Mode = 'WS-INIT'; -- reset for handling of next frame
Buf = (Buf or '') .. sock:Read(Packet.len);
if(Packet.fin == 1) then
local msg = Buf; Buf = nil;
print('< ' .. msg);
local ok, data = pcall(json.decode, msg);
if(ok and data) then
-- handle message
end;
end;
end;
end;
end;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment