From 2343364eac519bcb7eeab923b56da5bd060a3e00 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 15:09:18 +0100 Subject: [PATCH 01/15] packages/ircbot: initial commit --- packages/servers/ircbot/LICENSE | 19 ++ packages/servers/ircbot/README | 4 + packages/servers/ircbot/justirc.py | 325 +++++++++++++++++++++++++++++ 3 files changed, 348 insertions(+) create mode 100644 packages/servers/ircbot/LICENSE create mode 100644 packages/servers/ircbot/README create mode 100644 packages/servers/ircbot/justirc.py diff --git a/packages/servers/ircbot/LICENSE b/packages/servers/ircbot/LICENSE new file mode 100644 index 0000000..2b0bd4a --- /dev/null +++ b/packages/servers/ircbot/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2022 Tiago Carvalho + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/servers/ircbot/README b/packages/servers/ircbot/README new file mode 100644 index 0000000..fe0e6b1 --- /dev/null +++ b/packages/servers/ircbot/README @@ -0,0 +1,4 @@ +private-void-bot +================ + +IRC bot for the Private Void IRC network. diff --git a/packages/servers/ircbot/justirc.py b/packages/servers/ircbot/justirc.py new file mode 100644 index 0000000..46233bd --- /dev/null +++ b/packages/servers/ircbot/justirc.py @@ -0,0 +1,325 @@ +# Copyright (c) 2015 Gökberk Yaltıraklı +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + + +import socket + +from collections import defaultdict +from collections import namedtuple + + +_IRCPacket = namedtuple("IRCPacket", "prefix command arguments") + + +def _parse_irc_packet(packet): + prefix = "" + command = "" + arguments = [] + + if packet.startswith(":"): + prefix = packet[1:].split(" ")[0] + packet = packet.split(" ", 1)[1] + + if " " in packet: + if " :" in packet: + last_argument = packet.split(" :")[1] + packet = packet.split(" :")[0] + for splitted in packet.split(" "): + if not command: + command = splitted + else: + arguments.append(splitted) + arguments.append(last_argument) + else: + for splitted in packet.split(" "): + if not command: + command = splitted + else: + arguments.append(splitted) + else: + command = packet + + return _IRCPacket(prefix, command, arguments) + + +_IRCPacket.parse = _parse_irc_packet + + +class EventEmitter: + def __init__(self): + self.handlers = defaultdict(lambda: []) + + def add_listener(self, name, handler): + self.handlers[name].append(handler) + + def remove_listener(self, name, handler): + self.handlers[name].remove(handler) + + def emit(self, name, data=None): + """Emit an event + + This function emits an event to all listeners registered to it. + + Parameters + ---------- + name : str + Event name. Case sensitive. + data + Event data. Can be any type and passed directly to the event + handlers. + + """ + for handler in list(self.handlers[name]): + handler(data) + + def on(self, name): + """ + Decorate a function as an event handler. + + Parameters + ---------- + name : str + The event name to handle + """ + + def inner(func): + self.add_listener(name, func) + return func + + return inner + + +# Event data types +_IRCEvent = namedtuple("IRCEvent", "bot") +_PacketEvent = namedtuple("PacketEvent", "bot packet") +_MessageEvent = namedtuple("MessageEvent", "bot channel sender message") +_JoinEvent = namedtuple("JoinEvent", "bot channel nick") +_PartEvent = namedtuple("PartEvent", "bot channel nick") + + +class IRCConnection(EventEmitter): + def __init__(self): + """Create an IRC connection + + After creating the object and adding all the event handlers, you need to + call .connect on it to actually connect to a server. + + """ + super().__init__() + self.socket = None + + self.nick = "" + + def run_once(self): + """Run one iteration of the IRC client. + + This function is called in a loop by the run_loop function. It can be + called separately, but most of the time there is no need to do this. + + """ + + line = next(self.lines) + packet = _IRCPacket.parse(line) + sender = packet.prefix.split("!")[0] + + ev = _PacketEvent(self, packet) + self.emit("packet", ev) + self.emit(f"packet_{packet.command}", ev) + + if packet.command == "PRIVMSG": + channel = packet.arguments[0] + message = packet.arguments[1] + ev = _MessageEvent(self, channel, sender, message) + self.emit("message", ev) + self.emit(f"message_{channel}", ev) + self.emit(f"message_{sender}", ev) + + if channel[0] == "#": + self.emit("message#", ev) + else: + self.emit("pm", ev) + elif packet.command == "PING": + # Handle a PING message + self.send_line("PONG :{}".format(packet.arguments[0])) + self.emit("ping", _IRCEvent(self)) + elif packet.command == "433" or packet.command == "437": + # Command 433 is "Nick in use" + # Add underscore to the nick + + self.set_nick("{}_".format(self.nick)) + elif packet.command == "001": + self.emit("welcome", _IRCEvent(self)) + elif packet.command == "JOIN": + ev = _JoinEvent(self, packet.arguments[0], sender) + self.emit("join", ev) + elif packet.command == "PART": + ev = _PartEvent(self, packet.arguments[0], sender) + self.emit("part", ev) + + def run_loop(self): + """Runs the main loop of the client + + This function is usually called after you add all the callbacks and + connect to the server. It will block until the connection to the server + is broken. + + """ + while True: + self.run_once() + + def _read_lines(self): + buff = "" + while True: + buff += self.socket.recv(1024).decode("utf-8", "replace") + while "\n" in buff: + line, buff = buff.split("\n", 1) + line = line.replace("\r", "") + yield line + + def connect(self, server, port=6667, tls=False): + """Connects to the IRC server + + Parameters + ---------- + server : str + The server IP or domain to connect to + port : int + The server port to connect to + tls : bool + Enable the use of TLS + + """ + + self.socket = socket.create_connection((server, port)) + + if tls: + import ssl + + context = ssl.SSLContext() + self.socket = context.wrap_socket(self.socket, server) + + self.lines = self._read_lines() + self.emit("connect", _IRCEvent(self)) + + def send_line(self, line): + """Sends a line directly to the server. + + This is a low-level function that can be used to implement functionality + that's not covered by this library. Almost all of the time, you should + have no need to use this function. + + Parameters + ---------- + line : str + The line to send to the server + + """ + self.socket.send(f"{line}\r\n".encode("utf-8")) + + def send_message(self, to, message): + """Sends a message to a user or a channel + + This is the main method of interaction as an IRC bot or client. This + function results in a PRIVMSG packet to the server. + + Parameters + ---------- + to : str + The target of the message + message : str + The message content + + """ + self.send_line(f"PRIVMSG {to} :{message}") + + def send_notice(self, to, message): + """Send a notice message + + Notice messages usually have special formatting on clients. + + Parameters + ---------- + to : str + The target of the message + message : str + The message content + + """ + self.send_line(f"NOTICE {to} :{message}") + + def send_action_message(self, to, action): + """Send an action message to a channel or user. + + Action messages can have special formatting on clients and are usually + send like /me is happy + + Parameters + ---------- + to : str + The target of the message. Can be a channel or a user. + action : str + The message content + + """ + self.send_message(to, f"\x01ACTION {action}\x01") + + def join_channel(self, channel): + """Join a channel + + This function joins a given channel. After the channel is joined, the + "join" event is emitted with your nick. + + Parameters + ---------- + channel : str + The channel to join + + """ + self.send_line(f"JOIN {channel}") + + def set_nick(self, nick): + """Sets or changes your nick + + This should be called before joining channels, but can be called at any + time afterwards. If the requested nick is not available, the library + will keep adding underscores until an available nick is found. + + Parameters + ---------- + nick : str + The nickname to use + + """ + self.nick = nick + self.send_line(f"NICK {nick}") + + def send_user_packet(self, username): + """Send a user packet + + This should be sent after your nickname. It is displayed on the clients + when they view your details and look at "Real Name". + + Parameters + ---------- + username : str + The name to set + + """ + self.send_line(f"USER {username} 0 * :{username}") -- 2.47.0 From 9c0917027b42ff2296549d75a495f9bca2e808ce Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 15:50:47 +0100 Subject: [PATCH 02/15] packages/ircbot: git ignore --- packages/servers/ircbot/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/servers/ircbot/.gitignore diff --git a/packages/servers/ircbot/.gitignore b/packages/servers/ircbot/.gitignore new file mode 100644 index 0000000..225fc6f --- /dev/null +++ b/packages/servers/ircbot/.gitignore @@ -0,0 +1 @@ +/__pycache__ -- 2.47.0 From a1d2ed677c19a7d6bce6471d1491cfbf29d3ecc1 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 15:51:01 +0100 Subject: [PATCH 03/15] packages/ircbot: mod justirc --- packages/servers/ircbot/justirc.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/servers/ircbot/justirc.py b/packages/servers/ircbot/justirc.py index 46233bd..1c1e6db 100644 --- a/packages/servers/ircbot/justirc.py +++ b/packages/servers/ircbot/justirc.py @@ -212,8 +212,12 @@ class IRCConnection(EventEmitter): if tls: import ssl - context = ssl.SSLContext() - self.socket = context.wrap_socket(self.socket, server) + context = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT) + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + context.minimum_version = ssl.TLSVersion.TLSv1_3 + context.maximum_version = ssl.TLSVersion.TLSv1_3 + self.socket = context.wrap_socket(self.socket) self.lines = self._read_lines() self.emit("connect", _IRCEvent(self)) -- 2.47.0 From 9c8abab1e31245a083627a55dbd289daf0b4292a Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 15:51:13 +0100 Subject: [PATCH 04/15] packages/ircbot: add bot code --- packages/servers/ircbot/main.py | 37 +++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 packages/servers/ircbot/main.py diff --git a/packages/servers/ircbot/main.py b/packages/servers/ircbot/main.py new file mode 100644 index 0000000..e294a98 --- /dev/null +++ b/packages/servers/ircbot/main.py @@ -0,0 +1,37 @@ +import justirc + +NICK = 'smith' + +def main(): + bot = justirc.IRCConnection() + + @bot.on('packet') + def new_packet(e): + print(e.packet) + + @bot.on('connected') + def reload_plugins(e): + print('bot has connected') + + @bot.on('connect') + def connect(e): + bot.send_line(f'NICK {NICK}') + bot.send_line(f'USER {NICK} 8 * {NICK}') + bot.emit('connected') + + @bot.on('welcome') + def welcome(e): + bot.join_channel("#general") + + @bot.on('message') + def message(e): + message = e.message.lower() + if message == '.fistbump': + message = f'vroooooooooooo fiiiist, {e.sender} :vvvv)))' + bot.send_message(e.channel, message) + + bot.connect('irc.privatevoid.net', port=6697, tls=True) + bot.run_loop() + +if __name__ == '__main__': + main() -- 2.47.0 From 5e787f49cef95d169c36d3e27f077cbe71aac6a4 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 15:56:08 +0100 Subject: [PATCH 05/15] packages/ircbot: a bit of refactoring --- packages/servers/ircbot/main.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/packages/servers/ircbot/main.py b/packages/servers/ircbot/main.py index e294a98..87479bb 100644 --- a/packages/servers/ircbot/main.py +++ b/packages/servers/ircbot/main.py @@ -1,23 +1,21 @@ import justirc -NICK = 'smith' - def main(): + config = dict(nick='smith', debug=False) + run_bot(config) + +def run_bot(c): bot = justirc.IRCConnection() - @bot.on('packet') - def new_packet(e): - print(e.packet) - - @bot.on('connected') - def reload_plugins(e): - print('bot has connected') + if c['debug']: + @bot.on('packet') + def new_packet(e): + print(e.packet) @bot.on('connect') def connect(e): - bot.send_line(f'NICK {NICK}') - bot.send_line(f'USER {NICK} 8 * {NICK}') - bot.emit('connected') + bot.send_line(f'NICK {c["nick"]}') + bot.send_line(f'USER {c["nick"]} 8 * {c["nick"]}') @bot.on('welcome') def welcome(e): -- 2.47.0 From dff97b97a52cb2633c194ea2c1c41216bc7beed5 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 21:04:35 +0100 Subject: [PATCH 06/15] packages/ircbot: organize code in hooks --- packages/servers/ircbot/hooks/.gitignore | 1 + packages/servers/ircbot/hooks/fistbump.py | 7 +++ packages/servers/ircbot/hooks/quit.py | 7 +++ packages/servers/ircbot/hooks/reload.py | 7 +++ packages/servers/ircbot/main.py | 63 ++++++++++++++++++++--- 5 files changed, 78 insertions(+), 7 deletions(-) create mode 100644 packages/servers/ircbot/hooks/.gitignore create mode 100644 packages/servers/ircbot/hooks/fistbump.py create mode 100644 packages/servers/ircbot/hooks/quit.py create mode 100644 packages/servers/ircbot/hooks/reload.py diff --git a/packages/servers/ircbot/hooks/.gitignore b/packages/servers/ircbot/hooks/.gitignore new file mode 100644 index 0000000..225fc6f --- /dev/null +++ b/packages/servers/ircbot/hooks/.gitignore @@ -0,0 +1 @@ +/__pycache__ diff --git a/packages/servers/ircbot/hooks/fistbump.py b/packages/servers/ircbot/hooks/fistbump.py new file mode 100644 index 0000000..33cea53 --- /dev/null +++ b/packages/servers/ircbot/hooks/fistbump.py @@ -0,0 +1,7 @@ +import main + +class EventHandler(main.EventHandler): + def on_message(bot, e): + if e.message == '.fistbump': + msg = f'vroooooooooooo fiiiist, {e.sender}! :^)' + bot.send_message(e.channel, msg) diff --git a/packages/servers/ircbot/hooks/quit.py b/packages/servers/ircbot/hooks/quit.py new file mode 100644 index 0000000..cc5bd53 --- /dev/null +++ b/packages/servers/ircbot/hooks/quit.py @@ -0,0 +1,7 @@ +import main + +class EventHandler(main.EventHandler): + def on_message(bot, e): + if e.message == '.quit': + bot.send_message(e.channel, 'exiting...') + bot.emit('quit') diff --git a/packages/servers/ircbot/hooks/reload.py b/packages/servers/ircbot/hooks/reload.py new file mode 100644 index 0000000..604337d --- /dev/null +++ b/packages/servers/ircbot/hooks/reload.py @@ -0,0 +1,7 @@ +import main + +class EventHandler(main.EventHandler): + def on_message(bot, e): + if e.message == '.reload': + bot.send_message(e.channel, 'reloading hooks...') + bot.emit('reload-hooks') diff --git a/packages/servers/ircbot/main.py b/packages/servers/ircbot/main.py index 87479bb..f86ca8c 100644 --- a/packages/servers/ircbot/main.py +++ b/packages/servers/ircbot/main.py @@ -1,34 +1,83 @@ +import os +import sys import justirc +import importlib + +class EventHandler(object): + def on_message(bot, event): + ... + + def on_reload(bot): + ... def main(): - config = dict(nick='smith', debug=False) + config = dict( + debug=False, + nick='smith', + channel='#general', + server='irc.privatevoid.net', + port=6697, + tls=True, + ) run_bot(config) +def shutdown_bot_hooks(bot): + for name, hook in bot.hooks: + try: + hook.EventHandler.on_reload(bot) + except Exception as e: + print(f'exception running hook {name}: {e}') + def run_bot(c): bot = justirc.IRCConnection() + bot.db = () # TODO: store a database handle here + bot.hooks = [] # storage for all bot hooks + if c['debug']: @bot.on('packet') def new_packet(e): print(e.packet) + @bot.on('reload-hooks') + def reload_hooks(e): + shutdown_bot_hooks(bot) + bot.hooks.clear() + + for path in filter(lambda h: h[-3:] == '.py', os.listdir('hooks')): + name = '.'.join(['hooks', path.split('.py')[0]]) + if name in sys.modules.keys(): + del sys.modules[name] + try: + mod = importlib.import_module(name, package=name) + bot.hooks.append((name, mod)) + except Exception as e: + print(f'failed to load hook {name}: {e}') + + @bot.on('quit') + def quit(e): + shutdown_bot_hooks(bot) + exit(0) + @bot.on('connect') def connect(e): bot.send_line(f'NICK {c["nick"]}') bot.send_line(f'USER {c["nick"]} 8 * {c["nick"]}') + bot.emit('reload-hooks') @bot.on('welcome') def welcome(e): - bot.join_channel("#general") + bot.join_channel(c['channel']) @bot.on('message') def message(e): - message = e.message.lower() - if message == '.fistbump': - message = f'vroooooooooooo fiiiist, {e.sender} :vvvv)))' - bot.send_message(e.channel, message) + for name, hook in bot.hooks: + try: + hook.EventHandler.on_message(bot, e) + except Exception as e: + print(f'exception running hook {name}: {e}') - bot.connect('irc.privatevoid.net', port=6697, tls=True) + bot.connect(c['server'], port=c['port'], tls=c['tls']) bot.run_loop() if __name__ == '__main__': -- 2.47.0 From d54bcec082c9d8179bb041eeb3dbaa9a4f84b993 Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 21:30:10 +0100 Subject: [PATCH 07/15] packages/ircbot: dice roll --- packages/servers/ircbot/hooks/roll.py | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 packages/servers/ircbot/hooks/roll.py diff --git a/packages/servers/ircbot/hooks/roll.py b/packages/servers/ircbot/hooks/roll.py new file mode 100644 index 0000000..2850f09 --- /dev/null +++ b/packages/servers/ircbot/hooks/roll.py @@ -0,0 +1,8 @@ +import main +import random + +class EventHandler(main.EventHandler): + def on_message(bot, e): + if e.message == '.roll': + msg = f'{e.sender}: rolled a {random.randint(1, 6)}' + bot.send_message(e.channel, msg) -- 2.47.0 From 24c2712e71dcbafaedf5ba405dd965002d15013d Mon Sep 17 00:00:00 2001 From: Tiago Carvalho Date: Sat, 24 Sep 2022 23:45:30 +0100 Subject: [PATCH 08/15] packages/ircbot: meme --- packages/servers/ircbot/main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/servers/ircbot/main.py b/packages/servers/ircbot/main.py index f86ca8c..83965f5 100644 --- a/packages/servers/ircbot/main.py +++ b/packages/servers/ircbot/main.py @@ -45,7 +45,7 @@ def run_bot(c): bot.hooks.clear() for path in filter(lambda h: h[-3:] == '.py', os.listdir('hooks')): - name = '.'.join(['hooks', path.split('.py')[0]]) + name = '.'.join(['hooks', path[:-3]]) if name in sys.modules.keys(): del sys.modules[name] try: -- 2.47.0 From 049f2f669a29654be1f6f6188c5afd5cc614bb4d Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 16:37:24 +0200 Subject: [PATCH 09/15] inputs: add nix-filter --- flake.nix | 2 ++ 1 file changed, 2 insertions(+) diff --git a/flake.nix b/flake.nix index dc210b4..ab1cc39 100644 --- a/flake.nix +++ b/flake.nix @@ -166,6 +166,8 @@ url = "github:hercules-ci/flake-parts"; inputs.nixpkgs.follows = "nixpkgs"; }; + + nix-filter.url = "github:numtide/nix-filter"; repin-flake-compat = { url = "github:edolstra/flake-compat"; -- 2.47.0 From cbf4a3b256195a6eead39028c5fdb8edc019b0ff Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 16:37:28 +0200 Subject: [PATCH 10/15] flake.lock: Update MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Added input 'nix-filter': 'github:numtide/nix-filter/3b821578685d661a10b563cba30b1861eec05748' (2022-08-22) --- flake.lock | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/flake.lock b/flake.lock index f3f8f9d..4a4edba 100644 --- a/flake.lock +++ b/flake.lock @@ -396,6 +396,21 @@ "type": "github" } }, + "nix-filter": { + "locked": { + "lastModified": 1661201956, + "narHash": "sha256-RizGJH/buaw9A2+fiBf9WnXYw4LZABB5kMAZIEE5/T8=", + "owner": "numtide", + "repo": "nix-filter", + "rev": "3b821578685d661a10b563cba30b1861eec05748", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "nix-filter", + "type": "github" + } + }, "nix-super": { "inputs": { "lowdown-src": "lowdown-src", @@ -559,6 +574,7 @@ "hercules-ci-effects": "hercules-ci-effects", "mms": "mms", "nar-serve": "nar-serve", + "nix-filter": "nix-filter", "nix-super": "nix-super", "nixpkgs": "nixpkgs", "repin-flake-compat": "repin-flake-compat", -- 2.47.0 From 253fd2f2f0391f680f62ca08953f2b37a2355e13 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 17:49:59 +0200 Subject: [PATCH 11/15] packages/ircbot: build --- packages/projects.nix | 1 + packages/servers/ircbot/project.nix | 32 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) create mode 100644 packages/servers/ircbot/project.nix diff --git a/packages/projects.nix b/packages/projects.nix index 22dd73b..c4a782a 100644 --- a/packages/projects.nix +++ b/packages/projects.nix @@ -27,6 +27,7 @@ ./modules/devshell.nix ./build-support + ./servers/ircbot/project.nix ./websites/landing/project.nix ./websites/stop-using-nix-env/project.nix ]; diff --git a/packages/servers/ircbot/project.nix b/packages/servers/ircbot/project.nix new file mode 100644 index 0000000..e9240ba --- /dev/null +++ b/packages/servers/ircbot/project.nix @@ -0,0 +1,32 @@ +{ inputs, pkgs, ... }: + +let + python = pkgs.python3; +in +{ + packages.ircbot = with pkgs; stdenvNoCC.mkDerivation { + pname = "ircbot"; + version = "0.0.0"; + + src = with inputs.nix-filter.lib; filter { + root = ./.; + include = [ + (matchExt "py") + (inDirectory "hooks") + ]; + }; + installPhase = '' + mkdir -p $out/bin $out/lib + + cp -r $src/ $out/lib/ircbot + + cat <$out/bin/ircbot + #!${runtimeShell} + export PYTHONNOUSERSITE=true + export PYTHONPATH="$out/lib/ircbot" + exec ${python.interpreter} $out/lib/ircbot/main.py "$@" + EOF + chmod +x $out/bin/ircbot + ''; + }; +} -- 2.47.0 From 95ee759f754a30870bb3c8e3ca4433ad4035650a Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 18:50:14 +0200 Subject: [PATCH 12/15] packages/ircbot: add devShell --- packages/servers/ircbot/.envrc | 2 ++ packages/servers/ircbot/project.nix | 42 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 packages/servers/ircbot/.envrc diff --git a/packages/servers/ircbot/.envrc b/packages/servers/ircbot/.envrc new file mode 100644 index 0000000..5d84e98 --- /dev/null +++ b/packages/servers/ircbot/.envrc @@ -0,0 +1,2 @@ +source ../../build-support/activate-shell +nix_direnv_watch_file project.nix diff --git a/packages/servers/ircbot/project.nix b/packages/servers/ircbot/project.nix index e9240ba..333a134 100644 --- a/packages/servers/ircbot/project.nix +++ b/packages/servers/ircbot/project.nix @@ -2,8 +2,50 @@ let python = pkgs.python3; + procfile = pkgs.writeText "Procfile" '' + ircd: ${pkgs.ngircd}/bin/ngircd --config ${ircdConfig} --nodaemon + ''; + + ircdConfig = pkgs.writeText "ngircd.conf" '' + [Global] + Name = ircbot-dev.local + Info = IRC Bot Development + Network = IRCBotDev + Listen = 127.0.0.1 + Ports = 6668 + + [Options] + Ident = no + PAM = no + AllowedChannelTypes = # + OperCanUseMode = yes + OperChanPAutoOp = yes + + [Channel] + Name = #general + Topic = General discussions + + [Operator] + Name = op + Password = op + ''; in { + projectShells.ircbot = { + commands = { + irssi-dev = { + help = "Irssi for development"; + command = "exec ${pkgs.irssi}/bin/irssi --config=$PRJ_DATA_DIR/irssi-config --home=$PRJ_DATA_DIR/irssi-home -c 127.0.0.1 -p 6668 \"$@\""; + }; + svc = { + help = "goreman with development services"; + command = "exec ${pkgs.goreman}/bin/goreman -f ${procfile} -set-ports=false \"$@\""; + }; + }; + tools = [ + python + ]; + }; packages.ircbot = with pkgs; stdenvNoCC.mkDerivation { pname = "ircbot"; version = "0.0.0"; -- 2.47.0 From 6982def2c7aa3613a7ffcf70c0c37c22abd2f941 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 18:50:53 +0200 Subject: [PATCH 13/15] gitignore: add .data --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 72071ea..06d79aa 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ result result-* **/.direnv/ +.data/ \ No newline at end of file -- 2.47.0 From 7a6f7b5cc0297999ee8af080f1908553d306b37d Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 19:28:08 +0200 Subject: [PATCH 14/15] packages/ircbot: implement basic overridable config --- packages/servers/ircbot/main.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/servers/ircbot/main.py b/packages/servers/ircbot/main.py index 83965f5..8694d63 100644 --- a/packages/servers/ircbot/main.py +++ b/packages/servers/ircbot/main.py @@ -1,6 +1,7 @@ import os import sys import justirc +import json import importlib class EventHandler(object): @@ -11,7 +12,7 @@ class EventHandler(object): ... def main(): - config = dict( + default_config = dict( debug=False, nick='smith', channel='#general', @@ -19,7 +20,11 @@ def main(): port=6697, tls=True, ) - run_bot(config) + config = dict() + if (config_file := os.getenv("IRCBOT_CONFIG")) and config_file != "": + with open(config_file) as f: + config = json.load(f) + run_bot(default_config | config) def shutdown_bot_hooks(bot): for name, hook in bot.hooks: -- 2.47.0 From 43d852f11db9014ada403b6ec7f618863bab26f3 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 25 Sep 2022 19:28:19 +0200 Subject: [PATCH 15/15] packages/ircbot: add bot to devShell services --- packages/servers/ircbot/config.json | 5 +++++ packages/servers/ircbot/project.nix | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 packages/servers/ircbot/config.json diff --git a/packages/servers/ircbot/config.json b/packages/servers/ircbot/config.json new file mode 100644 index 0000000..b076ab7 --- /dev/null +++ b/packages/servers/ircbot/config.json @@ -0,0 +1,5 @@ +{ + "server": "127.0.0.1", + "port": 6668, + "tls": false +} diff --git a/packages/servers/ircbot/project.nix b/packages/servers/ircbot/project.nix index 333a134..c853ef6 100644 --- a/packages/servers/ircbot/project.nix +++ b/packages/servers/ircbot/project.nix @@ -4,6 +4,7 @@ let python = pkgs.python3; procfile = pkgs.writeText "Procfile" '' ircd: ${pkgs.ngircd}/bin/ngircd --config ${ircdConfig} --nodaemon + bot: ${python.interpreter} main.py ''; ircdConfig = pkgs.writeText "ngircd.conf" '' @@ -29,6 +30,12 @@ let Name = op Password = op ''; + + botConfig = pkgs.writeText "ircbot-config.json" (builtins.toJSON { + server = "127.0.0.1"; + port = 6668; + tls = false; + }); in { projectShells.ircbot = { @@ -45,6 +52,7 @@ in tools = [ python ]; + env.IRCBOT_CONFIG.value = botConfig; }; packages.ircbot = with pkgs; stdenvNoCC.mkDerivation { pname = "ircbot"; -- 2.47.0