Add graceful exits
This sets up a set of ropes and pulleys that signal the `Bot.keepalive` function to clean things up after a quit signal has been sent. This allows plugins to define an `on_unload` function to save any important datas on intentional exit. Signed-off-by: Alek Ratzloff <alekratz@gmail.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
from functools import partial
|
||||||
import logging
|
import logging
|
||||||
|
import signal
|
||||||
|
|
||||||
from .config import ServerConfig
|
from .config import ServerConfig
|
||||||
from .bot import Bot
|
from .bot import Bot
|
||||||
@@ -10,15 +12,18 @@ logging.basicConfig(
|
|||||||
)
|
)
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
log.debug("Loading config")
|
log.debug("Loading config")
|
||||||
config = ServerConfig()
|
config = ServerConfig()
|
||||||
config.load("config.toml")
|
config.load("config.toml")
|
||||||
log.debug("Using configuration: %s", config)
|
log.debug("Using configuration: %s", config)
|
||||||
|
|
||||||
server = Bot(config)
|
bot = Bot(config)
|
||||||
await server.run()
|
|
||||||
|
|
||||||
|
try:
|
||||||
asyncio.run(main())
|
asyncio.run(bot.run())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
log.info("Got ctrl-c")
|
||||||
|
finally:
|
||||||
|
log.info("Quitting, press ctrl-c to quit immediately")
|
||||||
|
bot.quit()
|
||||||
|
asyncio.run(bot.keepalive())
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ class Bot:
|
|||||||
]
|
]
|
||||||
# TODO - this may not be needed
|
# TODO - this may not be needed
|
||||||
self.__channels: Set[str] = set()
|
self.__channels: Set[str] = set()
|
||||||
|
self.__quitting = asyncio.Event()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def server_config(self) -> ServerConfig:
|
def server_config(self) -> ServerConfig:
|
||||||
@@ -31,6 +32,9 @@ class Bot:
|
|||||||
def plugins(self) -> Sequence[plugin.Plugin]:
|
def plugins(self) -> Sequence[plugin.Plugin]:
|
||||||
return self.__plugins
|
return self.__plugins
|
||||||
|
|
||||||
|
def quit(self):
|
||||||
|
self.__quitting.set()
|
||||||
|
|
||||||
def channel_plugins(self, channel: str) -> Sequence[plugin.Plugin]:
|
def channel_plugins(self, channel: str) -> Sequence[plugin.Plugin]:
|
||||||
return [plugin for plugin in self.plugins if channel in plugin.channels]
|
return [plugin for plugin in self.plugins if channel in plugin.channels]
|
||||||
|
|
||||||
@@ -127,6 +131,9 @@ class Bot:
|
|||||||
|
|
||||||
async def keepalive(self):
|
async def keepalive(self):
|
||||||
# loop while we're connected, check every second
|
# loop while we're connected, check every second
|
||||||
log.info("Starting keepalive loop")
|
await self.__quitting.wait()
|
||||||
while self.connection.connected:
|
log.info("Shutting down gracefully")
|
||||||
await asyncio.sleep(1.0)
|
# TODO: unload modules
|
||||||
|
await asyncio.gather(
|
||||||
|
*[plugin.on_unload(self.connection) for plugin in self.plugins]
|
||||||
|
)
|
||||||
|
|||||||
@@ -51,6 +51,9 @@ class Plugin:
|
|||||||
async def on_message(self, conn: IrcProtocol, channel: str, who: Prefix, line: str):
|
async def on_message(self, conn: IrcProtocol, channel: str, who: Prefix, line: str):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
async def on_unload(self, conn: IrcProtocol):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def load_plugin(server_config: ServerConfig, plugin_config: PluginConfig) -> Plugin:
|
def load_plugin(server_config: ServerConfig, plugin_config: PluginConfig) -> Plugin:
|
||||||
name = plugin_config["module"]
|
name = plugin_config["module"]
|
||||||
|
|||||||
Reference in New Issue
Block a user