diff --git a/OpenOS/client/usr/bin/search4.lua b/OpenOS/client/usr/bin/search4.lua new file mode 100644 index 0000000..12469d4 --- /dev/null +++ b/OpenOS/client/usr/bin/search4.lua @@ -0,0 +1,184 @@ +local event = require "event" +local sides = require "sides" +local inv = require "inv" + +local function popup(str,title) + if title then + title=string.format("[%s]",title or "") + else + title = "" + end + local width, height, content = 0, 0, {} + for line in str:gmatch("[^\n]*") do + height = height + 1 + width = math.max(width,line:len()) + content[#content+1] = line + end + if width < 1 or height < 1 then return false end + local startx,starty = (40-(width//2))-2, (12-(height//2))-2 + io.write(string.format("\27[%d;%dH╒═%s%s╕",starty,startx,title,("═"):rep((width+1)-title:len()))) + for k,v in pairs(content) do + io.write(string.format("\27[%d;%dH│ %s%s │",starty+k,startx,v,(" "):rep(width-v:len()))) + end + io.write(string.format("\27[%d;%dH┕%s┙",starty+1+#content,startx,("━"):rep(width+2))) +end + +function inv.search(searchterm) + local rt + repeat + rt = inv.matchAll({label=searchterm or ""},true) + if not rt then + popup("Server appears to be down.\nPress any key to try again.","Error") + event.pull("key_down") + end + until rt + return rt, #rt, #rt +end + +local searchterm = "" +--local output = inv.getAliases()[os.getenv("HOSTNAME")] +local output +local ci,si = 1,1 +local run = true +local timers = {} + +repeat + local w,aliases = pcall(inv.getAliases) + if not w then + popup("Server appears to be down.\nPress any key to try again.","Error") + event.pull("key_down") + else + output=aliases[os.getenv("HOSTNAME")] + end +until w + +local phases = { +[0] = "⣿⣿", +"⢾⣿", +" ⣿", +" ⣹", +"⣏⣹", +"⣏ ", +"⣿ ", +"⣿⡷" +} + +local function search() + io.write("\n\27[2KSearch: ") + searchterm = io.read() +end +local function setOutput() + io.write("\n\27[2KOutput side:") + local ins = io.read() + output = tonumber(ins) or sides[ins] +end + +local function extract(item) + io.write(string.format("\nExtracting %s; Count [64] or x to exit? ",item.label)) + local count = io.read() + if count == "x" then return false end + count=tonumber(count) or 64 + item.size = nil + print(inv.extract(item,count,output[1],output[2])) +end + +local function info(item) + local s = string.format("\n%s (%s)\nCount: %d\n",item.label,item.name,item.size) + if item.aspects then + s=s.."Aspects: " + for k,v in pairs(item.aspects) do + s=string.format("%s\n - %d x %s",s,v,k) + end + end + s=s.."\n\nPress any key." + popup(s,item.label or item.name) + event.pull("key_down") +end + +local function help() + popup("\n[Tab] Search\n[Enter] Extract Items\n[i] Item Information\n[r] Refresh\n[o] Set output\n\nPress any key.","Key bindings") + event.pull("key_down") +end + +local function draw(sr, ci, used, size) + io.write("\27[2J\27[H") + for i = si, si+22 do + if sr[i] then + item = sr[i] + pt = "\27[0m" + if ci == i then + pt = "\27[7m" + end + print(string.format("%s%-59s %20s", pt, item.label, string.format("(%d - %dx%d + %d)", item.size, math.floor(item.size/item.maxSize),item.maxSize,item.size%item.maxSize))) + end + end + io.write("\27[0m\27[25;62HPress [H] for help.") + local mcol = 3 + local countdown = 8-(math.floor((os.time()-43200)/86400)%8) + if countdown == 8 then + mcol = 1 + elseif countdown >= 4 then + mcol = 2 + end +-- io.write(string.format("\27[0m\27[1;77H\27[3%im%i %s\27[0m", mcol, countdown, phases[math.floor((os.time()-43200)/86400)%8])) + io.write(string.format("\27[0m\27[24;1H\27[3%im%1i %2s\27[0m %-70s",mcol, countdown, phases[math.floor((os.time()-43200)/86400)%8], searchterm)) +-- io.write(string.format("\27[24;1H(%d/%d) %s",used,size-1,searchterm)) +end + +--[[ +timers[#timers+1] = event.timer(120,function() + io.write(string.format("\27[1;77H%i %s\27[24;1H", 8-(math.floor((os.time()-43200)/86400)%8), phases[math.floor((os.time()-43200)/86400)%8])) +end,math.huge) +]]-- + +while run do + local sr, used, size = inv.search(searchterm) + ci = 1 + while true do + if ci > #sr then + ci = #sr + elseif ci < 1 then + ci = 1 + end + if ci > math.min(si + 20,#sr) then + si = si + 5 + elseif ci < si + 2 then + si = si - 5 + end + if si < 1 then + si = 1 + elseif si > #sr then + si = #sr - 23 + end + draw(sr,ci,used,size) + local _,_,ch,co = event.pull(60,"key_down") + ch=string.char(ch or 0) + if co == 208 then -- down + ci = ci + 1 + elseif co == 200 then -- up + ci = ci - 1 + elseif co == 28 then -- enter + extract(sr[ci]) + break + elseif co == 15 then -- tab + search() + break + elseif ch == "i" then + info(sr[ci]) + elseif ch == "h" then + help() + elseif ch == "r" then + popup("Refreshing index...") +-- inv.inputItems() + break + elseif ch == "o" then + setOutput() + elseif ch == "q" then + run = false + break + end + end +end +for k,v in pairs(timers) do + event.cancel(v) +end \ No newline at end of file diff --git a/OpenOS/client/usr/lib/inv.lua b/OpenOS/client/usr/lib/inv.lua new file mode 100644 index 0000000..b1b32f4 --- /dev/null +++ b/OpenOS/client/usr/lib/inv.lua @@ -0,0 +1,43 @@ +local serial = require "serialization" +local minitel = require "minitel" +local buffer = require "buffer" +local lz16 = require "liblz16" +local rpc = require "rpc" + +local server +local port = 15 + +local f = io.open("/etc/invsrv","rb") +if not f then error("no server configured") end +server=f:read() +port=tonumber(f:read()) or port +f:close() + +local inv = setmetatable({}, {__index=rpc.proxy(server, "inv_")}) + +function inv.matchAll(criteria, fuzzy) + local socket = minitel.open(server,port) + if not socket then return false end + local cstr = "compress=true\tfuzzy="..tostring(fuzzy) + for k,v in pairs(criteria) do + cstr=string.format("%s\t%s=%s", cstr, k, v) + end + socket:write(cstr.."\n") + socket.mode = {r=true} + local function cread() + if socket.state ~= "open" then + return nil + end + os.sleep(0.05) + return socket:read("*a") + end + local lsock = lz16.buffer(buffer.new("rb",{read = cread,close=function() end})) + local rt = {} + for line in lsock:lines() do + rt[#rt+1] = serial.unserialize(line) + end + lsock:close() + return rt +end + +return inv \ No newline at end of file diff --git a/OpenOS/server/etc/rc.d/searchsrv.lua b/OpenOS/server/etc/rc.d/searchsrv.lua new file mode 100644 index 0000000..b7247db --- /dev/null +++ b/OpenOS/server/etc/rc.d/searchsrv.lua @@ -0,0 +1,89 @@ +local serial = require "serialization" +local minitel = require "minitel" +local thread = require "thread" +local syslog = require "syslog" +local lz16 = require "liblz16" +local inv = require "inv" +local rpc = require "rpc" + +local listeners = {} +local coro = {} +local config = {port=15,logfile="/tmp/dss.log"} + +function reload() + local f = io.open("/etc/dss/dss.cfg","rb") + if not f then + os.execute("mkdir /etc/dss") + f=io.open("/etc/dss/dss.cfg", "wb") + f:write(serial.serialize(config)) + f:close() + end + config = serial.unserialize(f:read("*a")) + f:close() + local alias = inv.getAliases() + for fn,_ in pairs(inv) do + for hn,_ in pairs(alias) do + rpc.allow(fn,hn) + end + end +end + +local function parseSearch(str) + local criteria = {} + for arg in str:gmatch("[^\t]+") do + local k,v = arg:match("(.+)=(.*)") + criteria[k] = tonumber(v) or v or "" + end + local fuzzy, compress = criteria.fuzzy or false, criteria.compress or false + criteria.fuzzy, criteria.compress = nil, nil + return criteria, fuzzy, compress +end + +local function formatEntry(stack) + local ft = {} + for k,v in pairs(stack) do + if type(v) == "string" or type(v) == "number" then + ft[k] = v + end + end + return serial.serialize(ft) .. "\n" +end + +local function handleSocket(socket) + coro[#coro+1] = thread.create(function() + local query + repeat + os.sleep(0.5) + query = socket:read() + until query + syslog(string.format("[%s:%i] %s",socket.addr,socket.port,query),syslog.info,"mtdss") + local criteria, fuzzy, compress = parseSearch(query) + local lsock + if compress then + socket.mode={w=true} + lsock = lz16.buffer(socket) + else + lsock = socket + end + for slot, stack in pairs(inv.matchAll(criteria,fuzzy)) do + lsock:write(formatEntry(stack)) + end + lsock:close() + socket:close() + end) + syslog(string.format("Connection from %s:%i",socket.addr,socket.port),syslog.info, "mtdss") +end + +function start() + for k,v in pairs(inv) do + rpc.register("inv_"..k, v) + end + reload() + listeners[#listeners+1] = minitel.flisten(config.port,handleSocket) +end +function stop() + thread.waitForAll(coro) + for k,v in pairs(listeners) do + event.ignore("net_msg",v) + end +end \ No newline at end of file diff --git a/OpenOS/server/usr/bin/addalias.lua b/OpenOS/server/usr/bin/addalias.lua new file mode 100644 index 0000000..9118e11 --- /dev/null +++ b/OpenOS/server/usr/bin/addalias.lua @@ -0,0 +1,39 @@ +local component = require "component" +local sides = require "sides" + +local tA = {...} + +if #tA < 3 then + io.stderr:write("usage: addalias
") + return +end + +local alines = {} + +local f = io.open("/etc/talias","rb") +if f then + for line in f:lines() do + local lt = {} + for word in line:gmatch("%S+") do + lt[#lt+1] = word + end + alines[string.format("%s\t%s",table.remove(lt,1), table.remove(lt,1))] = lt + end + f:close() +end + +local addr = component.get(tA[1]) +local side = tonumber(tA[2]) or sides[tA[2]] +local aname = string.format("%s\t%s",addr,side) +alines[aname] = alines[aname] or {} +alines[aname][#alines[aname]+1] = tA[3] + +local f = io.open("/etc/talias","wb") +for k,v in pairs(alines) do + f:write(k) + for _,w in ipairs(v) do + f:write("\t"..w) + end + f:write("\n") +end +f:close() diff --git a/OpenOS/server/usr/lib/inv.lua b/OpenOS/server/usr/lib/inv.lua new file mode 100644 index 0000000..22ed149 --- /dev/null +++ b/OpenOS/server/usr/lib/inv.lua @@ -0,0 +1,113 @@ +local inv = {} +local transposers = {} + +local component = require "component" +local serialization = require "serialization" +local syslog = require "syslog" + +function inv.scanTransposers() + transposers = {} + for k,v in pairs(component.list("transposer")) do + for i = 0, 5 do + local iname = component.invoke(k, "getInventoryName", i) + if iname == "storagedrawers:controller" or iname == "storagedrawers:controllerslave" then + transposers[#transposers+1] = component.proxy(k) + transposers[#transposers].drawerside = i + transposers[k] = transposers[#transposers] + break + end + end + end +end + +inv.scanTransposers() + +function inv.match(specifiers) + local counter = 1 + for item in transposers[1].getAllStacks(transposers[1].drawerside) do + local match = true + for k,v in pairs(specifiers) do + if item[k] ~= v then + match = false + break + end + end + if match then + return counter, item + end + counter = counter + 1 + end +end +function inv.matchAll(specifiers,fuzzy) + local counter = 1 + local rt = {} + for item in transposers[1].getAllStacks(transposers[1].drawerside) do + local match = true + if item == nil or item.name == "minecraft:air" then + match = false + end + for k,v in pairs(specifiers) do + if fuzzy and type(item[k]) == "string" and type(v) == "string" then + if not item[k]:lower():find(v:lower()) then + match=false + break + end + else + if item[k] ~= v then + match = false + break + end + end + end + if match then + rt[counter] = item + end + counter = counter + 1 + end + return rt +end + +function inv.extract(specifiers,count,addr,side) + if not transposers[addr] then return false end + local transfered = 0 + repeat + local slot, stack = inv.match(specifiers) + if not slot or not stack then + break + end + local lt = transposers[addr].transferItem(transposers[addr].drawerside, side, count-transfered, slot) + transfered = transfered + lt + until transfered >= count + local sf = "" + for k,v in pairs(specifiers) do + sf=string.format("%s%s=%s ",sf,tostring(k),tostring(v)) + end + syslog(string.format("%s:%i extracted %i items matching %s",addr,side,transfered,sf),nil,"mtdss") + return transfered>0, transfered +end + +function inv.getTransposers() + local rt = {} + for k,v in pairs(component.list("transposer")) do + rt[#rt+1] = k + end + return rt +end + +function inv.getAliases() + local rt = {} + local f = io.open("/etc/talias","rb") + for line in f:lines() do + local lt = {} + for word in line:gmatch("%S+") do + lt[#lt+1] = word + end + local addr, side = table.remove(lt,1), tonumber(table.remove(lt,1)) + for k,v in pairs(lt) do + rt[v] = {addr, side} + end + end + return rt +end + +return inv \ No newline at end of file