def __init__(self, host, port=None, ws=True, stop_event=None): threading.Thread.__init__(self) if not host[-1] == "]" and host.rfind(":") > -1: # Not a literal IPv6 address and a port is given as part of the hostname pos = host.rfind(":") if pos > -1: port = int(host[pos+1:]) host = host[:pos] self.log = MyLog().log # Synchronization self._client_lock = threading.Lock() self._stop_event = stop_event if stop_event != None else threading.Event() # Data structures self._cache = {} # msvid -> msv_data self._msv_handlers = [] self._set_handlers = [] # Timeout Manager self._tm = timeouts.TimeoutManager(stop_event=self._stop_event) # Server Clock Estimator self._clock = ServerClockEstimator() # Backoffticker self._ticker = BackoffTicker(self._tm, self._ontick) # Request management self._request_counter = 0 self._pending_requests = {} # reqid -> (event, result) # Connection to MsvServer if ws == True: self._conn = connection.WSConnection() if not port: self._serv_addr = (host, messages.CLIENT_ACCEPT_PORT) else: self._serv_addr = (host, port) else: self._conn = connection.Connection() if not port: self._serv_addr = (host, messages.FRONTEND_ACCEPT_PORT) else: self._serv_addr = (host, port) self._isReady = threading.Event()
class Client(threading.Thread): def __init__(self, host, port=None, ws=True, stop_event=None): threading.Thread.__init__(self) if not host[-1] == "]" and host.rfind(":") > -1: # Not a literal IPv6 address and a port is given as part of the hostname pos = host.rfind(":") if pos > -1: port = int(host[pos+1:]) host = host[:pos] self.log = MyLog().log # Synchronization self._client_lock = threading.Lock() self._stop_event = stop_event if stop_event != None else threading.Event() # Data structures self._cache = {} # msvid -> msv_data self._msv_handlers = [] self._set_handlers = [] # Timeout Manager self._tm = timeouts.TimeoutManager(stop_event=self._stop_event) # Server Clock Estimator self._clock = ServerClockEstimator() # Backoffticker self._ticker = BackoffTicker(self._tm, self._ontick) # Request management self._request_counter = 0 self._pending_requests = {} # reqid -> (event, result) # Connection to MsvServer if ws == True: self._conn = connection.WSConnection() if not port: self._serv_addr = (host, messages.CLIENT_ACCEPT_PORT) else: self._serv_addr = (host, port) else: self._conn = connection.Connection() if not port: self._serv_addr = (host, messages.FRONTEND_ACCEPT_PORT) else: self._serv_addr = (host, port) self._isReady = threading.Event() def isReady(self): return self._isReady.isSet() def waitForReady(self, timeout): return self._isReady.wait(timeout) def isConnected(self): """Added by Ingar to check if client is ready for operation. TODO: this should NOT be different from isReady """ return self._conn and self._conn.is_connected() def stop(self): """Request that the client (main loop) stops""" self._stop_event.set() def run(self): """Main loop""" self._tm.start() #self._conn.connect(self._serv_addr) self._ticker.start() self._isReady.set() while not self._stop_event.is_set(): if not self._conn.is_connected(): try: self._conn.connect(self._serv_addr) # Get whatever msvs we were already monitoring self.log.debug("Reconnected, restoring subscriptions") self.get(self._cache.keys()) except: self.log.exception("Failed to connect, retrying later") time.sleep(5) continue try: data = self._conn.get(1.0) except: self.log.exception("Failed to read, trying to reconnect") self._conn.close() continue if data != None: try: msg = json.loads(data) self._onmessage(msg) except ValueError: self.log.exception("Bad message '%s'"%data) continue # Cleanup self._conn.close() def _onmessage(self, msg): """Receive message from connection""" if msg['cmd'] == MsvCmd.PONG: cs, ss = msg['data'] cr = time.time() self._clock.add_sample(cs, ss, cr) return if msg['type'] == MsgType.RESPONSE: # all responses except PONG # Update Msv Cache if msg['cmd'] in [MsvCmd.GET, MsvCmd.CREATE]: for msv_data in msg['data']: self._cache[msv_data['msvid']] = msv_data try: # Hand over response to requesting client self._onresponse(msg) except Exception, e: print "MSV CLIENT ERROR, calling onresponse:",e traceback.print_exc() # Notify clients of set changes if msg['cmd'] in [MsvCmd.GET, MsvCmd.CREATE]: msvid_list = [x['msvid'] for x in msg['data']] for handler in self._set_handlers: try: handler(msvid_list, []) except Exception, e: print "MSV CLIENT ERROR on handler %s: %s"%(handler, e) traceback.print_exc() return