Operating system for OpenComputers
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

98 wiersze
2.6KB

  1. local serial = require "serialization"
  2. local minitel = require "minitel"
  3. local event = require "event"
  4. local rpc = {}
  5. _G.rpcf = {}
  6. rpc.port = 111
  7. local function setacl(self, fname, host)
  8. self[fname] = self[fname] or {}
  9. self[fname][host] = true
  10. end
  11. rpc.allow = setmetatable({},{__call=setacl})
  12. rpc.deny = setmetatable({},{__call=setacl})
  13. local function isPermitted(host,fn)
  14. if rpc.allow[fn] then
  15. return rpc.allow[fn][host] or false
  16. end
  17. if rpc.deny[fn] and rpc.deny[fn][host] then
  18. return false
  19. end
  20. return true
  21. end
  22. local function rpcexec(_, from, port, data)
  23. os.spawn(function()
  24. if port == rpc.port then
  25. local rpcrq = serial.unserialize(data) or {}
  26. if rpcf[rpcrq[1]] and isPermitted(from,rpcrq[1]) then
  27. minitel.send(from,port,serial.serialize({rpcrq[2],pcall(rpcf[rpcrq[1]],table.unpack(rpcrq,3))}))
  28. elseif type(rpcrq[2]) == "string" then
  29. minitel.send(from,port,serial.serialize({rpcrq[2],false,"function unavailable"}))
  30. end
  31. end
  32. end,"rpc worker for "..tostring(from))
  33. end
  34. function rpcf.list()
  35. local rt = {}
  36. for k,v in pairs(rpcf) do
  37. rt[#rt+1] = k
  38. end
  39. return rt
  40. end
  41. function rpc.call(hostname,fn,...) -- string string -- boolean -- Calls exported function *fn* on host *hostname*, with parameters *...*, returning whatever the function returns, or false.
  42. if hostname == "localhost" then
  43. return rpcf[fn](...)
  44. end
  45. local rv = minitel.genPacketID()
  46. minitel.rsend(hostname,rpc.port,serial.serialize({fn,rv,...}),true)
  47. local st = computer.uptime()
  48. local rt = {}
  49. repeat
  50. local _, from, port, data = event.pull(30, "net_msg", hostname, rpc.port)
  51. rt = serial.unserialize(tostring(data)) or {}
  52. until (type(rt) == "table" and rt[1] == rv) or computer.uptime() > st + 30
  53. if rt[1] == rv then
  54. if rt[2] then
  55. return table.unpack(rt,3)
  56. end
  57. error(rt[3])
  58. end
  59. error("timed out")
  60. end
  61. function rpc.proxy(hostname,filter) -- string string -- table -- Returns a component.proxy()-like table from the functions on *hostname* with names matching *filter*.
  62. filter=(filter or "").."(.+)"
  63. local fnames = rpc.call(hostname,"list")
  64. if not fnames then return false end
  65. local rt = {}
  66. for k,v in pairs(fnames) do
  67. fv = v:match(filter)
  68. if fv then
  69. rt[fv] = function(...)
  70. return rpc.call(hostname,v,...)
  71. end
  72. end
  73. end
  74. return rt
  75. end
  76. function rpc.register(name,fn) -- string function -- -- Registers a function to be exported by the RPC library.
  77. local rpcrunning = false
  78. for k,v in pairs(os.tasks()) do
  79. if os.taskInfo(v).name == "rpc daemon" then
  80. rpcrunning = true
  81. end
  82. end
  83. if not rpcrunning then
  84. os.spawn(function()
  85. while true do
  86. pcall(rpcexec,event.pull("net_msg"))
  87. end
  88. end,"rpc daemon")
  89. end
  90. rpcf[name] = fn
  91. end
  92. return rpc