def test_exceptions(self): stats = SMPPClientStatsCollector().get(cid = 'test_exceptions') self.assertRaises(KeyNotFound, stats.get, 'anything') self.assertRaises(KeyNotFound, stats.set, 'anything', 22) self.assertRaises(KeyNotFound, stats.inc, 'anything') stats.set('created_at', datetime.now()) self.assertRaises(KeyNotIncrementable, stats.inc, 'created_at')
def test_stats_set(self): stats = SMPPClientStatsCollector().get(cid = 'test_stats_set') self.assertEqual(stats.get('last_seqNum'), None) stats.set('last_seqNum', 2) self.assertEqual(stats.get('last_seqNum'), 2)
class SMPPClientFactory(ClientFactory): protocol = SMPPClientProtocol def __init__(self, config, msgHandler=None): self.reconnectTimer = None self.smpp = None self.connectionRetry = True self.config = config # Setup statistics collector self.stats = SMPPClientStatsCollector().get(cid=self.config.id) self.stats.set('created_at', datetime.now()) # Set up a dedicated logger self.log = logging.getLogger(LOG_CATEGORY_CLIENT_BASE + ".%s" % config.id) if len(self.log.handlers) != 1: self.log.setLevel(self.config.log_level) _when = self.config.log_rotate if hasattr( self.config, 'log_rotate') else 'midnight' if 'stdout' in self.config.log_file: handler = logging.StreamHandler(sys.stdout) else: handler = TimedRotatingFileHandler( filename=self.config.log_file, when=_when) formatter = logging.Formatter(self.config.log_format, self.config.log_date_format) handler.setFormatter(formatter) self.log.addHandler(handler) self.log.propagate = False if msgHandler is None: self.msgHandler = self.msgHandlerStub else: self.msgHandler = msgHandler def buildProtocol(self, addr): """Provision protocol """ proto = ClientFactory.buildProtocol(self, addr) # Setup logger proto.log = self.log return proto def getConfig(self): return self.config def msgHandlerStub(self, smpp, pdu): self.log.warn("msgHandlerStub: Received an unhandled message %s ...", pdu) def startedConnecting(self, connector): self.log.info("Connecting to %s ...", connector.getDestination()) def getExitDeferred(self): """Get a Deferred so you can be notified on disconnect and exited This deferred is called once disconnection occurs without a further reconnection retrys """ return self.exitDeferred def clientConnectionFailed(self, connector, reason): """Connection failed """ self.log.error("Connection failed. Reason: %s", str(reason)) if self.config.reconnectOnConnectionFailure and self.connectionRetry: self.log.info("Reconnecting after %d seconds ...", self.config.reconnectOnConnectionFailureDelay) self.reconnectTimer = reactor.callLater( self.config.reconnectOnConnectionFailureDelay, self.reConnect, connector) else: self.connectDeferred.errback(reason) self.exitDeferred.callback(None) self.log.info("Exiting.") def clientConnectionLost(self, connector, reason): """Connection lost """ self.log.error("Connection lost. Reason: %s", str(reason)) if self.config.reconnectOnConnectionLoss and self.connectionRetry: self.log.info("Reconnecting after %d seconds ...", self.config.reconnectOnConnectionLossDelay) self.reconnectTimer = reactor.callLater( self.config.reconnectOnConnectionLossDelay, self.reConnect, connector) else: self.exitDeferred.callback(None) self.log.info("Exiting.") def reConnect(self, connector=None): if connector is None: self.log.error("No connector to retry !") else: # Reset deferred if it were called before if self.connectDeferred.called is True: self.connectDeferred = defer.Deferred() self.connectDeferred.addCallback(self.bind) # And try to connect again connector.connect() def _connect(self): self.connectionRetry = True if self.config.useSSL: self.log.info('Establishing SSL connection to %s:%d', self.config.host, self.config.port) reactor.connectSSL(self.config.host, self.config.port, self, CtxFactory(self.config)) else: self.log.info('Establishing TCP connection to %s:%d', self.config.host, self.config.port) reactor.connectTCP(self.config.host, self.config.port, self) self.exitDeferred = defer.Deferred() self.connectDeferred = defer.Deferred() return self.connectDeferred def connectAndBind(self): self._connect() self.connectDeferred.addCallback(self.bind) return self.connectDeferred def disconnect(self): if self.smpp is not None: self.log.info('Disconnecting SMPP client') return self.smpp.unbindAndDisconnect() else: return None def stopConnectionRetrying(self): """This will stop the factory from reconnecting It is used whenever a service stop has been requested, the connectionRetry flag is reset to True upon connect() call """ self.log.info('Stopped automatic connection retrying.') if self.reconnectTimer and self.reconnectTimer.active(): self.reconnectTimer.cancel() self.reconnectTimer = None self.connectionRetry = False def disconnectAndDontRetryToConnect(self): self.log.info('Ordering a disconnect with no further reconnections.') self.stopConnectionRetrying() return self.disconnect() def bind(self, smpp): self.smpp = smpp if self.config.bindOperation == 'transceiver': return smpp.bindAsTransceiver() elif self.config.bindOperation == 'receiver': return smpp.bindAsReceiver() elif self.config.bindOperation == 'transmitter': return smpp.bindAsTransmitter() else: raise SMPPClientError("Invalid bind operation: %s" % self.config.bindOperation) def getSessionState(self): if self.smpp is None: return SMPPSessionStates.NONE else: return self.smpp.sessionState