complete SpaceAPI integration
[saartuer.git] / spaceapi.py
1 from threading import Lock
2 from libtuer import ThreadFunction, logger
3 import urllib.request
4
5 from config import spaceApiKey
6
7 class SpaceApi:
8         def __init__ (self, waker):
9                 self._state_to_set = None
10                 self._state_last_set = None
11                 self._running = True
12                 self.set_state = ThreadFunction(self._set_state, "Space API")
13                 self._set_state_lock = Lock()
14                 waker.register(self.set_state, 10.0) # re-try setting the state every 10 seconds
15         
16         def stop (self):
17                 self.set_state.stop()
18         
19         def _do_request(self, state):
20                 state_val = 1 if state else 0
21                 try:
22                         logger.info("Setting SpaceAPI to %d" % state_val)
23                         url = "http://spaceapi.hacksaar.de/status.php?action=update&key=%s&status=%d" % (spaceApiKey, state_val)
24                         response = urllib.request.urlopen(url, timeout=5.0)
25                         responseText = response.read().decode('utf-8').strip()
26                         if response.getcode() == 200 and responseText == "UpdateSuccessful": return True
27                         logger.error("SpaceAPI returned unexpected code %d, content %s" % (response.getcode(), responseText))
28                         return False
29                 except urllib.request.URLError as e:
30                         logger.error("SpaceAPI update returned error: %s" % str(e))
31                         return False
32         
33         # set_state is the asynchronous version of _set_state (see __init__)
34         def _set_state (self, state = None):
35                 '''Sets the state, if None: leave state unchanged and re-try if previous attempts failed'''
36                 if state is not None:
37                         self._state_to_set = state
38                 else:
39                         # always have a local variable because of parallelism
40                         state = self._state_to_set
41                 
42                 if not self._set_state_lock.acquire(False):
43                         # we don't want many threads to wait here
44                         # the next status update will fix everything anyways
45                         pass
46                 else:
47                         # got the lock
48                         try:
49                                 # check if there's something we need to do
50                                 if self._state_last_set == state: return
51                                 # take action!
52                                 success = self._do_request(state)
53                                 # TODO error too often -> log critical to send mails
54                                 if success:
55                                         self._state_last_set = state
56                         finally:
57                                 self._set_state_lock.release()