session.lua 2.59 KB
Newer Older
1 2 3
-- This is the file launched in a new thread for each user session on login.

local lume = require("lume")
4
local utf8 = require("polywell.utf8")
5
local shell = require("os.orb.shell")
6
local rpcs = require("os.orb.rpcs")
7 8
local fs = require("os.orb.fs")

9
local env, command, stdin, output, hostname = ...
10

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
local function completions_for(input, dir, prefixes)
   local input_parts = lume.split(input, "/")
   if(#input_parts == 1) then
      local matches = {}
      for _,v in pairs(fs.ls(dir, "/")) do
         if(fs.exists(v, dir) and utf8.sub(v, 1, #input) == input) then
            local parts = lume.clone(prefixes)
            table.insert(parts, v)
            if(fs.isdir(v, dir)) then table.insert(parts, "") end
            table.insert(matches, table.concat(parts, "/"))
         end
      end
      return matches
   else
      local first_part = table.remove(input_parts, 1)
      table.insert(prefixes, first_part)
      return completions_for(table.concat(input_parts, "/"),
28
                             dir .. "/" .. first_part, prefixes)
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
   end
end

local function read()
   local msg = stdin:demand()
   if(msg.op == "stdin") then
      return msg.stdin
   elseif(msg.op == "complete") then
      -- we are turning read into a generic RPC dispatch point, which we
      -- will likely turn out to regret! but it's our only entry point now.
      local ok, err = pcall(function()
            local dir = msg.input:match("^/") and "" or env.CWD
            local completions = completions_for(msg.input, dir, {})
            output:push({op="rpc", fn="completions",
                         args={completions, msg.input}})
      end)
      if(not ok) then
         print("OS handler error:", err)
         output:push({op="status", status="err", out=err})
      end
   else
      print("Unknown op!", lume.serialize(msg))
   end
   return read()
end
54 55 56 57 58 59 60 61 62 63

local write = function(...)
   local out = table.concat(lume.map({...}, tostring), " ")
   output:push({ op = "stdout", out = out })
end

local add_rpc = function(acc, name)
   acc[name] = function(...)
      local chan = love.thread.newChannel()
      output:push({op="rpc", fn=name, args={...}, chan=chan})
64 65 66 67 68 69 70
      local response = chan:demand()
      if(response[1] == "_error") then
         table.remove(response, 1)
         error(unpack(response))
      else
         return unpack(response)
      end
71 72 73 74
   end
   return acc
end

75 76
local ok, err = pcall(fs.init_if_needed, hostname)
if(not ok) then print("init err:", err) return false end
77

78
xpcall(shell.exec, function(e) print(e, debug.traceback()) end,
79
       env, command, lume.reduce(rpcs, add_rpc, {read = read, write = write}))