-
Notifications
You must be signed in to change notification settings - Fork 2
/
jobserver
215 lines (183 loc) · 5.92 KB
/
jobserver
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
jobserver = {}
version = "0.1"
os.loadAPI("swarm")
swarm.setSystemType("jobserver")
config = {}
local e,msg,func,job,jobid,status
lastId = 0
--local jobs = {}
jobs = {}
--local sent = {}
sent = {}
--local active = {}
active = {}
counter = {}
function save()
config["active"] = active
config["jobs"] = jobs
config["sent"] = sent
config["lastJobID"] = lastId
swarm.saveConfig(config)
end
function load()
local i,v
config = swarm.loadConfig()
if config == nil then
return nil
end
active = config["active"] or {}
jobs = config["jobs"] or {}
sent = config["sent"] or {}
swarm.statistics["Loaded Jobs"] = swarm.statistics["Loaded Jobs"] + swarm.countArray(jobs)
if type(sent) == "table" then
for i,v in pairs(sent) do
jobs[#jobs+1] = v
swarm.statistics["Loaded Jobs"] = swarm.statistics["Loaded Jobs"] + 1
end
end
sent = {}
if type(active) == "table" then
for i,v in pairs(active) do
jobs[#jobs+1] = v
swarm.statistics["Loaded Jobs"] = swarm.statistics["Loaded Jobs"] + 1
end
end
active = {}
lastId = config["lastJobID"] or 0
return config
end
function main()
swarm.status("main() started",true,-1000)
while not swarm.quit do
swarm.status("main routine: jobs: "..swarm.countArray(jobs).." active: "..swarm.countArray(active).." sent: "..swarm.countArray(sent))
e = {os.pullEvent("modem_message")}
if e[5]["message"]:byte(1) == 20 then -- drone request a job to do
--print(textutils.serialize(e[3]).." requests job")
if #jobs == 0 then
-- print("no jobs in queue, ask me again later")
-- No jobs currently, ask me again later.
rednet.send(e[4],string.char(21).."nil")
swarm.statistics["No Jobs"] = swarm.statistics["No Jobs"] + 1
else
-- Sent a job to drone to consider
job = jobs[1]
jobid = lastId
lastId = lastId + 1
rednet.send(e[4],string.char(21)..textutils.serialize({jobid,job}))
sent[jobid] = job
table.remove(jobs,1)
save()
swarm.statistics["Suggested Jobs"] = swarm.statistics["Suggested Jobs"] + 1
end
elseif e[5]["message"]:byte(1) == 22 then -- drone tells us if it will do a job or not
msg = textutils.unserialize(string.sub(e[5]["message"],2))
jobid = msg[1]
--print("response "..textutils.serialize(msg[2]))
if not msg[2] then
-- drone has denied job
jobs[#jobs+1] = sent[jobid]
table.remove(sent,jobid)
save()
swarm.statistics["Declined Jobs"] = swarm.statistics["Declined Jobs"] + 1
else
-- -- drone has accepted job, yay
active[jobid] = sent[jobid]
table.remove(sent,jobid)
save()
swarm.statistics["Accepted Jobs"] = swarm.statistics["Accepted Jobs"] + 1
end
elseif e[5]["message"]:byte(1) == 24 then -- drone tells us about the status of its job
msg = textutils.unserialize(string.sub(e[5]["message"],2))
jobid = msg[1]
status = msg[2]
msg = msg[3]
-- print("drone "..e[4].." reports for job "..jobid..": status: "..status.." msg: "..msg)
if status == -1 then
table.insert(jobs,active[jobid])
table.remove(active,jobid)
save()
swarm.statistics["Failed Jobs"] = swarm.statistics["Failed Jobs"] + 1
elseif status == -2 then
table.remove(active,jobid)
save()
swarm.statistics["Finished Jobs"] = swarm.statistics["Finished Jobs"] + 1
else
-- status update
end
elseif e[5]["message"]:byte(1) == 25 then -- someone sends a new job.
msg = textutils.unserialize(string.sub(e[5]["message"],2))
if msg ~= nil and type(msg[1]) == "string" then
local fail = false
local tmpe = ""
local function ferr(e)
fail = true
tmpe = e
end
local r,_e = xpcall(function() return loadstring(msg[1]) end,ferr)
if fail then _e = tmpe end
if r == nil or not r or fail then
rednet.send(e[4],string.char(26)..textutils.serialize({false,_e}))
swarm.statistics["Bad Jobs"] = swarm.statistics["Bad Jobs"] + 1
else
table.insert(jobs,{0,msg[1]})
save()
rednet.send(e[4],string.char(26)..textutils.serialize({true}))
swarm.statistics["Created Jobs"] = swarm.statistics["Created Jobs"] + 1
end
else
--print("received NIL job, ignoring")
end
elseif e[5]["message"]:byte(1) == 100 then -- Status query
rednet.send(e[4],string.char(101).."JOBSERVER "..swarm.id.." ["..swarm.label.."] jobs: "..swarm.countArray(jobs).." active: "..swarm.countArray(active).." sent: "..swarm.countArray(sent).." finished: "..config["finished"])
elseif e[5]["message"]:byte(1) == 110 then -- Reboot signal
swarm.status("received reboot signal")
save()
rednet.send(e[4],string.char(111))
swarm.status("will now reboot")
os.reboot()
break
elseif e[5]["message"]:byte(1) == 130 then -- Hard reboot signal
os.reboot()
break
elseif e[5]["message"]:byte(1) == 120 then -- Full status query
rednet.send(e[4],string.char(121)..textutils.serialize(swarm._status))
end
end
end
--[[
The one and only: run()
--]]
function run()
term.clear()
term.setCursorPos(1,1)
-- Prepare statistics table
swarm.statistics["Created Jobs"] = 0
swarm.statistics["Bad Jobs"] = 0
swarm.statistics["Accepted Jobs"] = 0
swarm.statistics["Declined Jobs"] = 0
swarm.statistics["Finished Jobs"] = 0
swarm.statistics["Failed Jobs"] = 0
swarm.statistics["Suggested Jobs"] = 0
swarm.statistics["Loaded Jobs"] = 0
swarm.statistics["No Jobs"] = 0
-- Open modem
swarm.openModem(swarm.id)
swarm.openModem(swarm.CHANNEL_JOB_BROADCAST)
-- Load config or create a default one.
load()
if not config then
print("No config found, trying to create one.")
config = config or {}
config["finished"] = 0
save()
print("Default config created, please change it and reboot.")
return
end
-- Get global environment so we can pass it to the job-script
env = getfenv()
swarm.status("starting routines...",true)
-- Wrappers, to catch errors and stuff
function wrapMain() return swarm.wrap(main,"main") end
parallel.waitForAny(wrapMain,swarm.wrapGui)
return
end