comparison web/settings.py @ 253:0a1b642e3086

long polling config updates
author Matt Johnston <matt@ucc.asn.au>
date Mon, 08 Jun 2015 22:29:46 +0800
parents
children 03e540c3ec24
comparison
equal deleted inserted replaced
251:b6079cb0c665 253:0a1b642e3086
1 import gevent
2 import fcntl
3 import hashlib
4
5 class Settings(object):
6 RAND_SIZE = 15 # 120 bits
7
8 """ Handles state updates from both the web UI and from the fridge client.
9 The fridge client is canonical. It provides the epoch (apart from 'startepoch'), that
10 is changed any time the fridge reloads its local config. The fridge only accepts
11 updates that have the same epoch.
12
13 When the web UI changes it keeps the same epoch but generates a new tag. The fridge sends
14 its current known tag and waits for it to change.
15
16 content is opaque, presently a dictionary of decoded json
17 """
18
19 def __init__(self):
20 self.event = gevent.event.Event()
21 self.contents = None
22 self.epoch = None
23 self.tag = None
24
25 self.update(self, None, 'startepoch')
26
27 def wait(self, epoch_tag = None, timeout = None):
28 """ returns false if the timeout was hit """
29 if self.epoch_tag() != epoch_tag:
30 # has alredy changed
31 return True
32 return self.event.wait(timeout)
33
34 def epoch_tag(self):
35 return '%s-%s' % (self.epoch, self.tag)
36
37 def random(self):
38 return binascii.hexlify(os.urandom(self.RAND_SIZE))
39
40 def update(self, contents, epoch = None):
41 """ replaces settings contents and updates waiters if changed """
42 if epoch:
43 if self.epoch == epoch:
44 return
45 else:
46 self.epoch = epoch
47
48 self.tag = self.random()
49 self.contents = contents
50
51 self.event.set()
52 self.event.clear()
53
54 def get(self):
55 """ Returns (contents, epoch-tag) """
56 return self.contents, self.epoch_tag()
57
58
59
60
61