Browse Source

Readd missing websocket code

Godzil 6 years ago
parent
commit
ed6cd63825
2 changed files with 137 additions and 0 deletions
  1. 2 0
      src/webide-compile.lua
  2. 135 0
      src/webide-websocket.lua

+ 2 - 0
src/webide-compile.lua

@@ -13,6 +13,8 @@ end
 
 local webideFiles = {
    'file-api.lua',
+   'webide-compile.lua',
+   'webide-websocket.lua',
 }
 for i, f in ipairs(webideFiles) do compileAndRemoveIfNeeded(f) end
 

+ 135 - 0
src/webide-websocket.lua

@@ -0,0 +1,135 @@
+--rewrite from https://github.com/creationix/nodemcu-webide
+
+local function decode(chunk)
+  if #chunk < 2 then return end
+  local second = string.byte(chunk, 2)
+  local len = bit.band(second, 0x7f)
+  local offset
+  if len == 126 then
+    if #chunk < 4 then return end
+    len = bit.bor(
+      bit.lshift(string.byte(chunk, 3), 8),
+      string.byte(chunk, 4))
+    offset = 4
+  elseif len == 127 then
+    if #chunk < 10 then return end
+    len = bit.bor(
+      -- Ignore lengths longer than 32bit
+      bit.lshift(string.byte(chunk, 7), 24),
+      bit.lshift(string.byte(chunk, 8), 16),
+      bit.lshift(string.byte(chunk, 9), 8),
+      string.byte(chunk, 10))
+    offset = 10
+  else
+    offset = 2
+  end
+  local mask = bit.band(second, 0x80) > 0
+  if mask then
+    offset = offset + 4
+  end
+  if #chunk < offset + len then return end
+
+  local first = string.byte(chunk, 1)
+  local payload = string.sub(chunk, offset + 1, offset + len)
+  assert(#payload == len, "Length mismatch")
+  if mask then
+    payload = crypto.mask(payload, string.sub(chunk, offset - 3, offset))
+  end
+  local extra = string.sub(chunk, offset + len + 1)
+  local opcode = bit.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 = string.char(
+    bit.bor(0x80, opcode),
+    bit.bor(len < 126 and len or len < 0x10000 and 126 or 127)
+  )
+  if len >= 0x10000 then
+    head = head .. string.char(
+    0,0,0,0, -- 32 bit length is plenty, assume zero for rest
+    bit.band(bit.rshift(len, 24), 0xff),
+    bit.band(bit.rshift(len, 16), 0xff),
+    bit.band(bit.rshift(len, 8), 0xff),
+    bit.band(len, 0xff)
+  )
+  elseif len >= 126 then
+    head = head .. string.char(bit.band(bit.rshift(len, 8), 0xff), bit.band(len, 0xff))
+  end
+  return head .. payload
+end
+
+local guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+local function acceptKey(key)
+  return crypto.toBase64(crypto.hash("sha1", key .. guid))
+end
+
+return function (connection, payload)
+  local buffer = false
+  local socket = {}
+  local queue = {}
+  local waiting = false
+  local function onSend()
+    if queue[1] then
+      local data = table.remove(queue, 1)
+      return connection:send(data, onSend)
+    end
+    waiting = false
+  end
+  function socket.send(...)
+    local data = encode(...)
+    if not waiting then
+      waiting = true
+      connection:send(data, onSend)
+    else
+      queue[#queue + 1] = data
+    end
+    collectgarbage()
+    print(node.heap())
+  end
+
+  connection: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
+  end)
+
+  connection:on("sent", function(_, _)
+    if socket.onsent ~= nil then
+      socket.onsent()
+    end
+  end)
+
+  connection:on("disconnection", function(_, _)
+    if socket.onclose ~= nil then
+      socket.onclose()
+    end
+  end)
+
+  local req = dofile("httpserver-request.lc")(payload)
+  local key = payload:match("Sec%-WebSocket%-Key: ([A-Za-z0-9+/=]+)")
+  local fileExists = file.open(req.uri.file, "r")
+  file.close()
+  if req.method == "GET" and key and fileExists then
+    connection: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 () dofile(req.uri.file)(socket) end)
+    buffer = ""
+  else
+    connection:send(
+      "HTTP/1.1 404 Not Found\r\nConnection: Close\r\n\r\n",
+      connection.close)
+  end
+end