ldd-CC/neovariable2.lua

271 lines
6.3 KiB
Lua
Raw Normal View History

--[[
NewVariable 2 (WIP) by LDDestroier
Get with:
wget https://raw.githubusercontent.com/LDDestroier/CC/master/neovariable2.lua
2019-02-20 07:08:14 +00:00
To Do:
2019-02-20 07:08:14 +00:00
+ asymmetrical encryption (actually forget that, functions wouldn't work out)
+ work on stability
+ steal underpants
--]]
2019-02-19 22:43:16 +00:00
local tArg = {...}
local mode = tArg[1] -- "server" or "demo", otherwise works as API
2019-02-19 22:43:16 +00:00
if not peripheral.find("modem") then
ccemux.attach("top", "wireless_modem")
end
local makeMT = function(indexFunc, newindexFunc)
local output = {}
local _output = output
output = {}
local mt = {
__index = function(t, k)
if indexFunc then
return indexFunc(_output, k)
else
return _output[k]
end
end,
__newindex = function(t, k, v)
if newindexFunc then
_output[k] = newindexFunc(_output, k, v)
else
_output[k] = v
end
end
}
setmetatable(output, mt)
return output
end
-- information about the API
2019-02-19 22:43:16 +00:00
local nv = {
dir = { -- all DIRECTORIES will end with "/"
main = "neovariable", -- main directory where all neovariable stuff are
privateID = "private", -- private computer ID, protect with your life
publicID = "public", -- public computer ID, is shared all the time
config = "config", -- config options
api = "api/" -- where APIs are stored
2019-02-19 22:43:16 +00:00
},
envKey = 1, -- determines which environment to use
environment = {}, -- stores multiple environments
privateID = nil, -- every computer should have a secret, individual "ID"
publicID = nil, -- every computer should also have a public key
channel = 1002, -- modem channel
}
-- functions that are put in the api for use
local API = {}
2019-02-19 22:43:16 +00:00
for k,v in pairs(nv.dir) do
if k ~= "main" then
nv.dir[k] = fs.combine(nv.dir.main, v)
end
2019-02-19 22:43:16 +00:00
if (not fs.exists(v)) and v:sub(-1, -1) == "/" then
fs.makeDir(nv.dir[k])
2019-02-19 22:43:16 +00:00
end
end
local getID = function(path)
if fs.exists(path) then
local file = fs.open(path, "r")
local contents = file.readAll()
file.close()
return contents
else
return false
end
end
2019-02-20 07:08:14 +00:00
local makeNewID = function(path, _id)
2019-02-19 22:43:16 +00:00
local file = fs.open(path, "w")
2019-02-20 07:08:14 +00:00
if _id then
file.write(_id)
else
local id = ""
for i = 1, 256 do
id = id .. string.char(math.random(11, 127))
end
file.write(id)
2019-02-19 22:43:16 +00:00
end
file.close()
return id
end
nv.privateID, nv.publicID = getID(nv.dir.privateID), getID(nv.dir.publicID)
if not nv.privateID then
nv.privateID = makeNewID(nv.dir.privateID)
end
if not nv.publicID then
nv.publicID = makeNewID(nv.dir.publicID)
end
local getModem = function()
local m = peripheral.find("modem")
if m then
if not m.isOpen(nv.channel) then
m.open(nv.channel)
end
end
return m
end
local modem = getModem()
local send = function(envKey, cID, command, recipient, tbl, key, value)
modem.transmit(nv.channel, nv.channel, {
envKey = envKey,
command = command,
t = tbl,
k = key,
v = value,
publicID = nv.publicID,
cID = cID or math.random(1, 2^30),
recipient = recipient
})
end
-- easy way to view values
local debugErrorScreen = function(value)
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1,1)
print(textutils.serialize(value))
term.setCursorPos(1, 18)
error()
end
local rawReceive = function(valueType, timeout)
local evt, tID
if timeout then
tID = os.startTimer(timeout)
end
repeat
evt = {os.pullEvent()}
until (
evt[1] == "modem_message" and type(evt[5]) == valueType
) or (
evt[1] == "timer" and evt[2] == tID
)
return evt[5]
end
local receive = function(envKey, cID, timeout)
local output
repeat
output = rawReceive("table", timeout)
until (output or {}).cID == cID or output == nil
return output
end
-- runs a neovariable server, and sets envList to the list of environments used
API.runServer = function( envList, verbose )
2019-02-19 22:43:16 +00:00
local evt, msg
while true do
repeat
repeat
evt = {os.pullEvent("modem_message")}
until type(evt[5]) == "table"
until evt[5].cID ~= nil
msg = evt[5]
if msg.command == "find" then
if verbose then print("got 'find' request") end
send(nil, msg.cID, "find_response", msg.publicID, nv.publicID)
elseif msg.command == "set" or msg.command == "get" then
2019-02-20 07:08:14 +00:00
if ( -- check the types of all the input
2019-02-19 22:43:16 +00:00
msg.envKey ~= nil and
type(msg.publicID) == "string" and
msg.k ~= nil and
msg.recipient == nv.publicID
) then
nv.environment[msg.publicID] = nv.environment[msg.publicID] or {}
nv.environment[msg.publicID][msg.envKey] = nv.environment[msg.publicID][msg.envKey] or {}
2019-02-19 22:43:16 +00:00
if msg.command == "set" then
if msg.v ~= nil then
2019-02-20 07:08:14 +00:00
if verbose then print("[" .. tostring(msg.envKey) .. "] " .. tostring(msg.k) .. " = " .. tostring(msg.v)) end
2019-02-19 22:43:16 +00:00
nv.environment[msg.publicID][msg.envKey][msg.k] = msg.v
end
elseif msg.command == "get" then
2019-02-20 07:08:14 +00:00
if verbose then print("[" .. tostring(msg.envKey) .. "] " .. tostring(msg.k)) end
2019-02-19 22:43:16 +00:00
send(msg.envKey, msg.cID, "get_response", msg.publicID, nv.environment[msg.publicID][msg.envKey][msg.k])
end
end
end
2019-02-20 07:08:14 +00:00
envList = nv.environment
2019-02-19 22:43:16 +00:00
end
end
API.findServer = function(getList, timeout)
2019-02-20 07:08:14 +00:00
timeout = tonumber(timeout) or 1
2019-02-19 22:43:16 +00:00
local cID = math.random(1, 2^30)
send(nil, cID, "find")
if getList then
local servers = {}
parallel.waitForAny(
function()
while true do
servers[#servers+1] = receive(nil, cID).publicID
end
end,
function()
sleep(timeout)
end
)
return servers
else
return (receive(nil, cID, timeout) or {}).publicID
end
end
API.newEnvironment = function(server, envKey)
2019-02-20 07:08:14 +00:00
assert(type(server) == "string", "server ID must be a string")
assert(envKey ~= nil, "envKey must not be nil")
return makeMT(
function(t, k)
local cID = math.random(1, 2^30)
send(envKey, cID, "get", server, t, k)
local response = receive(envKey, cID, 3)
if response then
return response.t
else
return nil, "no response"
2019-02-19 22:43:16 +00:00
end
end,
function(t, k, v)
local cID = math.random(1, 2^30)
send(envKey, cID, "set", server, t, k, v)
2019-02-19 22:43:16 +00:00
end
)
end
if mode == "server" then
API.runServer(nil, true)
elseif mode == "demo" then
local server = API.findServer(false, 1)
if server then
print("found server")
local noo = API.newEnvironment(server, 1)
local yoo = API.newEnvironment(server, 2)
print("made envs")
noo.hi = "what"
yoo.he = "bumbo"
print("set")
local var = noo.hi
local ver = yoo.he
print("get")
print("noo.hi = " .. tostring(noo.hi))
print("yoo.he = " .. tostring(yoo.he))
else
print("no neovariable server")
end
2019-02-19 22:43:16 +00:00
else
return API
2019-02-19 22:43:16 +00:00
end