SHOW:
|
|
- or go back to the newest paste.
1 | - | local ec = peripheral.find "ender_chest" |
1 | + | package.path = "/?;/?.lua;" .. package.path |
2 | - | local ecinv = peripheral.find "minecraft:ender chest" |
2 | + | local chest = settings.get "mail.chest" or error "please set mail.chest to the network name of the (non-ender) chest to use" |
3 | local ender_chest = peripheral.find "ender_chest" or error "ender chest connected through adapter + relay required" | |
4 | - | local f = fs.open("escan.log", "w") |
4 | + | local ender_chest_inv = peripheral.find "minecraft:ender chest" or error "ender chest directly connected required" |
5 | local modem = peripheral.find("modem", function(_, x) return x.isWireless() end) or error "wireless modem required" | |
6 | - | local z = ... |
6 | + | local ok, ecnet = pcall(require, "ecnet") |
7 | - | if z then |
7 | + | if not ok then |
8 | - | ec.setFrequency(tonumber(z, 16)) |
8 | + | print "Downloading ECNet library (https://forums.computercraft.cc/index.php?topic=181.0)" |
9 | - | return |
9 | + | shell.run "wget https://gist.githubusercontent.com/migeyel/278f77628248ea991719f0376979b525/raw/ecnet.min.lua ecnet.lua" |
10 | end | |
11 | ecnet = require "ecnet" | |
12 | - | for i = 0, 0xFFF do |
12 | + | local label = os.getComputerLabel() or error "Please set a label to use as a device name" |
13 | - | ec.setFrequency(i) |
13 | + | print("Address is", ecnet.address) |
14 | - | local count = 0 |
14 | + | local ecnet_modem = ecnet.wrap(modem) |
15 | - | for _, s in pairs(ecinv.list()) do |
15 | + | local maildata_path = "maildata" |
16 | - | count = count + s.count |
16 | + | |
17 | local acceptable_mailbox_name_pattern = "^[A-Za-z0-9_]+$" | |
18 | - | if count > 0 then |
18 | + | if not label:match(acceptable_mailbox_name_pattern) then error("label must match: " .. acceptable_mailbox_name_pattern) end |
19 | - | local log = ("%s %s 0x%03x %d"):format(os.date "!%X", table.concat(ec.getFrequencyColors(), "/"), i, count) |
19 | + | |
20 | - | print(log) |
20 | + | local function find_channel() |
21 | - | f.writeLine(log) |
21 | + | for i = 0, 10 do |
22 | local new = math.random(0, 0xFFF) | |
23 | - | if i % 256 == 255 then |
23 | + | ender_chest.setFrequency(new) |
24 | - | f.flush() |
24 | + | local count = 0 |
25 | for _, stack in pairs(ender_chest_inv.list()) do | |
26 | - | os.queueEvent "" |
26 | + | count = count + stack.count |
27 | - | os.pullEvent "" |
27 | + | end |
28 | if count == 0 then | |
29 | return new | |
30 | - | f.close() |
30 | + | end |
31 | end | |
32 | error "Available channel scan failed after 10 tries - has someone flooded ender chests with random stuff?" | |
33 | end | |
34 | ||
35 | local function writef(n, c) | |
36 | local f = fs.open(n, "w") | |
37 | f.write(c) | |
38 | f.close() | |
39 | end | |
40 | ||
41 | local function readf(n) | |
42 | local f = fs.open(n, "r") | |
43 | local out = f.readAll() | |
44 | f.close() | |
45 | return out | |
46 | end | |
47 | ||
48 | local data = {} | |
49 | if fs.exists(maildata_path) then data = textutils.unserialise(readf(maildata_path)) end | |
50 | if type(data.paired) ~= "table" then data.paired = {} end | |
51 | ||
52 | local function save_data() writef(maildata_path, textutils.serialise(data)) end | |
53 | ||
54 | local function split_at_spaces(s) | |
55 | local t = {} | |
56 | for i in string.gmatch(s, "%S+") do | |
57 | table.insert(t, i) | |
58 | end | |
59 | return t | |
60 | end | |
61 | ||
62 | local function update_self() | |
63 | print "Downloading update." | |
64 | local h = http.get "https://pastebin.com/raw/86Kjhq32" | |
65 | local t = h.readAll() | |
66 | h.close() | |
67 | local fn, err = load(t, "@mail") | |
68 | if not fn then printError("Not updating: syntax error in new version:\n" .. err) return end | |
69 | local f = fs.open("startup", "w") | |
70 | f.write(t) | |
71 | f.close() | |
72 | os.reboot() | |
73 | end | |
74 | ||
75 | local function first_letter(s) | |
76 | return string.sub(s, 1, 1) | |
77 | end | |
78 | ||
79 | local function send_stack(slot, addr) | |
80 | local channel = find_channel() | |
81 | print("[OUT] Channel:", channel) | |
82 | ecnet_modem.send(addr, { "stack_request", channel = channel }) | |
83 | local _, result = os.pullEvent "stack_request_response" | |
84 | if result == true then | |
85 | ender_chest_inv.pullItems(chest, slot) | |
86 | print("[OUT] Sent stack", slot) | |
87 | local _, result, x = os.pullEvent "stack_result" | |
88 | if result == false then | |
89 | printError("[OUT] Destination error: " .. tostring(x)) | |
90 | for eslot in pairs(ender_chest_inv.list()) do | |
91 | ender_chest_inv.pushItems(chest, eslot) | |
92 | end | |
93 | end | |
94 | return result | |
95 | else return false end | |
96 | end | |
97 | ||
98 | local function get_name(address) | |
99 | for name, addr in pairs(data.paired) do | |
100 | if addr == address then return name end | |
101 | end | |
102 | return address | |
103 | end | |
104 | ||
105 | local last_pair_request = nil | |
106 | ||
107 | local CLI_commands = { | |
108 | address = function() | |
109 | print(ecnet.address) | |
110 | end, | |
111 | update = update_self, | |
112 | pair = function(addr) | |
113 | local ok = ecnet_modem.connect(addr, 2) | |
114 | if not ok then error("Could not contact " .. addr) end | |
115 | ecnet_modem.send(addr, { "pair", label = label }) | |
116 | end, | |
117 | accept_pair = function() | |
118 | if not last_pair_request then error "no pair request to accept" end | |
119 | ecnet_modem.send(last_pair_request.address, { "pair_accept", label = label }) | |
120 | data.paired[last_pair_request.label] = last_pair_request.address | |
121 | save_data() | |
122 | last_pair_request = nil | |
123 | end, | |
124 | reject_pair = function() | |
125 | if not last_pair_request then error "no pair request to reject" end | |
126 | ecnet_modem.send(last_pair_request.address, { "pair_reject", label = label }) | |
127 | last_pair_request = nil | |
128 | end, | |
129 | paired = function() | |
130 | print "Paired:" | |
131 | for label, addr in pairs(data.paired) do | |
132 | print(label, addr) | |
133 | end | |
134 | end, | |
135 | unpair = function(name) | |
136 | data.paired[name] = nil | |
137 | save_data() | |
138 | end, | |
139 | send = function(name) | |
140 | local addr = data.paired[name] | |
141 | if not addr then error(name .. " not found") end | |
142 | if not ecnet_modem.connect(addr, 3) then error("Connection to " .. name .. " failed") end | |
143 | print "Connected" | |
144 | for slot, contents in pairs(peripheral.call(chest, "list")) do | |
145 | print("[OUT] Sending stack", slot) | |
146 | local timed_out, result = false, nil | |
147 | parallel.waitForAny(function() result = send_stack(slot, addr) end, function() sleep(5) timed_out = true end) | |
148 | if not timed_out then print("[OUT] Destination success") else printError "[OUT] Timed out." end | |
149 | end | |
150 | end, | |
151 | help = function() | |
152 | write([[EnderMail UI commands: | |
153 | address - print address | |
154 | update - update the code | |
155 | pair [address] - send a pairing request to the specified address | |
156 | accept_pair - accept the latest pairing request | |
157 | deny_pair - reject the latest pairing request | |
158 | paired - list all paired mailboxes | |
159 | unpair [name] - remove the named mailbox from your paired list | |
160 | send [name] - send contents of chest to specified paired mailbox | |
161 | ]]) | |
162 | end | |
163 | } | |
164 | ||
165 | local function handle_commands() | |
166 | print "Mailbox UI" | |
167 | local history = {} | |
168 | while true do | |
169 | write "|> " | |
170 | local text = read(nil, history) | |
171 | ||
172 | if text ~= "" then table.insert(history, text) end | |
173 | ||
174 | local tokens = split_at_spaces(text) | |
175 | local command = table.remove(tokens, 1) | |
176 | local args = tokens | |
177 | local fn = CLI_commands[command] | |
178 | ||
179 | if not fn then | |
180 | for command_name, func in pairs(CLI_commands) do | |
181 | if command and first_letter(command_name) == first_letter(command) then fn = func end | |
182 | end | |
183 | end | |
184 | if not fn then | |
185 | print("Command", command, "not found.") | |
186 | else | |
187 | local ok, err = pcall(fn, table.unpack(args)) | |
188 | if not ok then printError(err) end | |
189 | end | |
190 | end | |
191 | end | |
192 | ||
193 | local function handle_message(addr, msg) | |
194 | if type(msg) == "table" then | |
195 | if msg[1] == "pair" then | |
196 | if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end | |
197 | print(("Pair request from %s (%s)"):format(addr, msg.label)) | |
198 | print "`accept_pair` to accept, `reject_pair` to deny" | |
199 | last_pair_request = { address = addr, label = msg.label } | |
200 | elseif msg[1] == "pair_accept" then | |
201 | if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end | |
202 | print(("%s (%s) accepted pairing"):format(addr, msg.label)) | |
203 | data.paired[msg.label] = addr | |
204 | save_data() | |
205 | elseif msg[1] == "pair_reject" then | |
206 | if not msg.label or not msg.label:match(acceptable_mailbox_name_pattern) then return end | |
207 | print(("%s (%s) rejected pairing"):format(addr, msg.label)) | |
208 | elseif msg[1] == "stack_request" then | |
209 | 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 | |
210 | ender_chest.setFrequency(msg.channel) | |
211 | ecnet_modem.send(addr, { "stack_request_response", true }) | |
212 | local start = os.clock() | |
213 | -- constantly attempt to move items until done | |
214 | while os.clock() - start <= 5 do | |
215 | for slot, stack in pairs(ender_chest_inv.list()) do | |
216 | local moved = ender_chest_inv.pushItems(chest, slot) | |
217 | print("[IN]", get_name(addr), stack.name, moved) | |
218 | if moved > 0 then | |
219 | ecnet_modem.send(addr, { "stack_result", true, channel = msg.channel }) | |
220 | return | |
221 | else | |
222 | ecnet_modem.send(addr, { "stack_result", false, "out of space", channel = msg.channel }) | |
223 | return | |
224 | end | |
225 | end | |
226 | end | |
227 | ecnet_modem.send(addr, { "stack_result", false, channel = msg.channel }) | |
228 | elseif msg[1] == "stack_request_response" then | |
229 | os.queueEvent("stack_request_response", msg[2]) | |
230 | elseif msg[1] == "stack_result" then | |
231 | os.queueEvent("stack_result", msg[2], msg[3]) | |
232 | end | |
233 | end | |
234 | end | |
235 | ||
236 | local function handle_messages() | |
237 | while true do | |
238 | handle_message(ecnet_modem.receive()) | |
239 | end | |
240 | end | |
241 | ||
242 | parallel.waitForAll(handle_commands, handle_messages) |