3
0
mirror of https://github.com/jlu5/PyLink.git synced 2024-11-30 23:09:23 +01:00

More stuff for PINGing uplink and autoreconnect (#42 #59 #57)

Doesn't quite work yet; still blocks everything on disconnect for some reason...
This commit is contained in:
James Lu 2015-07-17 13:39:57 -07:00
parent 0aa2f98705
commit 9bef93c341
3 changed files with 40 additions and 8 deletions

29
main.py
View File

@ -46,13 +46,20 @@ class Irc():
# is also dependent on the protocol module. # is also dependent on the protocol module.
self.maxnicklen = 30 self.maxnicklen = 30
self.prefixmodes = 'ov' self.prefixmodes = 'ov'
# Uplink SID (filled in by protocol module)
self.uplink = None
self.serverdata = conf['servers'][netname] self.serverdata = conf['servers'][netname]
self.sid = self.serverdata["sid"] self.sid = self.serverdata["sid"]
self.botdata = conf['bot'] self.botdata = conf['bot']
self.proto = proto self.proto = proto
self.pingfreq = self.serverdata.get('pingfreq') or 10
self.pingtimeout = self.pingfreq * 2
self.connection_thread = threading.Thread(target = self.connect) self.connection_thread = threading.Thread(target = self.connect)
self.connection_thread.start() self.connection_thread.start()
self.pingTimer = None
self.lastping = time.time()
def connect(self): def connect(self):
ip = self.serverdata["ip"] ip = self.serverdata["ip"]
@ -61,9 +68,9 @@ class Irc():
try: try:
# Initial connection timeout is a lot smaller than the timeout after # Initial connection timeout is a lot smaller than the timeout after
# we've connected; this is intentional. # we've connected; this is intentional.
self.socket = socket.create_connection((ip, port), timeout=10) self.socket = socket.create_connection((ip, port), timeout=1)
self.socket.setblocking(0) self.socket.setblocking(0)
self.socket.settimeout(180) self.socket.settimeout(self.pingtimeout)
self.proto.connect(self) self.proto.connect(self)
except (socket.error, classes.ProtocolError, ConnectionError) as e: except (socket.error, classes.ProtocolError, ConnectionError) as e:
log.warning('(%s) Failed to connect to IRC: %s: %s', log.warning('(%s) Failed to connect to IRC: %s: %s',
@ -71,16 +78,19 @@ class Irc():
self.disconnect() self.disconnect()
else: else:
self.spawnMain() self.spawnMain()
self.schedulePing()
self.run() self.run()
def disconnect(self): def disconnect(self):
log.debug('(%s) Canceling pingTimer at %s due to disconnect() call', self.name, time.time())
self.connected.clear() self.connected.clear()
try: try:
self.socket.close() self.socket.close()
self.pingTimer.cancel()
except: # Socket timed out during creation; ignore except: # Socket timed out during creation; ignore
pass pass
autoconnect = self.serverdata.get('autoconnect') autoconnect = self.serverdata.get('autoconnect')
if autoconnect is not None and autoconnect >= 0: if autoconnect is not None and autoconnect >= 1110:
log.info('(%s) Going to auto-reconnect in %s seconds.', self.name, autoconnect) log.info('(%s) Going to auto-reconnect in %s seconds.', self.name, autoconnect)
time.sleep(autoconnect) time.sleep(autoconnect)
self.connect() self.connect()
@ -88,7 +98,9 @@ class Irc():
def run(self): def run(self):
buf = "" buf = ""
data = "" data = ""
while True: while (time.time() - self.lastping) < self.pingtimeout:
log.debug('(%s) time_since_last_ping: %s', self.name, (time.time() - self.lastping))
log.debug('(%s) self.pingtimeout: %s', self.name, self.pingtimeout)
try: try:
data = self.socket.recv(2048).decode("utf-8") data = self.socket.recv(2048).decode("utf-8")
buf += data buf += data
@ -115,7 +127,14 @@ class Irc():
except (socket.error, classes.ProtocolError, ConnectionError) as e: except (socket.error, classes.ProtocolError, ConnectionError) as e:
log.warning('(%s) Disconnected from IRC: %s: %s', log.warning('(%s) Disconnected from IRC: %s: %s',
self.name, type(e).__name__, str(e)) self.name, type(e).__name__, str(e))
self.disconnect() raise ProtocolError
def schedulePing(self):
self.proto.pingServer(self)
self.pingTimer = threading.Timer(self.pingfreq, self.schedulePing)
self.pingTimer.daemon = True
self.pingTimer.start()
log.debug('(%s) Ping scheduled at %s', self.name, time.time())
def spawnMain(self): def spawnMain(self):
nick = self.botdata.get('nick') or 'PyLink' nick = self.botdata.get('nick') or 'PyLink'

View File

@ -69,8 +69,10 @@ def loadDB():
", creating a new one in memory...", dbname) ", creating a new one in memory...", dbname)
db = {} db = {}
def exportDB(scheduler): def exportDB():
scheduler.enter(30, 1, exportDB, argument=(scheduler,)) scheduler = utils.schedulers.get('relaydb')
if scheduler:
scheduler.enter(30, 1, exportDB)
log.debug("Relay: exporting links database to %s", dbname) log.debug("Relay: exporting links database to %s", dbname)
with open(dbname, 'wb') as f: with open(dbname, 'wb') as f:
pickle.dump(db, f, protocol=4) pickle.dump(db, f, protocol=4)
@ -683,7 +685,7 @@ def initializeAll(irc):
def main(): def main():
loadDB() loadDB()
utils.schedulers['relaydb'] = scheduler = sched.scheduler() utils.schedulers['relaydb'] = scheduler = sched.scheduler()
scheduler.enter(30, 1, exportDB, argument=(scheduler,)) scheduler.enter(30, 1, exportDB)
# Thread this because exportDB() queues itself as part of its # Thread this because exportDB() queues itself as part of its
# execution, in order to get a repeating loop. # execution, in order to get a repeating loop.
thread = threading.Thread(target=scheduler.run) thread = threading.Thread(target=scheduler.run)

View File

@ -286,6 +286,12 @@ def updateClient(irc, numeric, field, text):
else: else:
raise ValueError("Changing field %r of a client is unsupported by this protocol." % field) raise ValueError("Changing field %r of a client is unsupported by this protocol." % field)
def pingServer(irc, source=None, target=None):
source = source or irc.sid
target = target or irc.uplink
if not (target is None or source is None):
_send(irc, source, 'PING %s %s' % (source, target))
def connect(irc): def connect(irc):
irc.start_ts = ts = int(time.time()) irc.start_ts = ts = int(time.time())
irc.uidgen = {} irc.uidgen = {}
@ -307,6 +313,10 @@ def handle_ping(irc, source, command, args):
if utils.isInternalServer(irc, args[1]): if utils.isInternalServer(irc, args[1]):
_send(irc, args[1], 'PONG %s %s' % (args[1], source)) _send(irc, args[1], 'PONG %s %s' % (args[1], source))
def handle_pong(irc, source, command, args):
if source == irc.uplink and args[1] == irc.sid:
irc.lastping = time.time()
def handle_privmsg(irc, source, command, args): def handle_privmsg(irc, source, command, args):
return {'target': args[0], 'text': args[1]} return {'target': args[0], 'text': args[1]}
@ -490,6 +500,7 @@ def handle_events(irc, data):
# Check if recvpass is correct # Check if recvpass is correct
raise ProtocolError('Error: recvpass from uplink server %s does not match configuration!' % servername) raise ProtocolError('Error: recvpass from uplink server %s does not match configuration!' % servername)
irc.servers[numeric] = IrcServer(None, servername) irc.servers[numeric] = IrcServer(None, servername)
irc.uplink = numeric
return return
elif args[0] == 'CAPAB': elif args[0] == 'CAPAB':
# Capability negotiation with our uplink # Capability negotiation with our uplink