-
Notifications
You must be signed in to change notification settings - Fork 1
/
pm_handler.lua
290 lines (238 loc) · 6 KB
/
pm_handler.lua
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
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
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: pm_handler.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2012 cisco Systems, Inc.
--
-- Created: Wed Nov 7 19:33:20 2012 mstenber
-- Last modified: Tue Nov 12 11:03:04 2013 mstenber
-- Edit time: 63 min
--
-- single pm handler prototype
require 'mst'
require 'mst_eventful'
local _eventful = mst_eventful.eventful
module('pm_handler', package.seeall)
-- first an abstract class that can be used to get information to a
-- handler
source = _eventful:new_subclass{class='source', mandatory={'parent'}}
-- by default, source is always ready
function source:ready()
return true
end
function source:repr_data()
return '?'
end
pm_handler = _eventful:new_subclass{class='pm_handler',
mandatory={'_pm'},
events={'changed'},
sources={}}
function pm_handler:repr_data()
return '?'
end
function pm_handler:init()
_eventful.init(self)
self.file_contents = {}
self.shell = self._pm.shell
for i, s in ipairs(self.sources)
do
self._sources = self._sources or {}
self._sources[s:new{parent=self}] = s
end
end
function pm_handler:uninit()
for k, v in pairs(self._sources or {})
do
k:done()
end
end
function pm_handler:queue()
local old = self.queued
self.queued = true
return not old
end
function pm_handler:ready()
for k, v in pairs(self._sources or {})
do
if not k:ready()
then
self:d('not ready source', k)
return false
end
end
return true
end
function pm_handler:maybe_tick()
if not self.tick
then
return
end
if not self:ready()
then
return
end
return self:tick()
end
function pm_handler:maybe_run()
if not self.queued
then
--self:d(' not queued')
return
end
-- if not ready, not going to do a thing
self:d('maybe_run')
if not self:ready()
then
self:d(' not ready')
return
end
self.queued = nil
local v = self:run()
if v and v > 0
then
self:changed()
end
end
function pm_handler:run()
-- REALLY implemented by the children
end
function pm_handler:time()
return self._pm:time()
end
function pm_handler:write_to_file(fpath, t0, comment_prefix)
local t = mst.array:new()
local s0 = table.concat(t0, '\n')
if comment_prefix
then
t:insert(comment_prefix)
t:insert(comment_prefix .. fpath)
t:insert(comment_prefix ..
'automatically generated by ' .. self.class ..
' on ' .. os.date())
t:insert(comment_prefix)
end
t:insert(s0)
t:insert('')
local s = t:join('\n')
if self.file_contents[fpath] == s0
then
return
end
self.file_contents[fpath] = s0
local f, err = io.open(fpath, 'w')
self:a(f, 'unable to open for writing', fpath, err)
f:write(s)
-- close the file
io.close(f)
return true
end
-- time handling utility function
function pm_handler:abs_to_delta(now, t, def)
if not t
then
mst.d('using default, no lifetime provided', def)
return def
end
local d = math.floor(t - now)
if d <= 0
then
mst.d('using default - t <= now', d, now, t, def)
return def
else
mst.d('using delta', d)
end
return d, true
end
-- openwrt-specific utilities (used only in pm_netifd_*)
function pm_handler:get_uci_cursor()
require 'uci'
return uci.cursor()
end
function pm_handler:get_uci_cursor()
require 'uci'
return uci.cursor()
end
function pm_handler:get_ubus_connection()
require 'ubus'
return ubus.connect()
end
-- openwrt-specific subclass
ni_source = source:new_subclass{class='ni_source'}
function ni_source:init()
self:connect_method(self.parent._pm.network_interface_changed,
self.ni_changed)
end
function ni_source:ni_changed(ni)
self:d('ni_changed')
self.parent.ni = ni
self.parent:queue()
end
function ni_source:ready()
return self.parent.ni
end
pm_handler_with_ni = pm_handler:new_subclass{class='pm_handler_with_ni',
sources={ni_source}}
pa_source = source:new_subclass{class='pa_source'}
function pa_source:init()
-- then connect to relevant change notifications we're interested about
self:connect_method(self.parent._pm.usp_changed, self.usp_changed)
self:connect_method(self.parent._pm.lap_changed, self.lap_changed)
end
function pa_source:usp_changed(usp)
self.parent.usp = usp
self.parent:queue()
end
function pa_source:lap_changed(lap)
self.parent.lap = lap
self.parent:queue()
end
function pa_source:ready()
return self.parent.usp and self.parent.lap
end
skv_source = source:new_subclass{class='skv_source'}
function skv_source:init()
self:connect_method(self.parent._pm.skv_changed, self.skv_changed)
end
function skv_source:skv_changed(k, v)
-- just proxy skv_changed to parent
self.parent:skv_changed(k, v)
end
pm_handler_with_pa = pm_handler:new_subclass{class='pm_handler_with_pa',
sources={pa_source,
skv_source}}
function pm_handler_with_pa:get_if_table()
if not self.if_table
then
-- shared datastructures
self.if_table = linux_if.if_table:new{shell=self.shell}
end
return self.if_table
end
function pm_handler_with_pa:skv_changed(k, v)
-- nop
end
pm_handler_with_pa_dns = pm_handler_with_pa:new_subclass{class='pm_handler_with_pa_dns'}
function pm_handler_with_pa_dns:skv_changed(k, v)
if k == elsa_pa.OSPF_IPV4_DNS_KEY
then
self.ospf_v4_dns = v or {}
elseif k == elsa_pa.OSPF_IPV4_DNS_SEARCH_KEY
then
self.ospf_v4_dns_search = v or {}
elseif k == elsa_pa.OSPF_DNS_KEY
then
self.ospf_dns = v or {}
elseif k == elsa_pa.OSPF_DNS_SEARCH_KEY
then
self.ospf_dns_search = v or {}
elseif k == elsa_pa.HP_SEARCH_LIST_KEY
then
self.hp_search = v or {}
else
return
end
self:queue()
end