From ca94d0136f2b32da8e5ead7f9067882f0fff6b5e Mon Sep 17 00:00:00 2001 From: InspectorCaracal Date: Sun, 11 Dec 2022 15:27:02 -0700 Subject: [PATCH 1/3] remove auto-reconnecting logic --- evennia/commands/default/comms.py | 9 ++++ evennia/server/portal/discord.py | 69 +++++++++---------------------- 2 files changed, 28 insertions(+), 50 deletions(-) diff --git a/evennia/commands/default/comms.py b/evennia/commands/default/comms.py index 329211744a..32a0a40b8d 100644 --- a/evennia/commands/default/comms.py +++ b/evennia/commands/default/comms.py @@ -1925,6 +1925,7 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS): /delete - alias to remove /guild - toggle the Discord server tag on/off /channel - toggle the Evennia/Discord channel tags on/off + /start - tell the bot to start, in case it lost its connection Example: discord2chan mydiscord = 555555555555555 @@ -1943,6 +1944,7 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS): "guild", "list", "remove", + "start", ) locks = "cmd:serversetting(DISCORD_ENABLED) and pperm(Developer)" help_category = "Comms" @@ -1973,6 +1975,13 @@ class CmdDiscord2Chan(COMMAND_DEFAULT_CLASS): f"WARNING: The Discord bot's typeclass is '{discord_bot.typeclass_path}'. This does not match {settings.DISCORD_BOT_CLASS} in settings!" ) + if "start" in self.switches: + if discord_bot.sessions.all(): + self.msg("The Discord bot is already running.") + else: + discord_bot.start() + return + if "guild" in self.switches: discord_bot.db.tag_guild = not discord_bot.db.tag_guild self.msg( diff --git a/evennia/server/portal/discord.py b/evennia/server/portal/discord.py index eab9ca1a92..b49576bd08 100644 --- a/evennia/server/portal/discord.py +++ b/evennia/server/portal/discord.py @@ -84,17 +84,16 @@ def should_retry(status_code): class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.ReconnectingClientFactory): """ - A variant of the websocket-factory that auto-reconnects. + A customized websocket client factory that navigates the Discord gateway process. """ - initialDelay = 1 factor = 1.5 maxDelay = 60 noisy = False gateway = None resume_url = None - do_retry = True + is_connecting = False def __init__(self, sessionhandler, *args, **kwargs): self.uid = kwargs.get("uid") @@ -122,8 +121,8 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin d = readBody(response) d.addCallback(self.websocket_init, *args, **kwargs) return d - elif should_retry(response.code): - delay(300, self.get_gateway_url, *args, **kwargs) + else: + logger.log_warn("Discord gateway request failed.") d.addCallback(cbResponse) @@ -132,6 +131,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin callback for when the URL is gotten """ data = json.loads(str(payload, "utf-8")) + self.is_connecting = False if url := data.get("url"): self.gateway = f"{url}/?v={DISCORD_API_VERSION}&encoding=json".encode("utf-8") useragent = kwargs.pop("useragent", DISCORD_USER_AGENT) @@ -179,30 +179,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin connector (Connector): Represents the connection. """ - logger.log_info("Attempting connection to Discord...") - - def clientConnectionFailed(self, connector, reason): - """ - Called when Client failed to connect. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - protocol.ReconnectingClientFactory.clientConnectionLost(self, connector, reason) - - def clientConnectionLost(self, connector, reason): - """ - Called when Client loses connection. - - Args: - connector (Connection): Represents the connection. - reason (str): The reason for the failure. - - """ - if self.do_retry and self.bot: - self.retry(connector) + logger.log_info("Connecting to Discord...") def reconnect(self): """ @@ -210,33 +187,27 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin de-registering the session and then reattaching a new one. """ - # set the retry flag to False so it doesn't attempt an automatic retry - # and duplicate the connection - self.do_retry = False - # disconnect everything - self.bot.transport.loseConnection() - self.sessionhandler.server_disconnect(self.bot) # set up the reconnection if self.resume_url: self.url = self.resume_url elif self.gateway: self.url = self.gateway else: - # we don't know where to reconnect to! start from the beginning - self.get_gateway_url() - return - self.start() + # we don't know where to reconnect to! we'll start from the beginning + self.url = None + self.bot.sendClose() + self.sessionhandler.server_disconnect(self.bot) def start(self): "Connect protocol to remote server" if not self.gateway: - # we can't actually start yet + # we don't know where to connect to # get the gateway URL from Discord + self.is_connecting = True self.get_gateway_url() - else: - # set the retry flag so we maintain this connection - self.do_retry = True + elif not self.is_connecting: + # everything is good, connect connectWS(self) @@ -255,7 +226,6 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS): def __init__(self): WebSocketClientProtocol.__init__(self) _BASE_SESSION_CLASS.__init__(self) - self.restart_downtime = None def at_login(self): pass @@ -265,8 +235,7 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS): Called when connection is established. """ - self.restart_downtime = None - self.restart_task = None + logger.log_msg("Discord connection established.") self.factory.bot = self self.init_session("discord", "discord.gg", self.factory.sessionhandler) @@ -352,11 +321,11 @@ class DiscordClient(WebSocketClientProtocol, _BASE_SESSION_CLASS): """ if self.nextHeartbeatCall: self.nextHeartbeatCall.cancel() - self.disconnect(reason) - if code >= 4000: - logger.log_err(f"Discord connection closed: {reason}") + self.nextHeartbeatCall = None + if wasClean: + logger.log_info(f"Discord connection closed ({code}) reason: {reason}") else: - logger.log_info(f"Discord disconnected: {reason}") + logger.log_info(f"Discord connection lost.") def _send_json(self, data): """ From 8c16252a4f2200d542e482ec6d919bf44761ef54 Mon Sep 17 00:00:00 2001 From: InspectorCaracal <51038201+InspectorCaracal@users.noreply.github.com> Date: Tue, 13 Dec 2022 21:13:53 -0700 Subject: [PATCH 2/3] reset reconnecting factory's internal delay --- evennia/server/portal/discord.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/evennia/server/portal/discord.py b/evennia/server/portal/discord.py index b49576bd08..018e957a79 100644 --- a/evennia/server/portal/discord.py +++ b/evennia/server/portal/discord.py @@ -195,6 +195,9 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin else: # we don't know where to reconnect to! we'll start from the beginning self.url = None + # reset the internal delay, since this is a deliberate disconnect + self.delay = self.initialDelay + # disconnect to allow the reconnection process to kick in self.bot.sendClose() self.sessionhandler.server_disconnect(self.bot) From f37124c360ea83b7200719941b6b101fef123003 Mon Sep 17 00:00:00 2001 From: InspectorCaracal Date: Tue, 13 Dec 2022 21:16:34 -0700 Subject: [PATCH 3/3] run black --- evennia/server/portal/discord.py | 1 + 1 file changed, 1 insertion(+) diff --git a/evennia/server/portal/discord.py b/evennia/server/portal/discord.py index 018e957a79..284e126e59 100644 --- a/evennia/server/portal/discord.py +++ b/evennia/server/portal/discord.py @@ -87,6 +87,7 @@ class DiscordWebsocketServerFactory(WebSocketClientFactory, protocol.Reconnectin A customized websocket client factory that navigates the Discord gateway process. """ + initialDelay = 1 factor = 1.5 maxDelay = 60