|
| 1 | +local genv = getfenv() |
| 2 | +local temp = {} |
| 3 | +genv.temp = temp |
| 4 | +local url = 'http://127.0.0.1:4343/' |
| 5 | +local args = {...} |
| 6 | +local tasks = {} |
| 7 | + |
| 8 | +-- https://www.lua.org/pil/11.4.html |
| 9 | +local Queue = {} |
| 10 | +function Queue.new() |
| 11 | + return {head = 0, tail = 0} |
| 12 | +end |
| 13 | +function Queue.push(q, value) |
| 14 | + q[q.head] = value |
| 15 | + q.head = q.head + 1 |
| 16 | +end |
| 17 | +function Queue.pop(q) |
| 18 | + if q.tail >= q.head then return nil end |
| 19 | + local value = q[q.tail] |
| 20 | + q[q.tail] = nil |
| 21 | + q.tail = q.tail + 1 |
| 22 | + return value |
| 23 | +end |
| 24 | +function Queue.length(q) |
| 25 | + return q.head - q.tail |
| 26 | +end |
| 27 | +local output = Queue.new() |
| 28 | + |
| 29 | +local function is_special_task(task_id) |
| 30 | + return (task_id == '_fetch' or task_id == '_send') |
| 31 | +end |
| 32 | + |
| 33 | +local function string_split(text) |
| 34 | + local pos = string.find(text, ';') |
| 35 | + return string.sub(text, 1, pos - 1), string.sub(text, pos + 1) |
| 36 | +end |
| 37 | + |
| 38 | +local function inner_resume(task_id, ...) |
| 39 | + local r = {coroutine.resume(tasks[task_id].co, ...)} |
| 40 | + if coroutine.status(tasks[task_id].co) == 'dead' then |
| 41 | + if not is_special_task(task_id) then |
| 42 | + Queue.push(output, {task_id=task_id, result=r}) |
| 43 | + end |
| 44 | + tasks[task_id] = nil |
| 45 | + return true |
| 46 | + end |
| 47 | + if r[1] then tasks[task_id].exp = r[2] end |
| 48 | + return false |
| 49 | +end |
| 50 | + |
| 51 | +local function make_task(task_id, f, ...) |
| 52 | + tasks[task_id] = {co=coroutine.create(f)} |
| 53 | + return inner_resume(task_id, ...) |
| 54 | +end |
| 55 | + |
| 56 | +local function resume_task(task_id, event, ...) |
| 57 | + local exp = tasks[task_id].exp |
| 58 | + if exp ~= nil and event ~= exp then return false end |
| 59 | + return inner_resume(task_id, event, ...) |
| 60 | +end |
| 61 | + |
| 62 | +local function event_queue(task_id, event) |
| 63 | + while true do |
| 64 | + local estruct = {os.pullEvent(event)} |
| 65 | + Queue.push(output, {task_id=task_id, result=estruct}) |
| 66 | + end |
| 67 | +end |
| 68 | + |
| 69 | +local function fetch_fn() |
| 70 | + local r = http.post(url..'start/'..os.getComputerID()..'/'..args[1]..'/') |
| 71 | + if (r == nil or r.getResponseCode() ~= 200) then |
| 72 | + print('Failed to start program '..args[1]) |
| 73 | + return |
| 74 | + end |
| 75 | + while true do |
| 76 | + r = http.post(url..'gettask/'..os.getComputerID()..'/', answer) |
| 77 | + if (r == nil or r.getResponseCode() ~= 200) then |
| 78 | + print('Connection broken') |
| 79 | + return |
| 80 | + end |
| 81 | + local cmd = r.readAll() |
| 82 | + if cmd == 'END' then |
| 83 | + break |
| 84 | + elseif cmd ~= 'NOOP' then |
| 85 | + local cmd, text = string_split(cmd) |
| 86 | + if cmd == 'TASK' then |
| 87 | + local task_id, text = string_split(text) |
| 88 | + local f = loadstring(text) |
| 89 | + setfenv(f, genv) |
| 90 | + make_task(task_id, f) |
| 91 | + elseif cmd == 'STARTQUEUE' then |
| 92 | + local task_id, text = string_split(text) |
| 93 | + make_task(task_id, event_queue, task_id, text) |
| 94 | + elseif cmd == 'STOPQUEUE' then |
| 95 | + tasks[text] = nil |
| 96 | + end |
| 97 | + end |
| 98 | + end |
| 99 | +end |
| 100 | + |
| 101 | +local function send_fn() |
| 102 | + while true do |
| 103 | + local r = Queue.pop(output) |
| 104 | + if r == nil then break end |
| 105 | + local answer = textutils.serializeJSON(r.result) |
| 106 | + http.post(url..'taskresult/'..os.getComputerID()..'/'..r.task_id..'/', answer) |
| 107 | + end |
| 108 | +end |
| 109 | + |
| 110 | +if make_task('_fetch', fetch_fn) then return end |
| 111 | + |
| 112 | +while true do |
| 113 | + local event, p1, p2, p3, p4, p5 = os.pullEvent() |
| 114 | + if resume_task('_fetch', event, p1, p2, p3, p4, p5) then break end |
| 115 | + |
| 116 | + -- Use of http API in user code is explicitly disallowed |
| 117 | + if event ~= 'http_success' and event ~= 'http_failure' then |
| 118 | + local local_task_ids = {} |
| 119 | + for task_id in pairs(tasks) do |
| 120 | + local_task_ids[task_id] = true |
| 121 | + end |
| 122 | + for task_id in pairs(local_task_ids) do |
| 123 | + if not is_special_task(task_id) then |
| 124 | + resume_task(task_id, event, p1, p2, p3, p4, p5) |
| 125 | + end |
| 126 | + end |
| 127 | + end |
| 128 | + |
| 129 | + if tasks['_send'] ~= nil then |
| 130 | + resume_task('_send', event, p1, p2, p3, p4, p5) |
| 131 | + else |
| 132 | + if Queue.length(output) > 0 then make_task('_send', send_fn) end |
| 133 | + end |
| 134 | +end |
0 commit comments