From aa2511baaa7f28314b8720191b8f3e4d7778de68 Mon Sep 17 00:00:00 2001 From: jesopo Date: Thu, 17 Oct 2019 16:53:48 +0100 Subject: [PATCH] add IRCBot.stop() - use it for !shutdown and './bitbotctl stop' --- bitbotctl | 9 ++++----- src/Control.py | 3 +++ src/IRCBot.py | 31 +++++++++++++++++++++++++------ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/bitbotctl b/bitbotctl index a66ddd73..2753d92d 100755 --- a/bitbotctl +++ b/bitbotctl @@ -20,10 +20,11 @@ def _die(s): sys.stderr.write("%s\n" % s) sys.exit(1) +SIMPLE = ["rehash", "reload", "stop"] if args.command == "log": arg_parser.add_argument("--level", "-l", help="Log level", default="INFO") -elif args.command in ["rehash", "reload"]: +elif args.command in SIMPLE: pass else: _die("Unknown command '%s'" % args.command) @@ -52,10 +53,8 @@ _send("0 version 0") if args.command == "log": _send("1 log %s" % args.level) -elif args.command == "rehash": - _send("1 rehash") -elif args.command == "reload": - _send("1 reload") +elif args.command in SIMPLE: + _send("1 %s" % args.command) read_buffer = b"" diff --git a/src/Control.py b/src/Control.py index 57f48ea4..cabea9f2 100644 --- a/src/Control.py +++ b/src/Control.py @@ -102,6 +102,9 @@ class Control(PollSource.PollSource): result = self._bot.try_reload_modules() response_data = result.message keepalive = False + elif command == "stop": + self._bot.stop() + keepalive = False self._send_action(client, response_action, response_data, id) if not keepalive: diff --git a/src/IRCBot.py b/src/IRCBot.py index da13a739..504dfdc0 100644 --- a/src/IRCBot.py +++ b/src/IRCBot.py @@ -50,7 +50,8 @@ class Bot(object): self._timers = timers self.start_time = time.time() - self.running = False + self._writing = False + self._reading = False self.servers = {} self.reconnections = {} @@ -273,19 +274,37 @@ class Bot(object): except BitBotPanic: return def _run(self): - self.running = True + self._writing = True + self._reading = True + self._read_thread = self._daemon_thread( lambda: self._loop_catch("read", self._read_loop)) self._write_thread = self._daemon_thread( lambda: self._loop_catch("write", self._write_loop)) self._event_loop() + def stop(self, reason: str="Stopping"): + self._reading = False # disable read thread + self.trigger_read() + for server in self.servers.values(): + line = server.send_quit(reason) + line.events.on("send").hook(self._shutdown_hook(server)) + def _shutdown_hook(self, server): + def shutdown(e): + server.disconnect() + self.disconnect(server) + if not self.servers: + self._writing = False + return shutdown + def _kill(self): - self.running = False + self._writing = False + self._reading = False self._trigger_both() def _event_loop(self): - while self.running or not self._event_queue.empty(): + while ((self._writing or self._reading) or + not self._event_queue.empty()): try: item = self._event_queue.get(block=True, timeout=self.get_poll_timeout()) @@ -320,7 +339,7 @@ class Bot(object): self.panic("Exception on '%s' thread" % name, throw=False) def _write_loop(self): - while self.running: + while self._writing: poll_sources = {} with self._write_condition: fds = [] @@ -364,7 +383,7 @@ class Bot(object): def _read_loop(self): poll_sources = {} - while self.running: + while self._reading: new_poll_sources = {} for poll_source in self._poll_sources: for fileno in poll_source.get_readables():