From 88426be62a8f464322ccfd7461a5602b63afd0e2 Mon Sep 17 00:00:00 2001 From: Mark Veidemanis Date: Sat, 3 Feb 2018 19:03:47 +0000 Subject: [PATCH] Move things into factories and implement reconnecting --- conf/example/config.json | 7 ++- threshold | 103 +++++++++++++++++++++++++-------------- 2 files changed, 72 insertions(+), 38 deletions(-) diff --git a/conf/example/config.json b/conf/example/config.json index c4e6afe..5ead613 100644 --- a/conf/example/config.json +++ b/conf/example/config.json @@ -21,6 +21,10 @@ "protocol": null, "bind": null, "timeout": 30, + "maxdelay": 5, + "initialdelay": 1, + "factor": 2, + "jitter": 5, "nickname": null, "username": null, "realname": null, @@ -33,8 +37,7 @@ "password": null, "authentity": "NickServ", "key": "key.pem", - "certificate": "cert.pem", - "enabled": true + "certificate": "cert.pem" }, "Master": [null, null] } diff --git a/threshold b/threshold index f7c4b97..9d4df1c 100755 --- a/threshold +++ b/threshold @@ -2,8 +2,7 @@ from twisted.internet import reactor from twisted.internet.defer import Deferred from twisted.internet.ssl import DefaultOpenSSLContextFactory -from twisted.internet.protocol import Protocol, Factory -from twisted.internet.endpoints import SSL4ClientEndpoint, TCP4ClientEndpoint, connectProtocol +from twisted.internet.protocol import Protocol, Factory, ClientFactory, ReconnectingClientFactory from twisted.words.protocols.irc import IRCClient #from twisted.python import log @@ -19,6 +18,8 @@ numbers = "0123456789" listener = None connections = {} IRCPool = {} +ReactorPool = {} +FactoryPool = {} MonitorPool = [] @@ -246,19 +247,39 @@ class IRCBot(IRCClient): nick, ident, host = self.parsen(user) helper.setWhoSingle(self.name, nick, ident, host) - def connectionLost(self, reason): - self.connected = False - self.channels = [] +class IRCBotFactory(ReconnectingClientFactory): + def __init__(self, name): + self.instance = pool[name] + self.name = name + self.maxDelay = self.instance["maxdelay"] + self.initialDelay = self.instance["initialdelay"] + self.factor = self.instance["factor"] + self.jitter = self.instance["jitter"] + + def buildProtocol(self, addr): + global IRCPool + entry = IRCBot(self.name) + IRCPool[self.name] = entry + self.client = entry + return entry + + def clientConnectionLost(self, connector, reason): + self.client.connected = False + self.client.channels = [] error = reason.getErrorMessage() log("%s: connection lost: %s" % (self.name, error)) helper.sendAll("%s: connection lost: %s" % (self.name, error)) + self.retry(connector) + #ReconnectingClientFactory.clientConnectionLost(self, connector, reason) - def connectionFailed(self, reason): - self.connected = False - self.channels = [] + def clientConnectionFailed(self, connector, reason): + self.client.connected = False + self.client.channels = [] error = reason.getErrorMessage() log("%s: connection failed: %s" % (self.name, error)) helper.sendAll("%s: connection failed: %s" % (self.name, error)) + self.retry(connector) + #ReconnectingClientFactory.clientConnectionFailed(self, connector, reason) class Base(Protocol): def __init__(self, addr): @@ -431,32 +452,37 @@ class Helper(object): log("Started bot %s to %s:%s protocol %s nickname %s" % (name, instance["host"], instance["port"], instance["protocol"], instance["nickname"])) if instance["protocol"] == "plain": if instance["bind"] == None: - point = TCP4ClientEndpoint(reactor, instance["host"], int(instance["port"]), timeout=int(instance["timeout"])) - bot = IRCBot(name) - IRCPool[name] = bot - d = connectProtocol(point, bot) + bot = IRCBotFactory(name) + rct = reactor.connectTCP(instance["host"], instance["port"], bot, timeout=int(instance["timeout"])) + + ReactorPool[name] = rct + FactoryPool[name] = bot return else: - point = TCP4ClientEndpoint(reactor, instance["host"], int(instance["port"]), timeout=int(instance["timeout"]), bindAddress=instance["bind"]) - bot = IRCBot(name) - IRCPool[name] = bot - d = connectProtocol(point, bot) + bot = IRCBotFactory(name) + rct = reactor.connectTCP(instance["host"], instance["port"], bot, timeout=int(instance["timeout"]), bindAddress=instance["bind"]) + + ReactorPool[name] = rct + FactoryPool[name] = bot return elif instance["protocol"] == "ssl": keyFN = certPath+instance["key"] certFN = certPath+instance["certificate"] contextFactory = DefaultOpenSSLContextFactory(keyFN.encode("utf-8", "replace"), certFN.encode("utf-8", "replace")) if instance["bind"] == None: - point = SSL4ClientEndpoint(reactor, instance["host"], int(instance["port"]), contextFactory, timeout=int(instance["timeout"])) - bot = IRCBot(name) - IRCPool[name] = bot - d = connectProtocol(point, bot) + bot = IRCBotFactory(name) + rct = reactor.connectSSL(instance["host"], int(instance["port"]), bot, contextFactory) + + ReactorPool[name] = rct + FactoryPool[name] = bot return else: - point = SSL4ClientEndpoint(reactor, instance["host"], int(instance["port"]), contextFactory, timeout=int(instance["timeout"]), bindAddress=instance["bind"]) - bot = IRCBot(name) - IRCPool[name] = bot - d = connectProtocol(point, bot) + + bot = IRCBotFactory(name) + rct = reactor.connectSSL(instance["host"], int(instance["port"]), bot, contextFactory, bindAddress=instance["bind"]) + + ReactorPool[name] = rct + FactoryPool[name] = bot return def addKeyword(self, keyword): @@ -637,10 +663,13 @@ class Helper(object): return pool[spl[1]]["enabled"] = False self.save("pool") - if spl[1] in IRCPool.keys(): - if IRCPool[spl[1]].connected == True: - IRCPool[spl[1]].transport.loseConnection() - del IRCPool[spl[1]] + if spl[1] in ReactorPool.keys(): + if spl[1] in FactoryPool.keys(): + FactoryPool[spl[1]].stopTrying() + ReactorPool[spl[1]].disconnect() + del IRCPool[spl[1]] + del ReactorPool[spl[1]] + del FactoryPool[spl[1]] success("Successfully disabled bot %s" % spl[1]) return else: @@ -995,9 +1024,9 @@ class Helper(object): spl[2] = None toUnset = True - if spl[1] in ["port", "timeout"]: + if spl[1] in ["port", "timeout", "maxdelay", "initialdelay", "factor", "jitter"]: try: - int(spl[2]) + spl[2] = int(spl[2]) except: failure("Value must be an integer, not %s" % spl[2]) return @@ -1066,12 +1095,7 @@ class Helper(object): if not spl[2] in pool[spl[1]].keys(): failure("No such key: %s" % spl[2]) return - if spl[2] in ["port", "timeout"]: - try: - int(spl[3]) - except: - failure("Value must be an integer, not %s" % spl[3]) - return + if spl[2] == "protocol": if not spl[3] in ["ssl", "plain"]: failure("Protocol must be ssl or plain, not %s" % spl[3]) @@ -1084,6 +1108,13 @@ class Helper(object): spl[3] = None toUnset = True + if spl[2] in ["port", "timeout", "maxdelay", "initialdelay", "factor", "jitter"]: + try: + spl[3] = int(spl[3]) + except: + failure("Value must be an integer, not %s" % spl[3]) + return + if spl[2] == "authtype": if not toUnset: if not spl[3] in ["sp", "ns"]: