170
170
# End of Avahi example code
173
def _datetime_to_dbus_struct(dt, variant_level=0):
174
"""Convert a UTC datetime.datetime() to a D-Bus struct.
175
The format is special to this application, since we could not find
176
any other standard way."""
177
return dbus.Struct((dbus.Int16(dt.year),
181
dbus.Byte(dt.minute),
182
dbus.Byte(dt.second),
183
dbus.UInt32(dt.microsecond)),
185
variant_level=variant_level)
173
def _datetime_to_dbus(dt, variant_level=0):
174
"""Convert a UTC datetime.datetime() to a D-Bus type."""
175
return dbus.String(dt.isoformat(), variant_level=variant_level)
188
178
class Client(dbus.service.Object):
194
184
secret: bytestring; sent verbatim (over TLS) to client
195
185
host: string; available for use by the checker command
196
186
created: datetime.datetime(); (UTC) object creation
197
last_started: datetime.datetime(); (UTC)
187
last_enabled: datetime.datetime(); (UTC)
199
189
last_checked_ok: datetime.datetime(); (UTC) or None
200
190
timeout: datetime.timedelta(); How long from last_checked_ok
201
191
until this client is invalid
202
192
interval: datetime.timedelta(); How often to start a new checker
203
stop_hook: If set, called by stop() as stop_hook(self)
193
disable_hook: If set, called by disable() as disable_hook(self)
204
194
checker: subprocess.Popen(); a running checker process used
205
195
to see if the client lives.
206
196
'None' if no process is running.
207
197
checker_initiator_tag: a gobject event source tag, or None
208
stop_initiator_tag: - '' -
198
disable_initiator_tag: - '' -
209
199
checker_callback_tag: - '' -
210
200
checker_command: string; External command which is run to check if
211
201
client lives. %() expansions are done at
249
239
interval = property(lambda self: self._interval, _set_interval)
250
240
del _set_interval
252
def __init__(self, name = None, stop_hook=None, config=None):
242
def __init__(self, name = None, disable_hook=None, config=None):
253
243
"""Note: the 'checker' key in 'config' sets the
254
244
'checker_command' attribute and *not* the 'checker'
281
271
self.host = config.get("host", "")
282
272
self.created = datetime.datetime.utcnow()
284
self.last_started = None
274
self.last_enabled = None
285
275
self.last_checked_ok = None
286
276
self.timeout = string_to_delta(config["timeout"])
287
277
self.interval = string_to_delta(config["interval"])
288
self.stop_hook = stop_hook
278
self.disable_hook = disable_hook
289
279
self.checker = None
290
280
self.checker_initiator_tag = None
291
self.stop_initiator_tag = None
281
self.disable_initiator_tag = None
292
282
self.checker_callback_tag = None
293
283
self.checker_command = config["checker"]
296
286
"""Start this client's checker and timeout hooks"""
297
self.last_started = datetime.datetime.utcnow()
287
self.last_enabled = datetime.datetime.utcnow()
298
288
# Schedule a new checker to be started an 'interval' from now,
299
289
# and every interval from then on.
300
290
self.checker_initiator_tag = (gobject.timeout_add
302
292
self.start_checker))
303
293
# Also start a new checker *right now*.
304
294
self.start_checker()
305
# Schedule a stop() when 'timeout' has passed
306
self.stop_initiator_tag = (gobject.timeout_add
295
# Schedule a disable() when 'timeout' has passed
296
self.disable_initiator_tag = (gobject.timeout_add
307
297
(self._timeout_milliseconds,
310
300
# Emit D-Bus signal
311
self.PropertyChanged(dbus.String(u"started"),
301
self.PropertyChanged(dbus.String(u"enabled"),
312
302
dbus.Boolean(True, variant_level=1))
313
self.PropertyChanged(dbus.String(u"last_started"),
314
(_datetime_to_dbus_struct
315
(self.last_started, variant_level=1)))
303
self.PropertyChanged(dbus.String(u"last_enabled"),
304
(_datetime_to_dbus(self.last_enabled,
318
"""Stop this client."""
319
if not getattr(self, "started", False):
308
"""Disable this client."""
309
if not getattr(self, "enabled", False):
321
logger.info(u"Stopping client %s", self.name)
322
if getattr(self, "stop_initiator_tag", False):
323
gobject.source_remove(self.stop_initiator_tag)
324
self.stop_initiator_tag = None
311
logger.info(u"Disabling client %s", self.name)
312
if getattr(self, "disable_initiator_tag", False):
313
gobject.source_remove(self.disable_initiator_tag)
314
self.disable_initiator_tag = None
325
315
if getattr(self, "checker_initiator_tag", False):
326
316
gobject.source_remove(self.checker_initiator_tag)
327
317
self.checker_initiator_tag = None
328
318
self.stop_checker()
319
if self.disable_hook:
320
self.disable_hook(self)
332
322
# Emit D-Bus signal
333
self.PropertyChanged(dbus.String(u"started"),
323
self.PropertyChanged(dbus.String(u"enabled"),
334
324
dbus.Boolean(False, variant_level=1))
335
325
# Do not run this again if called by a gobject.timeout_add
338
328
def __del__(self):
339
self.stop_hook = None
329
self.disable_hook = None
342
332
def checker_callback(self, pid, condition, command):
343
333
"""The checker has completed, so take appropriate actions."""
378
368
self.last_checked_ok = datetime.datetime.utcnow()
379
gobject.source_remove(self.stop_initiator_tag)
380
self.stop_initiator_tag = (gobject.timeout_add
381
(self._timeout_milliseconds,
369
gobject.source_remove(self.disable_initiator_tag)
370
self.disable_initiator_tag = (gobject.timeout_add
371
(self._timeout_milliseconds,
383
373
self.PropertyChanged(dbus.String(u"last_checked_ok"),
384
(_datetime_to_dbus_struct
385
(self.last_checked_ok,
374
(_datetime_to_dbus(self.last_checked_ok,
388
377
def start_checker(self):
389
378
"""Start a new checker subprocess if one is not running.
459
448
def still_valid(self):
460
449
"""Has the timeout not yet passed for this client?"""
461
if not getattr(self, "started", False):
450
if not getattr(self, "enabled", False):
463
452
now = datetime.datetime.utcnow()
464
453
if self.last_checked_ok is None:
497
486
dbus.String("host"):
498
487
dbus.String(self.host, variant_level=1),
499
488
dbus.String("created"):
500
_datetime_to_dbus_struct(self.created,
502
dbus.String("last_started"):
503
(_datetime_to_dbus_struct(self.last_started,
505
if self.last_started is not None
489
_datetime_to_dbus(self.created, variant_level=1),
490
dbus.String("last_enabled"):
491
(_datetime_to_dbus(self.last_enabled,
493
if self.last_enabled is not None
506
494
else dbus.Boolean(False, variant_level=1)),
507
dbus.String("started"):
508
dbus.Boolean(self.started, variant_level=1),
495
dbus.String("enabled"):
496
dbus.Boolean(self.enabled, variant_level=1),
509
497
dbus.String("last_checked_ok"):
510
(_datetime_to_dbus_struct(self.last_checked_ok,
498
(_datetime_to_dbus(self.last_checked_ok,
512
500
if self.last_checked_ok is not None
513
501
else dbus.Boolean (False, variant_level=1)),
514
502
dbus.String("timeout"):
565
553
def SetTimeout(self, milliseconds):
566
554
self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
569
Start = dbus.service.method(_interface)(start)
570
Start.__name__ = "Start"
557
Enable = dbus.service.method(_interface)(enable)
558
Enable.__name__ = "Enable"
572
560
# StartChecker - method
573
561
@dbus.service.method(_interface)