Advertisement
slipers

py

Mar 21st, 2022 (edited)
1,078
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.01 KB | None | 0 0
  1. local genv = getfenv()
  2. local temp = {}
  3. local event_sub = {}
  4. genv.temp = temp
  5. local url = 'ws://127.0.0.1:25585/'
  6. local proto_version = 3
  7. local tasks = {}
  8. local filters = {}
  9. local ycounts = {}
  10. local coparams = {}
  11.  
  12. local ws = http.websocket(url..'ws/')
  13. if ws == false then
  14.     error('Unable to connect to server '..url..'ws/')
  15. end
  16.  
  17. local serialize
  18. do
  19.     local function s_rec(v, tracking)
  20.         local t = type(v)
  21.         if v == nil then
  22.             return 'N'
  23.         elseif v == false then
  24.             return 'F'
  25.         elseif v == true then
  26.             return 'T'
  27.         elseif t == 'number' then
  28.             return '\[' .. tostring(v) .. '\]'
  29.         elseif t == 'string' then
  30.             return string.format('<%u>', #v) .. v
  31.         elseif t == 'table' then
  32.             if tracking[v] ~= nil then
  33.                 error('Cannot serialize table with recursive entries', 0)
  34.             end
  35.             tracking[v] = true
  36.             local r = '{'
  37.             for k, x in pairs(v) do
  38.                 r = r .. ':' .. s_rec(k, tracking) .. s_rec(x, tracking)
  39.             end
  40.             return r .. '}'
  41.         else
  42.             error('Cannot serialize type ' .. t, 0)
  43.         end
  44.         local tp = type(t)
  45.     end
  46.     serialize = function(v) return s_rec(v, {}) end
  47. end
  48.  
  49. function create_stream(s, idx)
  50.     if idx == nil then idx = 1 end
  51.     return {
  52.         getidx=function() return idx end,
  53.         isend=function() return idx > #s end,
  54.         fixed=function(n)
  55.             local r = s:sub(idx, idx + n - 1)
  56.             if #r ~= n then error('Unexpected end of stream') end
  57.             idx = idx + n
  58.             return r
  59.         end,
  60.         tostop=function(sym)
  61.             local newidx = s:find(sym, idx, true)
  62.             if newidx == nil then error('Unexpected end of stream') end
  63.             local r = s:sub(idx, newidx - 1)
  64.             idx = newidx + 1
  65.             return r
  66.         end,
  67.     }
  68. end
  69.  
  70. function deserialize(stream)
  71.     local tok = stream.fixed(1)
  72.     if tok == 'N' then
  73.         return nil
  74.     elseif tok == 'F' then
  75.         return false
  76.     elseif tok == 'T' then
  77.         return true
  78.     elseif tok == '\[' then
  79.         return tonumber(stream.tostop('\]'))
  80.     elseif tok == '<' then
  81.         local slen = tonumber(stream.tostop('>'))
  82.         return stream.fixed(slen)
  83.     elseif tok == 'E' then
  84.         local slen = tonumber(stream.tostop('>'))
  85.         local fn = assert(loadstring(stream.fixed(slen)))
  86.         setfenv(fn, genv)
  87.         return fn()
  88.     elseif tok == '{' then
  89.         local r = {}
  90.         while true do
  91.             tok = stream.fixed(1)
  92.             if tok == ':' then
  93.                 local key = deserialize(stream)
  94.                 r[key] = deserialize(stream)
  95.             else break end
  96.         end
  97.         return r
  98.     else
  99.         error('Unknown token ' .. tok)
  100.     end
  101. end
  102.  
  103. function drop_task(task_id)
  104.     tasks[task_id] = nil
  105.     filters[task_id] = nil
  106.     ycounts[task_id] = nil
  107.     coparams[task_id] = nil
  108. end
  109.  
  110. function ws_send(action, ...)
  111.     local m = action
  112.     for _, v in ipairs(arg) do
  113.         m = m .. serialize(v)
  114.     end
  115.     ws.send(m, true)
  116. end
  117.  
  118. function safe_unpack(a)
  119.     -- nil-safe
  120.     return table.unpack(a, 1, table.maxn(a))
  121. end
  122.  
  123. ws_send('0', proto_version, os.getComputerID(), arg)
  124.  
  125. while true do
  126.     local event, p1, p2, p3, p4, p5 = os.pullEvent()
  127.  
  128.     if event == 'websocket_message' then
  129.         local msg = create_stream(p2)
  130.         local action = msg.fixed(1)
  131.  
  132.         if action == 'T' or action == 'I' then  -- new task
  133.             local task_id = deserialize(msg)
  134.             local code = deserialize(msg)
  135.             local params = deserialize(msg)
  136.  
  137.             local fn, err = loadstring(code)
  138.             if fn == nil then
  139.                 -- couldn't compile
  140.                 ws_send('T', task_id, serialize{false, err}, 0)
  141.             else
  142.                 setfenv(fn, genv)
  143.                 if action == 'I' then
  144.                     ws_send('T', task_id, serialize{fn(safe_unpack(params))}, 0)
  145.                 else
  146.                     tasks[task_id] = coroutine.create(fn)
  147.                     ycounts[task_id] = 0
  148.                     coparams[task_id] = params
  149.                 end
  150.             end
  151.         elseif action == 'D' then  -- drop tasks
  152.             while not msg.isend() do
  153.                 drop_task(deserialize(msg))
  154.             end
  155.         elseif action == 'S' or action == 'U' then  -- (un)subscribe to event
  156.             local event = deserialize(msg)
  157.             if action == 'S' then
  158.                 event_sub[event] = true
  159.             else
  160.                 event_sub[event] = nil
  161.             end
  162.         elseif action == 'C' then  -- close session
  163.             local err = deserialize(msg)
  164.             if err ~= nil then
  165.                 io.stderr:write(err .. '\n')
  166.             end
  167.             break
  168.         end
  169.     elseif event == 'websocket_closed' then
  170.         error('Connection with server has been closed')
  171.     elseif event_sub[event] == true then
  172.         ws_send('E', event, {p1, p2, p3, p4, p5})
  173.     end
  174.  
  175.     local del_tasks = {}
  176.     for task_id in pairs(tasks) do
  177.         if filters[task_id] == nil or filters[task_id] == event then
  178.             local r
  179.             if coparams[task_id] ~= nil then
  180.                 r = {coroutine.resume(tasks[task_id], safe_unpack(coparams[task_id]))}
  181.                 coparams[task_id] = nil
  182.             else
  183.                 r = {coroutine.resume(tasks[task_id], event, p1, p2, p3, p4, p5)}
  184.             end
  185.             ycounts[task_id] = ycounts[task_id] + 1
  186.             if coroutine.status(tasks[task_id]) == 'dead' then
  187.                 ws_send('T', task_id, serialize(r), ycounts[task_id])
  188.                 del_tasks[task_id] = true
  189.             else
  190.                 if r[1] == true then
  191.                     filters[task_id] = r[2]
  192.                 else
  193.                     filters[task_id] = nil
  194.                 end
  195.             end
  196.         end
  197.     end
  198.     for task_id in pairs(del_tasks) do drop_task(task_id) end
  199. end
  200.  
  201. ws.close()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement