diff --git a/wgd/package.cfg b/wgd/package.cfg new file mode 100644 index 0000000..840d92f --- /dev/null +++ b/wgd/package.cfg @@ -0,0 +1,4 @@ +{["name"]="workgroup daemon", + ["description"]="Automated component sharing over Minitel.", + ["authors"]="Izaya", + ["dependencies"]={"vcomponent"}} diff --git a/wgd/service/wgd.lua b/wgd/service/wgd.lua new file mode 100644 index 0000000..5d3c040 --- /dev/null +++ b/wgd/service/wgd.lua @@ -0,0 +1,168 @@ +local vcomponent = require "vcomponent" +local serial = require "serialization" +local rpc = require "rpc" +local wgd = {} +wgd.rescanTime = 60*5 +wgd.allowTypes = {filesystem=true} +wgd.hosts = {} +wgd.components = {} +wgd.ignore = {computer.tmpAddress()} +local cImported = {} +local hostStat = {} + +local function loadConfig() + local f = io.open("/boot/cfg/workgroup.cfg") + if not f then return false end + local cfg = serial.unserialize(f:read("*a")) + f:close() + for k,v in pairs(cfg) do + wgd[k] = v + end +end +local function saveConfig() + local wt = { + allowTypes=wgd.allowTypes, + hosts=wgd.hosts, + ignore=wgd.ignore, + rescanTime=wgd.rescanTime, + } + local f = io.open("/boot/cfg/workgroup.cfg","wb") + if not f then return false end + f:write(serial.serialize(wt)) + f:close() +end + +local function getComponents() + return wgd.components +end + +local function exportComponent(a,norescan) + local p = component.proxy(a) + if p and wgd.allowTypes[p.type] and not cImported[a] and not wgd.ignore[a] then + for k,v in pairs(p) do + --[[ + if type(v) == "function" or (type(v) == "table" and v.address == a and v.name == k) then + rpc.register(string.format("wg_%s_%s",a,k),v) + end + ]] + rpc.register(string.format("wg_%s_%s",a,k),v) + wgd.components[a] = p.type + end + if norescan then return true end + for k,v in ipairs(wgd.hosts) do + rpc.call(v, "wg_rescan", os.getenv("HOSTNAME")) + end + end +end +local function unexportComponent(a) + if wgd.components[a] then + wgd.components[a] = nil + for k,v in ipairs(rpcf) do + if k:match("^wg_"..a:gsub("%-","%%-").."_") then + rpcf[k] = nil + end + end + for k,v in ipairs(hosts) do + rpc.call(v, "wg_rescan", os.getenv("HOSTNAME")) + end + end +end + +local function hostUp(name,clist) + syslog("Host "..name.." is up, scanning components.") + for a,t in pairs(clist) do + syslog("Found "..a:sub(1,8).." ("..t..") on host "..name) + local px = rpc.proxy(name, "wg_"..a:gsub("%-","%%-").."_") + if type(px) == "table" then + if t == "filesystem" then + px.fstype = wg_mtfs + local olabel = px.getLabel + function px.getLabel() + local rl = olabel() or a:sub(1,3) + return string.format("/net/%s/%s",name,rl) + end + end + cImported[a] = name + vcomponent.register(a, t, px) + syslog("Attached "..a:sub(1,8).." ("..t..") on host "..name) + service.fsmanager.mount(a) + end + end +end +local function hostDown(name) + for ca,ha in pairs(cImported) do + if ha == name then + vcomponent.unregister(ca) + cImported[ca] = nil + end + end +end + +function wgd.addHost(name) + wgd.removeHost(name) + wgd.hosts[#wgd.hosts+1] = name + saveConfig() + wgd.rescan(name) +end +function wgd.removeHost(name) + for i = #wgd.hosts, 1, -1 do + if wgd.hosts[i] == name then + print(table.remove(wgd.hosts, i)) + end + end + saveConfig() + hostDown(name) +end + +function wgd.rescan(name) + local targets = {name} + targets = #targets > 0 and targets or wgd.hosts + for _,n in ipairs(targets) do + os.spawn(function() + local clist = rpc.call(n, "wg_components") + if clist then + hostUp(n,clist) + else + hostDown(n) + end + end,"wgd worker: "..n) + coroutine.yield() + end +end + +local run +function wgd.start() + if run then return end + run = true + return os.spawn(function() + loadConfig() + rpc.register("wg_components",getComponents) + rpc.register("wg_rescan",wgd.rescan) + local rst = computer.uptime() + 5 + for a,t in component.list() do + exportComponent(a,true) + end + + for k,v in ipairs(wgd.hosts) do + rpc.call(v, "wg_rescan", os.getenv("HOSTNAME")) + end + + while run do + local tE = {coroutine.yield()} + if tE[1] == "component_added" then + exportComponent(tE[2]) + elseif tE[1] == "component_removed" then + unexportComponent(tE[2]) + end + if computer.uptime() > rst then + wgd.rescan() + rst = computer.uptime() + wgd.rescanTime + end + end + end, "workgroupd") +end +function wgd.stop() + run = false +end + +return wgd