import some packages from the main system
This commit is contained in:
parent
49c0b930f9
commit
104e59e6be
197
vcomponent/lib/vcomponent.lua
Normal file
197
vcomponent/lib/vcomponent.lua
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
local proxylist = {}
|
||||||
|
local proxyobjs = {}
|
||||||
|
local typelist = {}
|
||||||
|
local doclist = {}
|
||||||
|
|
||||||
|
local oproxy = component.proxy
|
||||||
|
function component.proxy(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if proxyobjs[address] ~= nil then
|
||||||
|
return proxyobjs[address]
|
||||||
|
end
|
||||||
|
return oproxy(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local olist = component.list
|
||||||
|
function component.list(filter, exact)
|
||||||
|
checkArg(1,filter,"string","nil")
|
||||||
|
local result = {}
|
||||||
|
local data = {}
|
||||||
|
for k,v in olist(filter, exact) do
|
||||||
|
data[#data + 1] = k
|
||||||
|
data[#data + 1] = v
|
||||||
|
result[k] = v
|
||||||
|
end
|
||||||
|
for k,v in pairs(typelist) do
|
||||||
|
if filter == nil or (exact and v == filter) or (not exact and v:find(filter, nil, true)) then
|
||||||
|
data[#data + 1] = k
|
||||||
|
data[#data + 1] = v
|
||||||
|
result[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local place = 1
|
||||||
|
return setmetatable(result,
|
||||||
|
{__call=function()
|
||||||
|
local addr,type = data[place], data[place + 1]
|
||||||
|
place = place + 2
|
||||||
|
return addr, type
|
||||||
|
end}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
local otype = component.type
|
||||||
|
function component.type(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if typelist[address] ~= nil then
|
||||||
|
return typelist[address]
|
||||||
|
end
|
||||||
|
return otype(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local odoc = component.doc
|
||||||
|
function component.doc(address, method)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
checkArg(2,method,"string")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
if proxylist[address][method] == nil then
|
||||||
|
error("no such method",2)
|
||||||
|
end
|
||||||
|
if doclist[address] ~= nil then
|
||||||
|
return doclist[address][method]
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return odoc(address, method)
|
||||||
|
end
|
||||||
|
|
||||||
|
local oslot = component.slot
|
||||||
|
function component.slot(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
return -1 -- vcomponents do not exist in a slot
|
||||||
|
end
|
||||||
|
return oslot(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local omethods = component.methods
|
||||||
|
function component.methods(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
local methods = {}
|
||||||
|
for k,v in pairs(proxylist[address]) do
|
||||||
|
if type(v) == "function" then
|
||||||
|
methods[k] = true -- All vcomponent methods are direct
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return methods
|
||||||
|
end
|
||||||
|
return omethods(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local oinvoke = component.invoke
|
||||||
|
function component.invoke(address, method, ...)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
checkArg(2,method,"string")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
if proxylist[address][method] == nil then
|
||||||
|
error("no such method",2)
|
||||||
|
end
|
||||||
|
return proxylist[address][method](...)
|
||||||
|
end
|
||||||
|
return oinvoke(address, method, ...)
|
||||||
|
end
|
||||||
|
|
||||||
|
local ofields = component.fields
|
||||||
|
function component.fields(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
return {} -- What even is this?
|
||||||
|
end
|
||||||
|
return ofields(address)
|
||||||
|
end
|
||||||
|
|
||||||
|
local componentCallback =
|
||||||
|
{
|
||||||
|
__call = function(self, ...) return proxylist[self.address][self.name](...) end,
|
||||||
|
__tostring = function(self) return (doclist[self.address] ~= nil and doclist[self.address][self.name] ~= nil) and doclist[self.address][self.name] or "function" end
|
||||||
|
}
|
||||||
|
|
||||||
|
local vcomponent = {}
|
||||||
|
|
||||||
|
function vcomponent.register(address, ctype, proxy, doc)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
checkArg(2,ctype,"string")
|
||||||
|
checkArg(3,proxy,"table")
|
||||||
|
if proxylist[address] ~= nil then
|
||||||
|
return nil, "component already at address"
|
||||||
|
elseif component.type(address) ~= nil then
|
||||||
|
return nil, "cannot register over real component"
|
||||||
|
end
|
||||||
|
proxy.address = address
|
||||||
|
proxy.type = ctype
|
||||||
|
local proxyobj = {}
|
||||||
|
for k,v in pairs(proxy) do
|
||||||
|
if type(v) == "function" then
|
||||||
|
proxyobj[k] = setmetatable({name=k,address=address},componentCallback)
|
||||||
|
else
|
||||||
|
proxyobj[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
proxylist[address] = proxy
|
||||||
|
proxyobjs[address] = proxyobj
|
||||||
|
typelist[address] = ctype
|
||||||
|
doclist[address] = doc
|
||||||
|
computer.pushSignal("component_added",address,ctype)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function vcomponent.unregister(address)
|
||||||
|
checkArg(1,address,"string")
|
||||||
|
if proxylist[address] == nil then
|
||||||
|
if component.type(address) ~= nil then
|
||||||
|
return nil, "cannot unregister real component"
|
||||||
|
else
|
||||||
|
return nil, "no component at address"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local thetype = typelist[address]
|
||||||
|
proxylist[address] = nil
|
||||||
|
proxyobjs[address] = nil
|
||||||
|
typelist[address] = nil
|
||||||
|
doclist[address] = nil
|
||||||
|
computer.pushSignal("component_removed",address,thetype)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function vcomponent.list()
|
||||||
|
local list = {}
|
||||||
|
for k,v in pairs(proxylist) do
|
||||||
|
list[#list + 1] = {k,typelist[k],v}
|
||||||
|
end
|
||||||
|
return list
|
||||||
|
end
|
||||||
|
|
||||||
|
function vcomponent.resolve(address, componentType)
|
||||||
|
checkArg(1, address, "string")
|
||||||
|
checkArg(2, componentType, "string", "nil")
|
||||||
|
for k,v in pairs(typelist) do
|
||||||
|
if componentType == nil or v == componentType then
|
||||||
|
if k:sub(1, #address) == address then
|
||||||
|
return k
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil, "no such component"
|
||||||
|
end
|
||||||
|
|
||||||
|
local r = math.random
|
||||||
|
function vcomponent.uuid()
|
||||||
|
return string.format("%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||||
|
r(0,255),r(0,255),r(0,255),r(0,255),
|
||||||
|
r(0,255),r(0,255),
|
||||||
|
r(64,79),r(0,255),
|
||||||
|
r(128,191),r(0,255),
|
||||||
|
r(0,255),r(0,255),r(0,255),r(0,255),r(0,255),r(0,255))
|
||||||
|
end
|
||||||
|
|
||||||
|
return vcomponent
|
3
vcomponent/package.cfg
Normal file
3
vcomponent/package.cfg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{["name"]="vComponent",
|
||||||
|
["description"]="Library for creating virtual component devices.",
|
||||||
|
["authors"]="gamax92"}
|
63
vtunnel/lib/interminitel.lua
Normal file
63
vtunnel/lib/interminitel.lua
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
local imt = {}
|
||||||
|
|
||||||
|
imt.ttypes = {}
|
||||||
|
imt.ttypes.string=1
|
||||||
|
imt.ttypes.number=2
|
||||||
|
|
||||||
|
imt.ftypes = {tostring,tonumber}
|
||||||
|
|
||||||
|
function imt.to16bn(n)
|
||||||
|
return string.char(math.floor(n/256))..string.char(math.floor(n%256))
|
||||||
|
end
|
||||||
|
function imt.from16bn(s)
|
||||||
|
return (string.byte(s,1,1)*256)+string.byte(s,2,2)
|
||||||
|
end
|
||||||
|
|
||||||
|
function imt.encodePacket(...)
|
||||||
|
local tArgs = {...}
|
||||||
|
local packet = string.char(#tArgs%256)
|
||||||
|
for _,segment in ipairs(tArgs) do
|
||||||
|
local segtype = type(segment)
|
||||||
|
segment = tostring(segment)
|
||||||
|
packet = packet .. imt.to16bn(segment:len()) .. string.char(imt.ttypes[segtype]) .. tostring(segment)
|
||||||
|
end
|
||||||
|
packet = imt.to16bn(packet:len()) .. packet
|
||||||
|
return packet
|
||||||
|
end
|
||||||
|
|
||||||
|
function imt.decodePacket(s)
|
||||||
|
local function getfirst(n)
|
||||||
|
local ns = s:sub(1,n)
|
||||||
|
s=s:sub(n+1)
|
||||||
|
return ns
|
||||||
|
end
|
||||||
|
if s:len() < 2 then return false end
|
||||||
|
local plen = imt.from16bn(getfirst(2))
|
||||||
|
local segments = {}
|
||||||
|
if s:len() < plen then return false end
|
||||||
|
local nsegments = string.byte(getfirst(1))
|
||||||
|
--print(tostring(plen).." bytes, "..tostring(nsegments).." segments")
|
||||||
|
for i = 1, nsegments do
|
||||||
|
local seglen = imt.from16bn(getfirst(2))
|
||||||
|
local segtype = imt.ftypes[string.byte(getfirst(1))]
|
||||||
|
local segment = segtype(getfirst(seglen))
|
||||||
|
--print(seglen,segtype,segment,type(segment))
|
||||||
|
segments[#segments+1] = segment
|
||||||
|
end
|
||||||
|
return table.unpack(segments)
|
||||||
|
end
|
||||||
|
function imt.getRemainder(s)
|
||||||
|
local function getfirst(n)
|
||||||
|
local ns = s:sub(1,n)
|
||||||
|
s=s:sub(n+1)
|
||||||
|
return ns
|
||||||
|
end
|
||||||
|
local plen = imt.from16bn(getfirst(2))
|
||||||
|
if s:len() > plen then
|
||||||
|
getfirst(plen)
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return imt
|
4
vtunnel/package.cfg
Normal file
4
vtunnel/package.cfg
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{["name"]="vTunnel",
|
||||||
|
["description"]="Virtual tunnel card over TCP",
|
||||||
|
["authors"]="Izaya",
|
||||||
|
["dependencies"]={"vcomponent"}}
|
162
vtunnel/service/vtunnel.lua
Normal file
162
vtunnel/service/vtunnel.lua
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
local vcomponent = require "vcomponent"
|
||||||
|
local serial = require "serialization"
|
||||||
|
local component = require "component"
|
||||||
|
local computer = require "computer"
|
||||||
|
local event = require "event"
|
||||||
|
local imt = require "interminitel"
|
||||||
|
|
||||||
|
local cfg = {}
|
||||||
|
cfg.peers = {}
|
||||||
|
cfg.rtimer = 5
|
||||||
|
cfg.katimer = 30
|
||||||
|
local listeners = {}
|
||||||
|
local proxies = {}
|
||||||
|
|
||||||
|
local function loadcfg()
|
||||||
|
local f = io.open("/boot/cfg/vtunnel.cfg","rb")
|
||||||
|
if not f then return false end
|
||||||
|
for k,v in pairs(serial.unserialize(f:read("*a")) or {}) do
|
||||||
|
cfg[k] = v
|
||||||
|
end
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
local function savecfg()
|
||||||
|
local f = io.open("/boot/cfg/vtunnel.cfg","wb")
|
||||||
|
if not f then
|
||||||
|
print("Warning: unable to save configuration.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
f:write(serial.serialize(cfg))
|
||||||
|
f:close()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function createTunnel(host,port,addr,raddr)
|
||||||
|
local proxy = {address=addr,buffer=""}
|
||||||
|
function proxy.connect()
|
||||||
|
if proxy.socket then
|
||||||
|
proxy.socket.close()
|
||||||
|
end
|
||||||
|
proxy.socket = component.invoke(component.list("internet")(),"connect",host,port)
|
||||||
|
local st = computer.uptime()
|
||||||
|
repeat
|
||||||
|
coroutine.yield()
|
||||||
|
until proxy.socket.finishConnect() or computer.uptime() > st+5
|
||||||
|
end
|
||||||
|
function proxy.send(...)
|
||||||
|
rt = 0
|
||||||
|
while not proxy.socket.write(imt.encodePacket(...)) and rt < 10 do
|
||||||
|
proxy.connect()
|
||||||
|
rt = rt + 1
|
||||||
|
end
|
||||||
|
proxy.last = computer.uptime()
|
||||||
|
end
|
||||||
|
function proxy.read()
|
||||||
|
local rb, r
|
||||||
|
local rt = 0
|
||||||
|
while true do
|
||||||
|
rb,r = proxy.socket.read(4096)
|
||||||
|
if rb or rt > 10 then break end
|
||||||
|
if type(rb) == "nil" then
|
||||||
|
proxy.connect()
|
||||||
|
end
|
||||||
|
rt = rt + 1
|
||||||
|
end
|
||||||
|
proxy.buffer = proxy.buffer .. rb
|
||||||
|
while imt.decodePacket(proxy.buffer) do
|
||||||
|
computer.pushSignal("modem_message",addr,raddr,0,0,imt.decodePacket(proxy.buffer))
|
||||||
|
proxy.buffer = imt.getRemainder(proxy.buffer) or ""
|
||||||
|
end
|
||||||
|
if computer.uptime() > proxy.last + cfg.katimer then
|
||||||
|
proxy.socket.write("\0\1\0")
|
||||||
|
proxy.last = computer.uptime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function proxy.getWakeMessage()
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
proxy.setWakeMessage = proxy.getWakeMessage
|
||||||
|
function proxy.maxPacketSize()
|
||||||
|
return 8192
|
||||||
|
end
|
||||||
|
function proxy.getChannel()
|
||||||
|
return host..":"..tostring(port)
|
||||||
|
end
|
||||||
|
proxy.connect()
|
||||||
|
proxy.last = computer.uptime()
|
||||||
|
return proxy
|
||||||
|
end
|
||||||
|
|
||||||
|
vt = {}
|
||||||
|
function start()
|
||||||
|
loadcfg()
|
||||||
|
for k,v in pairs(cfg.peers) do
|
||||||
|
print(string.format("Connecting to %s:%d",v.host,v.port))
|
||||||
|
v.addr = v.addr or vcomponent.uuid()
|
||||||
|
v.raddr = v.raddr or vcomponent.uuid()
|
||||||
|
local px = createTunnel(v.host, v.port, v.addr, v.raddr)
|
||||||
|
vcomponent.register(v.addr, "tunnel", px)
|
||||||
|
proxies[v.addr] = px
|
||||||
|
end
|
||||||
|
for k,v in pairs(os.tasks()) do
|
||||||
|
if os.taskInfo(v).name:match("minitel") then
|
||||||
|
os.kill(v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function vt.stop()
|
||||||
|
for k,v in pairs(proxies) do
|
||||||
|
vcomponent.unregister(k)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.listpeers()
|
||||||
|
for k,v in pairs(cfg.peers) do
|
||||||
|
print(string.format("#%d (%s:%d)\n Local address: %s\n Remote address: %s",k,v.host,v.port,v.addr,v.raddr))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
function vt.addpeer(host,port)
|
||||||
|
port = tonumber(port) or 4096
|
||||||
|
local t = {}
|
||||||
|
t.host = host
|
||||||
|
t.port = port
|
||||||
|
t.addr = vcomponent.uuid()
|
||||||
|
t.raddr = vcomponent.uuid()
|
||||||
|
cfg.peers[#cfg.peers+1] = t
|
||||||
|
print(string.format("Added peer #%d (%s:%d) to the configuration.\nRestart to apply changes.",#cfg.peers,host,port))
|
||||||
|
savecfg()
|
||||||
|
end
|
||||||
|
function vt.delpeer(n)
|
||||||
|
n=tonumber(n)
|
||||||
|
if not n then
|
||||||
|
print("delpeer requires a number, representing the peer number, as an argument.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local dp = table.remove(cfg.peers, n)
|
||||||
|
savecfg()
|
||||||
|
print(string.format("Removed peer %s:%d",dp.host, dp.port))
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.settimer(time)
|
||||||
|
time = tonumber(time)
|
||||||
|
if not time then
|
||||||
|
print("Timer must be a number.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
cfg.rtime = time
|
||||||
|
savecfg()
|
||||||
|
end
|
||||||
|
|
||||||
|
vt.start = start
|
||||||
|
_G.libs.vtunnel = vt
|
||||||
|
|
||||||
|
start()
|
||||||
|
local last = computer.uptime()
|
||||||
|
while true do
|
||||||
|
local tE = {coroutine.yield()}
|
||||||
|
if computer.uptime() > last + cfg.rtimer then
|
||||||
|
for k,v in pairs(proxies) do
|
||||||
|
v.read()
|
||||||
|
end
|
||||||
|
last = computer.uptime()
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue
Block a user