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
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
|
# File 'lib/multi_movingsign/server.rb', line 36
def start
TestRCLoader.load(options['testrc']) if options['testrc']
FileUtils.mkdir_p server_settings_path
lock_path = File.join(server_settings_path, "server.lock")
File.open(lock_path, 'w') do |lock|
raise "Cannot acquire lock! Is a server already running?" unless lock.flock(File::LOCK_EX | File::LOCK_NB)
lock.puts $$
lock.flush
mutex = Mutex.new
log_path = File.join(server_settings_path, "server.log")
log = File.new(log_path, "a")
$stdout = TeeIO.new($stdout, log)
$stderr = TeeIO.new($stderr, log)
signs = []
page_keys = []
page_solutions = {}
page_index = 0
alert = nil
stop = nil
Thread.new do
begin
Socket.unix_server_loop(server_socket_path) do |socket, address|
puts "SOCKET LOOP!"
begin
msg = nil
begin
msg, = socket.recvmsg_nonblock
rescue IO::WaitReadable
if IO.select([socket], [], [], 5)
retry
else
raise TimeoutError, "Timeout in recvmsg_nonblock"
end
end
unless msg
$stderr.puts "Bogus unix_server_loop?"
next
end
lines = msg.lines.map { |l| l.rstrip }
puts "Got UNIX message: #{lines.inspect}"
version = lines.delete_at 0
case command = lines.delete_at(0)
when 'add page'
name = lines.delete_at(0)
yaml = lines.join "\n"
solution = PageRenderer.new.render YAML.load(yaml), :count => signs.length
page_path = File.join(server_pages_path, "#{name}.yml")
File.open(page_path, "w") { |f| f.puts yaml }
mutex.synchronize do
page_solutions[name] = solution
page_keys << name unless page_keys.include? name
puts "Added #{name}!"
page_keys.delete 'nada'
page_solutions.delete 'nada'
end
socket.puts "okay"
when 'delete page'
name = lines.delete_at(0)
mutex.synchronize do
page_path = File.join(server_pages_path, "#{name}.yml")
FileUtils.rm(page_path, :force => true) if File.exists? page_path
page_keys.delete name
page_solutions.delete name
end
puts "Deleted #{name}"
socket.puts "okay"
when 'alert'
page_yaml = lines.join("\n")
mutex.synchronize do
condition_variable = ConditionVariable.new
alert = {"solution" => PageRenderer.new.render(YAML.load(page_yaml), :count => signs.length), 'condition_variable' => condition_variable}
puts "Signaling alert..."
condition_variable.wait mutex
end
socket.puts "okay"
when 'stop'
mutex.synchronize do
cv = ConditionVariable.new
stop = {'condition_variable' => cv}
cv.wait mutex
end
socket.puts "okay"
else
$stderr.puts "Unknown command '#{command}'"
end
rescue => e
$stderr.puts "Exception in unix server loop"
$stderr.puts e.message
$stderr.puts e.backtrace.join "\n"
ensure
socket.close
puts "SOCKET CLOSED"
end
end
rescue => e
$stderr.puts "UNIX socket loop raised!"
$stderr.puts e.message
$stderr.puts e.backtrace.join '\n'
Thread::current.pi
end
end
loop do
if stop
puts "Outter loop stopping..."
break
end
puts "Starting/Reloading!"
settings = Settings.load settings_path
raise_no_signs unless settings.signs?
mutex.synchronize do
page_keys = []
page_solutions = {}
signs = Signs.new settings.signs
FileUtils.mkdir_p server_pages_path
Dir.glob(File.join(server_pages_path, '*.yml')).sort.each do |path|
puts "Loading #{path}"
key = File.basename(path, File.extname(path))
page_keys << key
page_solutions[key] = PageRenderer.new.render YAML.load(File.read(path)), :count => signs.length
end
if page_keys.empty?
page_keys << 'nada'
page_solutions['nada'] = PageRenderer.new.render({'lines' => [{'prefix' => '', 'content' => ['No Pages']}, {'prefix' => '', 'content' => ['Configured']}]}, :count => signs.length)
end
end
loop do
if stop
puts "Inner loop stopping..."
break
end
page_key = nil
page_solution = nil
mutex.synchronize do
page_index = 0 if page_index >= page_keys.length || page_index < 0
if alert
page_key = 'ALERT'
page_solution = alert['solution']
page_index -= 1
condition_variable = alert['condition_variable']
alert = nil
condition_variable.signal
else
page_key = page_keys[page_index]
page_solution = page_solutions[page_key]
end
end
puts "Sending page #{page_key}"
signs.show_page_solution page_solution
sleep_amount = page_solution['lines'] && page_solution['lines'] * 3 * 2 || 20
sleep_amount = 20 if sleep_amount < 2
sleep sleep_amount
page_index += 1
end
end
if cv = stop && stop['condition_variable']
cv.signal
sleep 1 end
end
end
|