Skip to content

Commit 168214a

Browse files
authored
Merge pull request CloudBotIRC#109 from linuxdaemon/gonzobot+connect-errors
Handle errors on connect and attempt to reconnect
2 parents 134c97e + ac14f05 commit 168214a

4 files changed

Lines changed: 56 additions & 6 deletions

File tree

cloudbot/bot.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ def _init_routine(self):
221221
self.observer.start()
222222

223223
# Connect to servers
224-
yield from asyncio.gather(*[conn.connect() for conn in self.connections.values()], loop=self.loop)
224+
yield from asyncio.gather(*[conn.try_connect() for conn in self.connections.values()], loop=self.loop)
225225

226226
# Activate web interface.
227227
if self.config.get("web", {}).get("enabled", False) and web_installed:

cloudbot/client.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import asyncio
22
import collections
33
import logging
4+
import random
45

56
from cloudbot.permissions import PermissionManager
67

@@ -59,7 +60,20 @@ def describe_server(self):
5960
raise NotImplementedError
6061

6162
@asyncio.coroutine
62-
def connect(self):
63+
def try_connect(self):
64+
timeout = 30
65+
while True:
66+
try:
67+
yield from self.connect(timeout)
68+
except Exception:
69+
logger.exception("[%s] Error occurred while connecting.")
70+
else:
71+
break
72+
73+
yield from asyncio.sleep(random.randrange(timeout))
74+
75+
@asyncio.coroutine
76+
def connect(self, timeout=None):
6377
"""
6478
Connects to the server, or reconnects if already connected.
6579
"""

cloudbot/clients/irc.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import asyncio
22
import logging
3+
import random
34
import re
45
import ssl
56
from _ssl import PROTOCOL_SSLv23
@@ -106,7 +107,20 @@ def describe_server(self):
106107
return "{}:{}".format(self.server, self.port)
107108

108109
@asyncio.coroutine
109-
def connect(self):
110+
def try_connect(self):
111+
timeout = self.config["connection"].get("timeout", 30)
112+
while True:
113+
try:
114+
yield from self.connect(timeout)
115+
except (asyncio.TimeoutError, OSError):
116+
logger.exception("[%s] Error occurred while connecting", self.name)
117+
else:
118+
break
119+
120+
yield from asyncio.sleep(random.randrange(timeout))
121+
122+
@asyncio.coroutine
123+
def connect(self, timeout=None):
110124
"""
111125
Connects to the IRC server, or reconnects if already connected.
112126
"""
@@ -125,8 +139,15 @@ def connect(self):
125139
optional_params = {}
126140
if self.local_bind:
127141
optional_params["local_addr"] = self.local_bind
128-
self._transport, self._protocol = yield from self.loop.create_connection(
129-
lambda: _IrcProtocol(self), host=self.server, port=self.port, ssl=self.ssl_context, **optional_params)
142+
143+
coro = self.loop.create_connection(
144+
lambda: _IrcProtocol(self), host=self.server, port=self.port, ssl=self.ssl_context, **optional_params
145+
)
146+
147+
if timeout is not None:
148+
coro = asyncio.wait_for(coro, timeout)
149+
150+
self._transport, self._protocol = yield from coro
130151

131152
tasks = [
132153
self.bot.plugin_manager.launch(hook, Event(bot=self.bot, conn=self, hook=hook))

plugins/core/core_misc.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ def on_join(chan, conn, nick):
3232

3333
@hook.irc_raw('324')
3434
def check_mode(irc_paramlist, conn, message):
35-
#message(", ".join(irc_paramlist), "bloodygonzo")
35+
# message(", ".join(irc_paramlist), "bloodygonzo")
3636
mode = irc_paramlist[2]
3737
require_reg = conn.config.get('require_registered_channels', False)
3838
if not "r" in mode and conn.name == "snoonet" and require_reg:
@@ -125,3 +125,18 @@ def keep_alive(conn):
125125
while True:
126126
conn.cmd('PING', conn.nick)
127127
yield from asyncio.sleep(60)
128+
129+
130+
@hook.irc_raw('433')
131+
def on_nick_in_use(conn, irc_paramlist):
132+
conn.nick = irc_paramlist[1] + '_'
133+
conn.cmd("NICK", conn.nick)
134+
135+
136+
@asyncio.coroutine
137+
@hook.irc_raw('432', singlethread=True)
138+
def on_invalid_nick(conn):
139+
nick = conn.config['nick']
140+
conn.nick = nick
141+
conn.cmd("NICK", conn.nick)
142+
yield from asyncio.sleep(30) # Just in case, we make sure to wait at least 30 seconds between sending this

0 commit comments

Comments
 (0)