diff --git a/README.md b/README.md index c26a766..083fbfd 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,7 @@ All of the configuration data is stored in a file called `config.json` that must |MAIN.DISCORD_APP_TOKEN |"" |The discord bot token the birdge will use to log into discord |MAIN.LOG_LEVEL |"INFO" |Set the log level, can be `INFO` or `DEBUG` |MAIN.MESSAGE_DELAY |1.5 |Set the delay between messages sent from discord to minecraft +|MAIN.FAILSAFE_RETRIES |3 |The amount of times to try reconnecting to an online server before giving up and exiting. |MAIN.ADMINS |\[283983554051047425\] |Array of discord user ids that have administrative access to the bot |AUTH_SERVER.BIND.IP |"" |The IPv4 address which the authentication server will bind to (set to blank for 0.0.0.0) |AUTH_SERVER.PORT |9822 |The port which the authentication server will bind to diff --git a/config.example.json b/config.example.json index df172f1..3935d46 100644 --- a/config.example.json +++ b/config.example.json @@ -8,6 +8,7 @@ "DISCORD_APP_TOKEN": "", "LOG_LEVEL": "INFO", "MESSAGE_DELAY": 1.5, + "FAILSAFE_RETRIES": 3, "ADMINS": [ 283983554051047425 ] diff --git a/minecraft_discord_bridge/config.py b/minecraft_discord_bridge/config.py index 45a7925..a118bb9 100644 --- a/minecraft_discord_bridge/config.py +++ b/minecraft_discord_bridge/config.py @@ -36,6 +36,7 @@ class Configuration(object): self.discord_token = self._config["MAIN"]["DISCORD_APP_TOKEN"] self.logging_level = self._config["MAIN"]["LOG_LEVEL"] self.message_delay = self._config["MAIN"]["MESSAGE_DELAY"] + self.failsafe_retries = self._config["MAIN"]["FAILSAFE_RETRIES"] self.admin_users = self._config["MAIN"]["ADMINS"] self.auth_ip = self._config["AUTH_SERVER"]["BIND_IP"] self.auth_port = self._config["AUTH_SERVER"]["PORT"] diff --git a/minecraft_discord_bridge/minecraft_discord_bridge.py b/minecraft_discord_bridge/minecraft_discord_bridge.py index e6c6308..d1e8fbf 100755 --- a/minecraft_discord_bridge/minecraft_discord_bridge.py +++ b/minecraft_discord_bridge/minecraft_discord_bridge.py @@ -43,6 +43,8 @@ from mcstatus import MinecraftServer from bidict import bidict from requests_futures.sessions import FuturesSession +import _thread + import minecraft_discord_bridge from .database_session import DatabaseSession from .elasticsearch_logger import ElasticsearchLogger, ConnectionReason @@ -66,6 +68,7 @@ class MinecraftDiscordBridge(): # Initialize the discord part self.discord_bot = discord.Client() self.config = Configuration("config.json") + self.connection_retries = 0 self.auth_token = None self.connection = None self.setup_logging(self.config.logging_level) @@ -494,10 +497,11 @@ class MinecraftDiscordBridge(): handle_exception=self.minecraft_handle_exception) self.register_handlers(self.connection) + self.connection_retries += 1 self.connection.connect() try: self.aioloop.run_until_complete(self.discord_bot.start(self.config.discord_token)) - except KeyboardInterrupt: + except (KeyboardInterrupt, SystemExit): # log out of discord self.aioloop.run_until_complete(self.discord_bot.logout()) # log out of minecraft @@ -638,6 +642,14 @@ class MinecraftDiscordBridge(): self.logger.info('Disconnected.') if json_data: self.logger.info("Disconnect json data: %s", json_data) + if self.connection_retries >= self.config.failsafe_retries: + self.logger.info("Failed to join the server %s times in a row. Exiting.", self.connection_retries) + self.logger.info("Use a process supervisor if you wish to automatically restart the bridge.") + # This is possibly a huge hack... Since we cannot reliably raise exceptions on this thread + # for them to be caught on the main thread, we call interrupt_main to raise a KeyboardInterrupt + # on main and tell it to shut the bridge down. + _thread.interrupt_main() + return self.previous_player_list = self.player_list.copy() self.accept_join_events = False self.player_list = bidict() @@ -649,6 +661,7 @@ class MinecraftDiscordBridge(): self.logger.info('Not reconnecting to server because it appears to be offline.') time.sleep(15) self.logger.info('Reconnecting.') + self.connection_retries += 1 self.connection.connect() def handle_disconnect_packet(self, disconnect_packet): @@ -764,6 +777,7 @@ class MinecraftDiscordBridge(): def handle_join_game(self, join_game_packet): self.logger.info('Connected and joined game as entity id %d', join_game_packet.entity_id) self.player_list = bidict() + self.connection_retries = 0 def handle_chat(self, chat_packet): json_data = json.loads(chat_packet.json_data) @@ -822,7 +836,7 @@ class MinecraftDiscordBridge(): def handle_sigterm(*args, **kwargs): - raise KeyboardInterrupt() + raise KeyboardInterrupt def main():