from threading import Lock
from libtuer import ThreadFunction, logger
-import urllib.request
+import urllib.request, time
from config import spaceApiKey
+RETRY_TIME = 60
+HEARTBEAT_TIME = 10*60
+
class SpaceApi:
def __init__ (self, waker):
- self._state_to_set = None
- self._state_last_set = None
+ self._local_state = None
+ self._remote_state = None
+ self._last_set_at = 0
self._running = True
+ self._fail_count = 0 # number of consecutive fails
self.set_state = ThreadFunction(self._set_state, "Space API")
- self._set_state_lock = Lock()
- waker.register(self.set_state, 10.0) # re-try setting the state every 10 seconds
+ waker.register(self.set_state, RETRY_TIME)
def stop (self):
self.set_state.stop()
state_val = 1 if state else 0
try:
logger.info("Setting SpaceAPI to %d" % state_val)
- url = "http://spaceapi.hacksaar.de/status.php?action=update&key=%s&status=%d" % (spaceApiKey, state_val)
+ url = "https://spaceapi.hacksaar.de/status.php?action=update&key=%s&status=%d" % (spaceApiKey, state_val)
response = urllib.request.urlopen(url, timeout=5.0)
responseText = response.read().decode('utf-8').strip()
if response.getcode() == 200 and responseText == "UpdateSuccessful": return True
def _set_state (self, state = None):
'''Sets the state, if None: leave state unchanged and re-try if previous attempts failed'''
if state is not None:
- self._state_to_set = state
- else:
- # always have a local variable because of parallelism
- state = self._state_to_set
-
- if not self._set_state_lock.acquire(False):
- # we don't want many threads to wait here
- # the next status update will fix everything anyways
- pass
- else:
- # got the lock
- try:
- # check if there's something we need to do
- if self._state_last_set == state: return
- # take action!
- success = self._do_request(state)
- # TODO error too often -> log critical to send mails
- if success:
- self._state_last_set = state
- finally:
- self._set_state_lock.release()
+ self._local_state = state
+ # check if there's something we need to do: There's a valid state, and either the state has changed or
+ # we need to refresh our heartbeta)
+ now = time.time()
+ if self._local_state is not None and (self._local_state != self._remote_state or now > self._last_set_at+HEARTBEAT_TIME):
+ # take action!
+ success = self._do_request(self._local_state)
+ if success:
+ self._remote_state = self._local_state
+ self._last_set_at = now
+ self._fail_count = 0
+ else:
+ self._fail_count += 1
+ if self._fail_count in (5, 100):
+ logger.critical("Updating the SpaceAPI failed %d times in a row" % self._fail_count)