2019-11-26 21:34:40 +11:00
local serial = require " serialization "
local minitel = require " minitel "
local event = require " event "
local rpc = { }
_G.rpcf = { }
rpc.port = 111
local function rpcexec ( _ , from , port , data )
if port == rpc.port then
local rpcrq = serial.unserialize ( data )
local rpcn , rpcid = table.remove ( rpcrq , 1 ) , table.remove ( rpcrq , 1 )
if rpcf [ rpcn ] then
local rt = { pcall ( rpcf [ rpcn ] , table.unpack ( rpcrq ) ) }
if rt [ 1 ] == true then
table.remove ( rt , 1 )
end
minitel.send ( from , port , serial.serialize ( { rpcid , table.unpack ( rt ) } ) )
else
end
end
end
function rpcf . list ( )
local rt = { }
for k , v in pairs ( rpcf ) do
rt [ # rt + 1 ] = k
end
return rt
end
2020-05-12 10:57:13 +10:00
function rpc . call ( hostname , fn , ... ) -- string string -- boolean -- Calls exported function *fn* on host *hostname*, with parameters *...*, returning whatever the function returns, or false.
2019-11-26 21:34:40 +11:00
if hostname == " localhost " then
return rpcf [ fn ] ( ... )
end
local rv = minitel.genPacketID ( )
minitel.rsend ( hostname , rpc.port , serial.serialize ( { fn , rv , ... } ) , true )
local st = computer.uptime ( )
local rt = { }
repeat
local _ , from , port , data = event.pull ( 30 , " net_msg " , hostname , rpc.port )
2020-03-26 17:33:18 +11:00
rt = serial.unserialize ( tostring ( data ) ) or { }
until ( type ( rt ) == " table " and rt [ 1 ] == rv ) or computer.uptime ( ) > st + 30
2019-11-26 21:34:40 +11:00
if table.remove ( rt , 1 ) == rv then
return table.unpack ( rt )
end
return false
end
2020-05-12 10:57:13 +10:00
function rpc . proxy ( hostname , filter ) -- string string -- table -- Returns a component.proxy()-like table from the functions on *hostname* with names matching *filter*.
2019-11-26 21:34:40 +11:00
filter = ( filter or " " ) .. " (.+) "
local fnames = rpc.call ( hostname , " list " )
if not fnames then return false end
local rt = { }
for k , v in pairs ( fnames ) do
fv = v : match ( filter )
if fv then
rt [ fv ] = function ( ... )
return rpc.call ( hostname , v , ... )
end
end
end
return rt
end
2020-05-12 10:57:13 +10:00
function rpc . register ( name , fn ) -- string function -- -- Registers a function to be exported by the RPC library.
2019-11-26 21:34:40 +11:00
local rpcrunning = false
for k , v in pairs ( os.tasks ( ) ) do
if os.taskInfo ( v ) . name == " rpc daemon " then
rpcrunning = true
end
end
if not rpcrunning then
os.spawn ( function ( )
while true do
rpcexec ( event.pull ( " net_msg " ) )
end
end , " rpc daemon " )
end
rpcf [ name ] = fn
end
return rpc