Advertisement
fatboychummy

Potential 1.12.2 websocket fix

Apr 9th, 2023 (edited)
719
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.40 KB | None | 0 0
  1. local function minver(version)
  2.   local res
  3.   if _CC_VERSION then res = version <= _CC_VERSION
  4.   elseif not _HOST then res = version <= os.version():gsub("CraftOS ", "")
  5.   elseif _HOST:match("ComputerCraft 1%.1%d+") ~= version:match("1%.1%d+") then
  6.     version = version:gsub("(1%.)([02-9])", "%10%2")
  7.     local host = _HOST:gsub("(ComputerCraft 1%.)([02-9])", "%10%2")
  8.     res = version <= host:match("ComputerCraft ([0-9%.]+)")
  9.   else res = version <= _HOST:match("ComputerCraft ([0-9%.]+)") end
  10.   assert(res, "This program requires ComputerCraft " .. version .. " or later.")
  11. end
  12. minver "1.85.0"
  13. local url = "wss://remote.craftos-pc.cc/"
  14. if not string.pack then
  15.   if not fs.exists("string_pack.lua") then
  16.       print("Downloading string.pack polyfill...")
  17.       local handle, err = http.get(url:gsub("^ws", "http") .. "string_pack.lua")
  18.       if not handle then error("Could not download string.pack polyfill: " .. err) end
  19.       local file, err = fs.open("string_pack.lua", "w")
  20.       if not file then handle.close() error("Could not open string_pack.lua for writing: " .. err) end
  21.       file.write(handle.readAll())
  22.       handle.close()
  23.       file.close()
  24.   end
  25.   local sp = dofile "string_pack.lua"
  26.   for k,v in pairs(sp) do string[k] = v end
  27. end
  28. local rawterm
  29. if not fs.exists("rawterm.lua") or fs.getSize("rawterm.lua") ~= [[${SIZE}]] then
  30.   print("Downloading rawterm API...")
  31.   local handle, err = http.get(url:gsub("^ws", "http") .. "rawterm.lua")
  32.   if not handle then error("Could not download rawterm API: " .. err) end
  33.   local data = handle.readAll()
  34.   handle.close()
  35.   if fs.getFreeSpace("/") >= #data + 4096 then
  36.       local file, err = fs.open("rawterm.lua", "w")
  37.       if not file then error("Could not open rawterm.lua for writing: " .. err) end
  38.       file.write(data)
  39.       file.close()
  40.   else rawterm = assert(load(data, "@rawterm.lua", "t"))() end
  41. end
  42. rawterm = rawterm or dofile "rawterm.lua"
  43.  
  44. local arg, cmd = ...
  45. print("Connecting to " .. url .. "...")
  46. local conn, err = rawterm.wsDelegate(url .. arg, {["X-Rawterm-Is-Server"] = "Yes"})
  47. if not conn then error("Could not connect to server: " .. err) end
  48. local oldClose, oldReceive = conn.close, function()
  49.   local full_url = url .. arg
  50.   while true do
  51.     local _, ws_url, contents, binary = os.pullEvent("websocket_message")
  52.     if ws_url == full_url then
  53.       return contents, binary
  54.     end
  55.   end
  56. end
  57. local isOpen = true
  58. function conn:close() isOpen = false return oldClose(self) end
  59. function conn:receive(...) local res repeat res = table.pack(pcall(oldReceive, self, ...)) until not (not ok and res[2]:match("Terminated$")) return table.unpack(res, 2, res.n) end
  60. local w, h = term.getSize()
  61. local win = rawterm.server(conn, w, h, 0, "ComputerCraft Remote Terminal: " .. (os.computerLabel() or ("Computer " .. os.computerID())), term.current())
  62. win.setVisible(false)
  63. local monitors, ids = {}, {[0] = true}
  64. local oldcall = peripheral.call
  65. for i, v in ipairs{peripheral.find "monitor"} do
  66.   local mw, mh = v.getSize()
  67.   local name = peripheral.getName(v)
  68.   local methods = peripheral.getMethods(name)
  69.   local p = {}
  70.   for _, v in ipairs(methods) do p[v] = function(...) return oldcall(name, v, ...) end end
  71.   monitors[name] = {id = i, win = rawterm.server(conn, mw, mh, i, "ComputerCraft Remote Terminal: Monitor " .. name, p, nil, nil, nil, true)}
  72.   monitors[name].win.setVisible(false)
  73.   ids[i] = true
  74. end
  75. function peripheral.call(side, method, ...)
  76.   if monitors[side] then return monitors[side].win[method](...)
  77.   else return oldcall(side, method, ...) end
  78. end
  79. local oldterm = term.redirect(win)
  80. local ok, tm
  81. ok, err = pcall(parallel.waitForAny, function()
  82.   local coro = coroutine.create(shell.run)
  83.   local ok, filter = coroutine.resume(coro, cmd or (settings.get("bios.use_multishell") and "multishell" or "shell"))
  84.   while ok and coroutine.status(coro) == "suspended" do
  85.       local ev = {}
  86.       local pullers = {function() ev = table.pack(win.pullEvent(filter, true, true)) end}
  87.       for k, v in pairs(monitors) do pullers[#pullers+1] = function()
  88.           ev = table.pack(v.win.pullEvent(filter, true, true))
  89.           if ev[1] == "mouse_click" then ev = {"monitor_touch", k, ev[3], ev[4]}
  90.           elseif ev[1] == "mouse_up" or ev[1] == "mouse_drag" or ev[1] == "mouse_scroll" or ev[1] == "mouse_move" then ev = {} end
  91.       end end
  92.       pullers[#pullers+1] = function()
  93.           repeat ev = table.pack(os.pullEventRaw(filter)) until not (ev[1] == "websocket_message" and ev[2] == url .. arg) and not (ev[1] == "timer" and ev[2] == tm)
  94.       end
  95.       parallel.waitForAny(table.unpack(pullers))
  96.       if ev[1] then ok, filter = coroutine.resume(coro, table.unpack(ev, 1, ev.n)) end
  97.   end
  98.   if not ok then err = filter end
  99. end, function()
  100.   while isOpen do
  101.       win.setVisible(true)
  102.       win.setVisible(false)
  103.       for _, v in pairs(monitors) do
  104.           v.win.setVisible(true)
  105.           v.win.setVisible(false)
  106.       end
  107.       tm = os.startTimer(0.05)
  108.       repeat local ev, p = os.pullEventRaw("timer") until p == tm
  109.   end
  110. end, function()
  111.   while true do
  112.       local ev, side = os.pullEventRaw()
  113.       if ev == "peripheral" and peripheral.getType(side) == "monitor" and not monitors[side] then
  114.           local id = #ids + 1
  115.           local mw, mh = oldcall(side, "getSize")
  116.           local methods = peripheral.getMethods(side)
  117.           for _, v in ipairs(methods) do methods[v] = true end
  118.           local p = setmetatable({}, {__index = function(_, idx) if methods[idx] then return function(...) return oldcall(side, idx, ...) end end end})
  119.           monitors[side] = {id = id, win = rawterm.server(conn, mw, mh, id, "ComputerCraft Remote Terminal: Monitor " .. side, p, nil, nil, nil, true)}
  120.           monitors[side].win.setVisible(false)
  121.           ids[id] = true
  122.       elseif ev == "peripheral_detach" and monitors[side] then
  123.           monitors[side].win.close(true)
  124.           ids[monitors[side].id] = nil
  125.           monitors[side] = nil
  126.       elseif ev == "term_resize" then
  127.           win.reposition(nil, nil, term.getSize())
  128.       elseif ev == "monitor_resize" and monitors[side] then
  129.           monitors[side].win.reposition(nil, nil, oldcall(side, "getSize"))
  130.       end
  131.   end
  132. end)
  133. term.redirect(oldterm)
  134. for _, v in pairs(monitors) do v.win.close(true) end
  135. win.close()
  136. peripheral.call = oldcall
  137. shell.run("clear")
  138. if type(err) == "string" and not err:match("attempt to use closed file") then printError(err) end
  139.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement