Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package.path = "/?;/?.lua;" .. package.path
- local chest = settings.get "mail.chest" or error "please set mail.chest to the network name of the (non-ender) chest to use"
- local ender_chest = peripheral.find "ender_chest" or error "ender chest connected through adapter + relay required"
- local ender_chest_inv = peripheral.find "minecraft:ender chest" or error "ender chest directly connected required"
- local modem = peripheral.find("modem", function(_, x) return x.isWireless() end) or error "wireless modem required"
- local ok, ecnet = pcall(require, "ecnet")
- if not ok then
- print "Downloading ECNet library (https://forums.computercraft.cc/index.php?topic=181.0)"
- shell.run "wget https://gist.githubusercontent.com/migeyel/278f77628248ea991719f0376979b525/raw/ecnet.min.lua ecnet.lua"
- end
- ecnet = require "ecnet"
- local label = os.getComputerLabel() or error "Please set a label to use as a device name"
- print("Address is", ecnet.address)
- local ecnet_modem = ecnet.wrap(modem)
- local maildata_path = "maildata"
- local acceptable_mailbox_name_pattern = "^[A-Za-z0-9_]+$"
- if not label:match(acceptable_mailbox_name_pattern) then error("label must match: " .. acceptable_mailbox_name_pattern) end
- local function find_channel()
- for i = 0, 10 do
- local new = math.random(0, 0xFFF)
- ender_chest.setFrequency(new)
- local count = 0
- for _, stack in pairs(ender_chest_inv.list()) do
- count = count + stack.count
- end
- if count == 0 then
- return new
- end
- end
- error "Available channel scan failed after 10 tries - has someone flooded ender chests with random stuff?"
- end
- local function writef(n, c)
- local f = fs.open(n, "w")
- f.write(c)
- f.close()
- end
- local function readf(n)
- local f = fs.open(n, "r")
- local out = f.readAll()
- f.close()
- return out
- end
- local data = {}
- if fs.exists(maildata_path) then data = textutils.unserialise(readf(maildata_path)) end
- if type(data.paired) ~= "table" then data.paired = {} end
- local function save_data() writef(maildata_path, textutils.serialise(data)) end
- local function split_at_spaces(s)
- local t = {}
- for i in string.gmatch(s, "%S+") do
- table.insert(t, i)
- end
- return t
- end
- local function update_self()
- print "Downloading update."
- local h = http.get "https://pastebin.com/raw/86Kjhq32"
- local t = h.readAll()
- h.close()
- local fn, err = load(t, "@mail")
- if not fn then printError("Not updating: syntax error in new version:\n" .. err) return end
- local f = fs.open("startup", "w")
- f.write(t)
- f.close()
- os.reboot()
- end
- local function first_letter(s)
- return string.sub(s, 1, 1)
- end
- local function send_stack(slot, addr)
- local channel = find_channel()
- print("[OUT] Channel:", channel)
- ecnet_modem.send(addr, { "stack_request", channel = channel })
- local _, result = os.pullEvent "stack_request_response"
- if result == true then
- ender_chest_inv.pullItems(chest, slot)
- print("[OUT] Sent stack", slot)
- local _, result, x = os.pullEvent "stack_result"
- if result == false then
- printError("[OUT] Destination error: " .. tostring(x))
- for eslot in pairs(ender_chest_inv.list()) do
- ender_chest_inv.pushItems(chest, eslot)
- end
- end
- return result
- else return false end
- end
- local function get_name(address)
- for name, addr in pairs(data.paired) do
- if addr == address then return name end
- end
- return address
- end
- local last_pair_request = nil
- local CLI_commands = {
- address = function()
- print(ecnet.address)
- end,
- update = update_self,
- pair = function(addr)
- local ok = ecnet_modem.connect(addr, 2)
- if not ok then error("Could not contact " .. addr) end
- ecnet_modem.send(addr, { "pair", label = label })
- end,
- accept_pair = function()
- if not last_pair_request then error "no pair request to accept" end
- ecnet_modem.send(last_pair_request.address, { "pair_accept", label = label })
- data.paired[last_pair_request.label] = last_pair_request.address
- save_data()
- last_pair_request = nil
- end,
- reject_pair = function()
- if not last_pair_request then error "no pair request to reject" end
- ecnet_modem.send(last_pair_request.address, { "pair_reject", label = label })
- last_pair_request = nil
- end,
- paired = function()
- print "Paired:"
- for label, addr in pairs(data.paired) do
- print(label, addr)
- end
- end,
- unpair = function(name)
- data.paired[name] = nil
- save_data()
- end,
- send = function(name)
- local addr = data.paired[name]
- if not addr then error(name .. " not found") end
- if not ecnet_modem.connect(addr, 3) then error("Connection to " .. name .. " failed") end
- print "Connected"
- for slot, contents in pairs(peripheral.call(chest, "list")) do
- print("[OUT] Sending stack", slot)
- local timed_out, result = false, nil
- parallel.waitForAny(function() result = send_stack(slot, addr) end, function() sleep(5) timed_out = true end)
- if not timed_out then print("[OUT] Destination success") else printError "[OUT] Timed out." end
- end
- end,
- help = function()
- write([[EnderMail UI commands:
- address - print address
- update - update the code
- pair [address] - send a pairing request to the specified address
- accept_pair - accept the latest pairing request
- deny_pair - reject the latest pairing request
- paired - list all paired mailboxes
- unpair [name] - remove the named mailbox from your paired list
- send [name] - send contents of chest to specified paired mailbox
- ]])
- end
- }
- local function handle_commands()
- print "Mailbox UI"
- local history = {}
- while true do
- write "|> "
- local text = read(nil, history)
- if text ~= "" then table.insert(history, text) end
- local tokens = split_at_spaces(text)
- local command = table.remove(tokens, 1)
- local args = tokens
- local fn = CLI_commands[command]
- if not fn then
- for command_name, func in pairs(CLI_commands) do
- if command and first_letter(command_name) == first_letter(command) then fn = func end
- end
- end
- if not fn then
- print("Command", command, "not found.")
- else
- local ok, err = pcall(fn, table.unpack(args))
- if not ok then printError(err) end
- end
- end
- end
- local function handle_message(addr, msg)
- if type(msg) == "table" then
- if msg[1] == "pair" then
- if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end
- print(("Pair request from %s (%s)"):format(addr, msg.label))
- print "`accept_pair` to accept, `reject_pair` to deny"
- last_pair_request = { address = addr, label = msg.label }
- elseif msg[1] == "pair_accept" then
- if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end
- print(("%s (%s) accepted pairing"):format(addr, msg.label))
- data.paired[msg.label] = addr
- save_data()
- elseif msg[1] == "pair_reject" then
- if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end
- print(("%s (%s) rejected pairing"):format(addr, msg.label))
- elseif msg[1] == "stack_request" then
- if not msg.channel or msg.channel < 0 or msg.channel > 0xFFF then ecnet_modem.send(addr, { "stack_request_response", false, "channel missing/invalid" }) end
- ender_chest.setFrequency(msg.channel)
- ecnet_modem.send(addr, { "stack_request_response", true })
- local start = os.clock()
- -- constantly attempt to move items until done
- while os.clock() - start <= 5 do
- for slot, stack in pairs(ender_chest_inv.list()) do
- local moved = ender_chest_inv.pushItems(chest, slot)
- print("[IN]", get_name(addr), stack.name, moved)
- if moved > 0 then
- ecnet_modem.send(addr, { "stack_result", true, channel = msg.channel })
- return
- else
- ecnet_modem.send(addr, { "stack_result", false, "out of space", channel = msg.channel })
- return
- end
- end
- end
- ecnet_modem.send(addr, { "stack_result", false, channel = msg.channel })
- elseif msg[1] == "stack_request_response" then
- os.queueEvent("stack_request_response", msg[2])
- elseif msg[1] == "stack_result" then
- os.queueEvent("stack_result", msg[2], msg[3])
- end
- end
- end
- local function handle_messages()
- while true do
- handle_message(ecnet_modem.receive())
- end
- end
- parallel.waitForAll(handle_commands, handle_messages)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement