From: Zachary Vance Date: Sun, 1 Mar 2020 00:08:22 +0000 (-0800) Subject: Add computercraft folder X-Git-Url: https://git.za3k.com/?a=commitdiff_plain;h=f0f1cdccd6839d14c55284984936330293ae2d49;p=za3k.git Add computercraft folder --- diff --git a/computercraft/kv b/computercraft/kv new file mode 100644 index 0000000..2d856b7 --- /dev/null +++ b/computercraft/kv @@ -0,0 +1,235 @@ +local args = { ... } +local PROTOCOL = "kv" +local BSPROTOCOL = "kv-bs" +local NAMESPACE = "" -- global prefix for protocol, ex: "system2." +local KEYPREFIX = "" -- local prefix for put/get, ex: "za3k." +if KEYPREFIX == "" and fs.exists(".kv-prefix") then + f = fs.open(".kv-prefix", "r") + KEYPREFIX = f.readAll() + f.close() +end +local SERVER = NAMESPACE .. "kv-server" +local KVKEY = NAMESPACE .. "kv" +local REGFILE = ".register" +local RUNFILE = ".kv-run" +local shouldRegister = true +local findModem = function() + for _,side in ipairs(rs.getSides()) do + if peripheral.isPresent(side) and peripheral.getType(side) == "modem" then + return side + end + end + print("no modem available") +end + +local printUsage = function() + print("kv update") + print(" Update the 'kv' program to the lastest version") + print("kv get []") + print(" Get a program over wifi") + print("kv put [] ") + print(" Store a program over wifi") + print("kv run [...]") + print(" Immediately run the named program") + print("kv host [FILE]") + print(" Host a database server.") + print("kv host-dump FILE [PREFIX]") + print(" (as host) Prints all kv-pairs") + print("Edit .kv-prefix to set a global prefix") +end +local host = function(dbFile, quineDisable, noImmediate) + db = loadDB(dbFile) + if db == nil then + db = {} + else + print("loaded "..dbFile) + end + if not quineDisable then db[KVKEY] = readFile(KVKEY) end + local modemSide = findModem() + rednet.open(modemSide) + rednet.host(PROTOCOL, SERVER) + print("Hosting kv database") + print("To bootstrap run:") + print(" rednet.open(\"back\")") + print(" _,b,_=rednet.receive(\""..BSPROTOCOL.."\")") + print(" f=fs.open(\""..KVKEY.."\",\"w\")") + print(" f.write(b)") + print(" f.close()") + local dirty = false + while true do + clientID, message, protocol = rednet.receive(PROTOCOL, 60) + if clientID == nil then + -- Broadcast a bootstrap periodically + if not quineDisable then + --print("broadcast bs") + local bs = db[KVKEY] + rednet.broadcast(bs, BSPROTOCOL) + end + if dbFile and dirty then + print("write "..dbFile) + saveDB(dbFile, db) + dirty = false + end + elseif message.action == "get" then + print("get "..message.key) + local value = db[message.key] + response = { + ["action"]="getResponse", + ["key"]=message.key, + ["value"]=value + } + rednet.send(clientID, response, PROTOCOL) + elseif message.action == "put" then + print("put "..message.key) + db[message.key] = message.value + if noImmediate then + dirty = true + else + print("write "..dbFile) + saveDB(dbFile, db) + dirty = false + end + end + end + rednet.unhost(PROTOCOL, SERVER) + rednet.close(modemSide) +end +local get = function(k, prefix) + local modemSide = findModem() + prefix = prefix or KEYPREFIX + local key = NAMESPACE .. prefix .. k + rednet.open(modemSide) + local serverID = rednet.lookup(PROTOCOL, SERVER) + local message = { + ["action"] = "get", + ["key"] = key, + } + rednet.send(serverID, message, PROTOCOL) + local value = nil + while true do + peerID, message, protocol = rednet.receive(PROTOCOL, 10) + if peerID == nil then + break + elseif peerID == serverID and message.action == "getResponse" and message.key == key then + value = message.value + break + end + end + rednet.close() + return value +end +local put = function(k, v, prefix) + prefix = prefix or KEYPREFIX + local key = NAMESPACE .. prefix .. k + local modemSide = findModem() + rednet.open(modemSide) + local serverID = rednet.lookup(PROTOCOL, SERVER) + message = { + ["action"] = "put", + ["key"] = key, + ["value"] = v + } + rednet.send(serverID, message, PROTOCOL) + rednet.close() +end +writeFile = function(path, content) + local f = fs.open(path, "w") + f.write(content) + f.close() +end +readFile = function(path) + local f = fs.open(path, "r") + content = f.readAll() + f.close() + return content +end +loadDB = function(path) + if path == nil or not fs.exists(path) then + return nil + else + return textutils.unserialise(readFile(path)) + end +end +saveDB = function(path, db) + writeFile(path, textutils.serialise(db)) +end +local run = function(content, ...) + writeFile(RUNFILE, content) + shell.run(RUNFILE, ...) +end +local autoregister = function() + if shouldRegister and not fs.exists(REGFILE) then + writeFile(REGFILE, "registered: true") + local id = os.getComputerID() + local label = os.getComputerLabel() + put("registration."..id..".label", label) + put("registration."..id..".namespace", NAMESPACE) + end +end + +if #args < 1 then + printUsage(); return +elseif args[1] == "host" then + if #args == 1 then dbpath = nil + elseif #args == 2 then dbpath = args[2] + else printUsage(); return + end + host(dbpath) +elseif args[1] == "get" then + autoregister() + if #args == 2 then from, to = args[2], args[2] + elseif #args == 3 then from, to = args[2], args[3] + else printUsage(); return + end + content = get(from) + if content == nil then print("content not found"); return end + writeFile(to, content) +elseif args[1] == "put" then + autoregister() + if #args == 2 then from, to = args[2], args[2] + elseif #args == 3 then from, to = args[2], args[3] + else printUsage(); return + end + if not fs.exists(from) then print("file does not exist"); return end + content = readFile(from) + put(to, content) +elseif args[1] == "run" then + autoregister() + if #args >= 2 then + local from = args[2] + table.remove(args, 1) + table.remove(args, 1) + local runArgs = args + else printUsage(); return + end + content = get(from) + if content == nil then print("content not found"); return end + run(content, unpack(runArgs)) +elseif args[1] == "update" then + autoregister() + if #args == 1 then + old = readFile(KVKEY) + content = get(KVKEY, "") + if old == content then + print("Already up to date") + else + print("updating") + writeFile(KVKEY, content) + end + else + printUsage(); return + end +elseif args[1] == "host-dump" then + if #args == 2 then path, prefix = args[2], nil + elseif #args == 3 then path, prefix = args[2], args[3] + else printUsage(); return + end + db = loadDB(path) + if not db then print("DB file not found"); return end + for k,v in pairs(db) do + if not prefix or (k and string.find(k, prefix, 1, true)==1) then + print(k, v) + end + end +else printUsage(); return +end