Commencé à travailler sur le plugin NodeMCU pour Atom, mais j'ai des problèmes de 'delay' avec l'utilitaire luatool.py encore à régler, il va trop vite entre les commandes envoyées
This commit is contained in:
58
IDE_remote/SocketIDE/test1/init.lua
Normal file
58
IDE_remote/SocketIDE/test1/init.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
local bootreasons={
|
||||
[0]="power-on",
|
||||
[1]="hardware watchdog reset",
|
||||
[2]="exception reset",
|
||||
[3]="software watchdog reset",
|
||||
[4]="software restart",
|
||||
[5]="wake from deep sleep",
|
||||
[6]="external reset"
|
||||
}
|
||||
|
||||
local ip = wifi.sta.getip()
|
||||
if ip then
|
||||
print("already got:"..ip)
|
||||
else
|
||||
print("Connecting...")
|
||||
wifi.setmode(wifi.STATION)
|
||||
ip_cfg={}
|
||||
ip_cfg.ip = "192.168.6.90"
|
||||
ip_cfg.netmask = "255.255.255.0"
|
||||
ip_cfg.gateway = "192.168.6.1"
|
||||
wifi.sta.setip(ip_cfg)
|
||||
station_cfg={}
|
||||
station_cfg.ssid="holternet"
|
||||
station_cfg.pwd="nemosushi_sushinemo"
|
||||
wifi.sta.sethostname("mybutton1")
|
||||
wifi.sta.config(station_cfg)
|
||||
wifi.sta.connect()
|
||||
wifi.sta.autoconnect(1)
|
||||
|
||||
tmr.alarm(0, 1000, 1, function ()
|
||||
local ip = wifi.sta.getip()
|
||||
if ip then
|
||||
tmr.stop(0)
|
||||
print(ip)
|
||||
end
|
||||
end)
|
||||
end
|
||||
dofile("websocket.lc")
|
||||
dofile("main.lc")
|
||||
if file.exists("userinit.lua") then
|
||||
--[[
|
||||
0, power-on
|
||||
1, hardware watchdog reset
|
||||
2, exception reset
|
||||
3, software watchdog reset
|
||||
4, software restart
|
||||
5, wake from deep sleep
|
||||
6, external reset
|
||||
]]
|
||||
_ , reason = node.bootreason()
|
||||
if (reason<1 or reason > 3) then
|
||||
dofile("userinit.lua")
|
||||
else
|
||||
print ("Bootreason="..reason.." ("..bootreasons[reason].."), skipping userinit.lua")
|
||||
end
|
||||
else
|
||||
print("userinit.lua not found")
|
||||
end
|
||||
365
IDE_remote/SocketIDE/test1/luatool.py
Executable file
365
IDE_remote/SocketIDE/test1/luatool.py
Executable file
@@ -0,0 +1,365 @@
|
||||
#!/usr/bin/env python2
|
||||
#zf191020.1453
|
||||
|
||||
#
|
||||
# ESP8266 luatool
|
||||
# Author e-mail: 4ref0nt@gmail.com
|
||||
# Site: http://esp8266.ru
|
||||
# Contributions from: https://github.com/sej7278
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; either version 2 of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 51 Franklin
|
||||
# Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
import sys
|
||||
import serial
|
||||
from time import sleep
|
||||
import socket
|
||||
import argparse
|
||||
from os.path import basename
|
||||
|
||||
|
||||
tqdm_installed = True
|
||||
try:
|
||||
from tqdm import tqdm
|
||||
except ImportError, e:
|
||||
if e.message == 'No module named tqdm':
|
||||
tqdm_installed = False
|
||||
else:
|
||||
raise
|
||||
|
||||
version = "0.6.4"
|
||||
|
||||
|
||||
class TransportError(Exception):
|
||||
"""Custom exception to represent errors with a transport
|
||||
"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def __str__(self):
|
||||
return self.message
|
||||
|
||||
class AbstractTransport:
|
||||
def __init__(self):
|
||||
raise NotImplementedError('abstract transports cannot be instantiated.')
|
||||
|
||||
def close(self):
|
||||
raise NotImplementedError('Function not implemented')
|
||||
|
||||
def read(self, length):
|
||||
raise NotImplementedError('Function not implemented')
|
||||
|
||||
def writeln(self, data, check=1):
|
||||
raise NotImplementedError('Function not implemented')
|
||||
|
||||
def writer(self, data):
|
||||
self.writeln("file.writeline([==[" + data + "]==])\r")
|
||||
|
||||
def performcheck(self, expected):
|
||||
line = ''
|
||||
char = ''
|
||||
i = -1
|
||||
while char != chr(62): # '>'
|
||||
char = self.read(1)
|
||||
if char == '':
|
||||
raise Exception('No proper answer from MCU')
|
||||
if char == chr(13) or char == chr(10): # LF or CR
|
||||
if line != '':
|
||||
line = line.strip()
|
||||
if line+'\r' == expected and not args.bar:
|
||||
sys.stdout.write(" -> ok")
|
||||
elif line+'\r' != expected:
|
||||
if line[:4] == "lua:":
|
||||
sys.stdout.write("\r\n\r\nLua ERROR: %s" % line)
|
||||
raise Exception('ERROR from Lua interpreter\r\n\r\n')
|
||||
else:
|
||||
expected = expected.split("\r")[0]
|
||||
sys.stdout.write("\r\n\r\nERROR")
|
||||
sys.stdout.write("\r\n send string : '%s'" % expected)
|
||||
sys.stdout.write("\r\n expected echo : '%s'" % expected)
|
||||
sys.stdout.write("\r\n but got answer : '%s'" % line)
|
||||
sys.stdout.write("\r\n\r\n")
|
||||
raise Exception('Error sending data to MCU\r\n\r\n')
|
||||
line = ''
|
||||
else:
|
||||
line += char
|
||||
if char == chr(62) and expected[i] == char:
|
||||
char = ''
|
||||
i += 1
|
||||
|
||||
|
||||
class SerialTransport(AbstractTransport):
|
||||
def __init__(self, port, baud, delay):
|
||||
self.port = port
|
||||
self.baud = baud
|
||||
self.serial = None
|
||||
self.delay = delay
|
||||
|
||||
try:
|
||||
self.serial = serial.Serial(port, baud)
|
||||
except serial.SerialException as e:
|
||||
raise TransportError(e.strerror)
|
||||
|
||||
self.serial.timeout = 3
|
||||
self.serial.interCharTimeout = 3
|
||||
|
||||
def writeln(self, data, check=1):
|
||||
if self.serial.inWaiting() > 0:
|
||||
self.serial.flushInput()
|
||||
if len(data) > 0 and not args.bar:
|
||||
sys.stdout.write("\r\n->")
|
||||
sys.stdout.write(data.split("\r")[0])
|
||||
self.serial.write(data)
|
||||
print("le delay est: "+str(self.delay))
|
||||
sleep(self.delay)
|
||||
if check > 0:
|
||||
self.performcheck(data)
|
||||
elif not args.bar:
|
||||
sys.stdout.write(" -> send without check")
|
||||
|
||||
def read(self, length):
|
||||
return self.serial.read(length)
|
||||
|
||||
def close(self):
|
||||
self.serial.flush()
|
||||
self.serial.close()
|
||||
|
||||
|
||||
class TcpSocketTransport(AbstractTransport):
|
||||
def __init__(self, host, port):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.socket = None
|
||||
|
||||
try:
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
except socket.error as e:
|
||||
raise TransportError(e.strerror)
|
||||
|
||||
try:
|
||||
self.socket.connect((host, port))
|
||||
except socket.error as e:
|
||||
raise TransportError(e.strerror)
|
||||
# read intro from telnet server (see telnet_srv.lua)
|
||||
self.socket.recv(50)
|
||||
|
||||
def writeln(self, data, check=1):
|
||||
if len(data) > 0 and not args.bar:
|
||||
sys.stdout.write("\r\n->")
|
||||
sys.stdout.write(data.split("\r")[0])
|
||||
self.socket.sendall(data)
|
||||
if check > 0:
|
||||
self.performcheck(data)
|
||||
elif not args.bar:
|
||||
sys.stdout.write(" -> send without check")
|
||||
|
||||
def read(self, length):
|
||||
return self.socket.recv(length)
|
||||
|
||||
def close(self):
|
||||
self.socket.close()
|
||||
|
||||
|
||||
def decidetransport(cliargs):
|
||||
if cliargs.ip:
|
||||
data = cliargs.ip.split(':')
|
||||
host = data[0]
|
||||
if len(data) == 2:
|
||||
port = int(data[1])
|
||||
else:
|
||||
port = 23
|
||||
return TcpSocketTransport(host, port)
|
||||
else:
|
||||
return SerialTransport(cliargs.port, cliargs.baud, cliargs.delay)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# parse arguments or use defaults
|
||||
parser = argparse.ArgumentParser(description='ESP8266 Lua script uploader.')
|
||||
parser.add_argument('-p', '--port', default='/dev/ttyUSB0', help='Device name, default /dev/ttyUSB0')
|
||||
parser.add_argument('-b', '--baud', default=9600, help='Baudrate, default 9600')
|
||||
parser.add_argument('-f', '--src', default='main.lua', help='Source file on computer, default main.lua')
|
||||
parser.add_argument('-t', '--dest', default=None, help='Destination file on MCU, default to source file name')
|
||||
parser.add_argument('-c', '--compile', action='store_true', help='Compile lua to lc after upload')
|
||||
parser.add_argument('-r', '--restart', action='store_true', help='Restart MCU after upload')
|
||||
parser.add_argument('-d', '--dofile', action='store_true', help='Run the Lua script after upload')
|
||||
parser.add_argument('-v', '--verbose', action='store_true', help="Show progress messages.")
|
||||
parser.add_argument('-a', '--append', action='store_true', help='Append source file to destination file.')
|
||||
parser.add_argument('-l', '--list', action='store_true', help='List files on device')
|
||||
parser.add_argument('-w', '--wipe', action='store_true', help='Delete all lua/lc files on device.')
|
||||
parser.add_argument('-i', '--id', action='store_true', help='Query the modules chip id.')
|
||||
parser.add_argument('-e', '--echo', action='store_true', help='Echo output of MCU until script is terminated.')
|
||||
parser.add_argument('--bar', action='store_true', help='Show a progress bar for uploads instead of printing each line')
|
||||
parser.add_argument('--delay', default=0.3, help='Delay in seconds between each write.', type=float)
|
||||
parser.add_argument('--delete', default=None, help='Delete a lua/lc file from device.')
|
||||
parser.add_argument('--ip', default=None, help='Connect to a telnet server on the device (--ip IP[:port])')
|
||||
args = parser.parse_args()
|
||||
|
||||
transport = decidetransport(args)
|
||||
|
||||
if args.bar and not tqdm_installed:
|
||||
sys.stdout.write("You must install the tqdm library to use the bar feature\n")
|
||||
sys.stdout.write("To install, at the prompt type: \"pip install tqdm\"\n")
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if args.list:
|
||||
print("toto1456")
|
||||
#sleep(0.5)
|
||||
print("toto1458")
|
||||
|
||||
transport.writeln("local l = file.list();for k,v in pairs(l) do print('name:'..k..', size:'..v)end\r", 0)
|
||||
while True:
|
||||
char = transport.read(1)
|
||||
if char == '' or char == chr(62):
|
||||
break
|
||||
sys.stdout.write(char)
|
||||
sys.exit(0)
|
||||
|
||||
if args.id:
|
||||
transport.writeln("=node.chipid()\r", 0)
|
||||
id=""
|
||||
while True:
|
||||
char = transport.read(1)
|
||||
if char == '' or char == chr(62):
|
||||
break
|
||||
if char.isdigit():
|
||||
id += char
|
||||
print("\n"+id)
|
||||
sys.exit(0)
|
||||
|
||||
if args.wipe:
|
||||
transport.writeln("local l = file.list();for k,v in pairs(l) do print(k)end\r", 0)
|
||||
file_list = []
|
||||
fn = ""
|
||||
while True:
|
||||
char = transport.read(1)
|
||||
if char == '' or char == chr(62):
|
||||
break
|
||||
if char not in ['\r', '\n']:
|
||||
fn += char
|
||||
else:
|
||||
if fn:
|
||||
file_list.append(fn.strip())
|
||||
fn = ''
|
||||
for fn in file_list[1:]: # first line is the list command sent to device
|
||||
if args.verbose:
|
||||
sys.stderr.write("Delete file {} from device.\r\n".format(fn))
|
||||
transport.writeln("file.remove(\"" + fn + "\")\r")
|
||||
sys.exit(0)
|
||||
|
||||
if args.delete:
|
||||
transport.writeln("file.remove(\"" + args.delete + "\")\r")
|
||||
sys.exit(0)
|
||||
|
||||
if args.dest is None:
|
||||
args.dest = basename(args.src)
|
||||
|
||||
# open source file for reading
|
||||
try:
|
||||
try:
|
||||
f = open(args.src, "rt")
|
||||
except:
|
||||
import os
|
||||
base_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
f = open(os.path.join(base_dir, args.src), "rt")
|
||||
os.chdir(base_dir)
|
||||
except:
|
||||
sys.stderr.write("Could not open input file \"%s\"\n" % args.src)
|
||||
sys.exit(1)
|
||||
|
||||
# Verify the selected file will not exceed the size of the serial buffer.
|
||||
# The size of the buffer is 256. This script does not accept files with
|
||||
# lines longer than 230 characters to have some room for command overhead.
|
||||
num_lines = 0
|
||||
for ln in f:
|
||||
if len(ln) > 230:
|
||||
sys.stderr.write("File \"%s\" contains a line with more than 240 "
|
||||
"characters. This exceeds the size of the serial buffer.\n"
|
||||
% args.src)
|
||||
f.close()
|
||||
sys.exit(1)
|
||||
num_lines += 1
|
||||
|
||||
# Go back to the beginning of the file after verifying it has the correct
|
||||
# line length
|
||||
f.seek(0)
|
||||
|
||||
# set serial timeout
|
||||
if args.verbose:
|
||||
sys.stderr.write("Upload starting\r\n")
|
||||
|
||||
# remove existing file on device
|
||||
if args.append==False:
|
||||
if args.verbose:
|
||||
sys.stderr.write("Stage 1. Deleting old file from flash memory")
|
||||
transport.writeln("file.open(\"" + args.dest + "\", \"w\")\r")
|
||||
transport.writeln("file.close()\r")
|
||||
transport.writeln("file.remove(\"" + args.dest + "\")\r")
|
||||
else:
|
||||
if args.verbose:
|
||||
sys.stderr.write("[SKIPPED] Stage 1. Deleting old file from flash memory [SKIPPED]")
|
||||
|
||||
|
||||
# read source file line by line and write to device
|
||||
if args.verbose:
|
||||
sys.stderr.write("\r\nStage 2. Creating file in flash memory and write first line")
|
||||
if args.append:
|
||||
transport.writeln("file.open(\"" + args.dest + "\", \"a+\")\r")
|
||||
else:
|
||||
transport.writeln("file.open(\"" + args.dest + "\", \"w+\")\r")
|
||||
line = f.readline()
|
||||
if args.verbose:
|
||||
sys.stderr.write("\r\nStage 3. Start writing data to flash memory...")
|
||||
if args.bar:
|
||||
for i in tqdm(range(0, num_lines)):
|
||||
transport.writer(line.strip())
|
||||
line = f.readline()
|
||||
else:
|
||||
while line != '':
|
||||
transport.writer(line.strip())
|
||||
line = f.readline()
|
||||
|
||||
# close both files
|
||||
f.close()
|
||||
if args.verbose:
|
||||
sys.stderr.write("\r\nStage 4. Flush data and closing file")
|
||||
transport.writeln("file.flush()\r")
|
||||
transport.writeln("file.close()\r")
|
||||
|
||||
# compile?
|
||||
if args.compile:
|
||||
if args.verbose:
|
||||
sys.stderr.write("\r\nStage 5. Compiling")
|
||||
transport.writeln("node.compile(\"" + args.dest + "\")\r")
|
||||
transport.writeln("file.remove(\"" + args.dest + "\")\r")
|
||||
|
||||
# restart or dofile
|
||||
if args.restart:
|
||||
transport.writeln("node.restart()\r")
|
||||
if args.dofile: # never exec if restart=1
|
||||
transport.writeln("dofile(\"" + args.dest + "\")\r", 0)
|
||||
|
||||
if args.echo:
|
||||
if args.verbose:
|
||||
sys.stderr.write("\r\nEchoing MCU output, press Ctrl-C to exit")
|
||||
while True:
|
||||
sys.stdout.write(transport.read(1))
|
||||
|
||||
# close serial port
|
||||
transport.close()
|
||||
|
||||
# flush screen
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
if not args.bar:
|
||||
sys.stderr.write("\r\n--->>> All done <<<---\r\n")
|
||||
63
IDE_remote/SocketIDE/test1/main.lua
Normal file
63
IDE_remote/SocketIDE/test1/main.lua
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
collectgarbage("setmemlimit", 4)
|
||||
websocket.createServer(80, function (socket)
|
||||
local data
|
||||
node.output(function (msg)
|
||||
return socket.send(msg, 1)
|
||||
end, 1)
|
||||
print("New websocket client connected")
|
||||
|
||||
function socket.onmessage(payload, opcode)
|
||||
if opcode == 1 then
|
||||
if payload == "ls" then
|
||||
local list = file.list()
|
||||
local lines = {}
|
||||
for k, v in pairs(list) do
|
||||
lines[#lines + 1] = k .. "\0" .. v
|
||||
end
|
||||
socket.send(table.concat(lines, "\0"), 2)
|
||||
return
|
||||
-- standard js websockets do not support ping/pong opcodes so we have to
|
||||
-- fake it
|
||||
elseif payload == "ping" then
|
||||
socket.send("pong", 2)
|
||||
return
|
||||
end
|
||||
local command, name = payload:match("^([a-z]+):(.*)$")
|
||||
if command == "load" then
|
||||
file.open(name, "r")
|
||||
socket.send(file.read(), 2)
|
||||
file.close()
|
||||
elseif command == "save" then
|
||||
file.open(name, "w")
|
||||
file.write(data)
|
||||
data = nil
|
||||
file.close()
|
||||
print("saved:"..name)
|
||||
elseif command == "compile" then
|
||||
node.compile(name)
|
||||
print("compiled:"..name)
|
||||
elseif command == "run" then
|
||||
dofile(name)
|
||||
elseif command == "eval" then
|
||||
local fn, success, err
|
||||
fn, err = loadstring(data, name)
|
||||
if not fn then
|
||||
fn = loadstring("print(" .. data .. ")", name)
|
||||
end
|
||||
data = nil
|
||||
if fn then
|
||||
success, err = pcall(fn)
|
||||
end
|
||||
if not success then
|
||||
print(err)
|
||||
end
|
||||
else
|
||||
print("Invalid command: " .. command)
|
||||
end
|
||||
elseif opcode == 2 then
|
||||
data = payload
|
||||
end
|
||||
collectgarbage("setmemlimit", 4)
|
||||
end
|
||||
end)
|
||||
26
IDE_remote/SocketIDE/test1/toto.lua
Normal file
26
IDE_remote/SocketIDE/test1/toto.lua
Normal file
@@ -0,0 +1,26 @@
|
||||
print("c'est toto")
|
||||
|
||||
--l = file.list();for k,v in pairs(l) do print('name:'..k..', size:'..v)end
|
||||
|
||||
function dir2()
|
||||
l = file.list();for k,v in pairs(l) do print('name:'..k..', size:'..v)end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function dir()
|
||||
print("\n-------------------------------")
|
||||
l=file.list() i=0
|
||||
for k,v in pairs(l) do
|
||||
i=i+v
|
||||
print(k..string.rep(" ",19-string.len(k)).." : "..v.." bytes")
|
||||
end
|
||||
print("-------------------------------")
|
||||
print('\nUsed: '..i..' bytes\nusage: dofile("file.lua")\n')
|
||||
end
|
||||
|
||||
--[[
|
||||
dir()
|
||||
dir2()
|
||||
|
||||
]]
|
||||
10
IDE_remote/SocketIDE/test1/upload.sh
Executable file
10
IDE_remote/SocketIDE/test1/upload.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Petit script pour télécharger facilement tout le binz
|
||||
#zf191020.1427
|
||||
|
||||
chmod +x luatool.py
|
||||
./luatool.py --port /dev/cu.wchusbserial1410 -l
|
||||
./luatool.py --port /dev/cu.wchusbserial1410 -f websocket.lua -c
|
||||
./luatool.py --port /dev/cu.wchusbserial1410 -f main.lua -c
|
||||
./luatool.py --port /dev/cu.wchusbserial1410 -f init.lua
|
||||
./luatool.py --port /dev/cu.wchusbserial1410 -l
|
||||
141
IDE_remote/SocketIDE/test1/websocket.lua
Normal file
141
IDE_remote/SocketIDE/test1/websocket.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
do
|
||||
local websocket = {}
|
||||
_G.websocket = websocket
|
||||
local band = bit.band
|
||||
local bor = bit.bor
|
||||
local rshift = bit.rshift
|
||||
local lshift = bit.lshift
|
||||
local char = string.char
|
||||
local byte = string.byte
|
||||
local sub = string.sub
|
||||
local applyMask = crypto.mask
|
||||
local toBase64 = crypto.toBase64
|
||||
local hash = crypto.hash
|
||||
|
||||
local function decode(chunk)
|
||||
if #chunk < 2 then return end
|
||||
local second = byte(chunk, 2)
|
||||
local len = band(second, 0x7f)
|
||||
local offset
|
||||
if len == 126 then
|
||||
if #chunk < 4 then return end
|
||||
len = bor(
|
||||
lshift(byte(chunk, 3), 8),
|
||||
byte(chunk, 4))
|
||||
offset = 4
|
||||
elseif len == 127 then
|
||||
if #chunk < 10 then return end
|
||||
len = bor(
|
||||
-- Ignore lengths longer than 32bit
|
||||
lshift(byte(chunk, 7), 24),
|
||||
lshift(byte(chunk, 8), 16),
|
||||
lshift(byte(chunk, 9), 8),
|
||||
byte(chunk, 10))
|
||||
offset = 10
|
||||
else
|
||||
offset = 2
|
||||
end
|
||||
local mask = band(second, 0x80) > 0
|
||||
if mask then
|
||||
offset = offset + 4
|
||||
end
|
||||
if #chunk < offset + len then return end
|
||||
local first = byte(chunk, 1)
|
||||
local payload = sub(chunk, offset + 1, offset + len)
|
||||
assert(#payload == len, "Length mismatch")
|
||||
if mask then
|
||||
payload = applyMask(payload, sub(chunk, offset - 3, offset))
|
||||
end
|
||||
local extra = sub(chunk, offset + len + 1)
|
||||
local opcode = band(first, 0xf)
|
||||
return extra, payload, opcode
|
||||
end
|
||||
|
||||
local function encode(payload, opcode)
|
||||
opcode = opcode or 2
|
||||
assert(type(opcode) == "number", "opcode must be number")
|
||||
assert(type(payload) == "string", "payload must be string")
|
||||
local len = #payload
|
||||
local head = char(
|
||||
bor(0x80, opcode),
|
||||
bor(len < 126 and len or len < 0x10000 and 126 or 127)
|
||||
)
|
||||
if len >= 0x10000 then
|
||||
head = head .. char(
|
||||
0,0,0,0, -- 32 bit length is plenty, assume zero for rest
|
||||
band(rshift(len, 24), 0xff),
|
||||
band(rshift(len, 16), 0xff),
|
||||
band(rshift(len, 8), 0xff),
|
||||
band(len, 0xff)
|
||||
)
|
||||
elseif len >= 126 then
|
||||
head = head .. char(band(rshift(len, 8), 0xff), band(len, 0xff))
|
||||
end
|
||||
return head .. payload
|
||||
end
|
||||
|
||||
local guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
|
||||
local function acceptKey(key)
|
||||
return toBase64(hash("sha1", key .. guid))
|
||||
end
|
||||
|
||||
function websocket.createServer(port, callback)
|
||||
net.createServer(net.TCP):listen(port, function(conn)
|
||||
local buffer = false
|
||||
local socket = {}
|
||||
local queue = {}
|
||||
local waiting = false
|
||||
local function onSend()
|
||||
if queue[1] then
|
||||
local data = table.remove(queue, 1)
|
||||
return conn:send(data, onSend)
|
||||
end
|
||||
waiting = false
|
||||
end
|
||||
function socket.send(...)
|
||||
local data = encode(...)
|
||||
if not waiting then
|
||||
waiting = true
|
||||
conn:send(data, onSend)
|
||||
else
|
||||
queue[#queue + 1] = data
|
||||
end
|
||||
end
|
||||
|
||||
conn:on("receive", function(_, chunk)
|
||||
if buffer then
|
||||
buffer = buffer .. chunk
|
||||
while true do
|
||||
local extra, payload, opcode = decode(buffer)
|
||||
if not extra then return end
|
||||
buffer = extra
|
||||
socket.onmessage(payload, opcode)
|
||||
end
|
||||
end
|
||||
local _, e, method = string.find(chunk, "([A-Z]+) /[^\r]* HTTP/%d%.%d\r\n")
|
||||
local key, name, value
|
||||
while true do
|
||||
_, e, name, value = string.find(chunk, "([^ ]+): *([^\r]+)\r\n", e + 1)
|
||||
if not e then break end
|
||||
if string.lower(name) == "sec-websocket-key" then
|
||||
key = value
|
||||
end
|
||||
end
|
||||
|
||||
if method == "GET" and key then
|
||||
conn:send(
|
||||
"HTTP/1.1 101 Switching Protocols\r\n" ..
|
||||
"Upgrade: websocket\r\nConnection: Upgrade\r\n" ..
|
||||
"Sec-WebSocket-Accept: " .. acceptKey(key) .. "\r\n\r\n",
|
||||
function () callback(socket) end)
|
||||
buffer = ""
|
||||
else
|
||||
conn:send(
|
||||
"HTTP/1.1 404 Not Found\r\nConnection: Close\r\n\r\n",
|
||||
conn.close)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
end
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user