Move things into factories and implement reconnecting

This commit is contained in:
Mark Veidemanis 2018-02-03 19:03:47 +00:00
parent cd8c61cdc6
commit 88426be62a
2 changed files with 72 additions and 38 deletions

View File

@ -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]
}

101
threshold
View File

@ -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()
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"]: