mirror of
https://github.com/NixOS/nixpkgs.git
synced 2024-11-26 00:43:20 +00:00
420398889e
Posting media URLs to IRC that vanish, when they can be refetched from the remote server they were originated from is not great UX.
234 lines
7.4 KiB
Nix
234 lines
7.4 KiB
Nix
{ pkgs, ... }:
|
|
let
|
|
homeserverUrl = "http://homeserver:8008";
|
|
in
|
|
{
|
|
name = "matrix-appservice-irc";
|
|
meta = {
|
|
maintainers = pkgs.matrix-appservice-irc.meta.maintainers;
|
|
};
|
|
|
|
nodes = {
|
|
homeserver = {
|
|
# We'll switch to this once the config is copied into place
|
|
specialisation.running.configuration = {
|
|
services.matrix-synapse = {
|
|
enable = true;
|
|
settings = {
|
|
database.name = "sqlite3";
|
|
app_service_config_files = [ "/registration.yml" ];
|
|
|
|
enable_registration = true;
|
|
|
|
# don't use this in production, always use some form of verification
|
|
enable_registration_without_verification = true;
|
|
|
|
listeners = [ {
|
|
# The default but tls=false
|
|
bind_addresses = [
|
|
"0.0.0.0"
|
|
];
|
|
port = 8008;
|
|
resources = [ {
|
|
"compress" = true;
|
|
"names" = [ "client" ];
|
|
} {
|
|
"compress" = false;
|
|
"names" = [ "federation" ];
|
|
} ];
|
|
tls = false;
|
|
type = "http";
|
|
} ];
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = [ 8008 ];
|
|
};
|
|
};
|
|
|
|
ircd = {
|
|
services.ngircd = {
|
|
enable = true;
|
|
config = ''
|
|
[Global]
|
|
Name = ircd.ircd
|
|
Info = Server Info Text
|
|
AdminInfo1 = _
|
|
|
|
[Channel]
|
|
Name = #test
|
|
Topic = a cool place
|
|
|
|
[Options]
|
|
PAM = no
|
|
'';
|
|
};
|
|
networking.firewall.allowedTCPPorts = [ 6667 ];
|
|
};
|
|
|
|
appservice = { pkgs, ... }: {
|
|
services.matrix-appservice-irc = {
|
|
enable = true;
|
|
registrationUrl = "http://appservice:8009";
|
|
|
|
settings = {
|
|
homeserver.url = homeserverUrl;
|
|
homeserver.domain = "homeserver";
|
|
|
|
ircService = {
|
|
servers."ircd" = {
|
|
name = "IRCd";
|
|
port = 6667;
|
|
dynamicChannels = {
|
|
enabled = true;
|
|
aliasTemplate = "#irc_$CHANNEL";
|
|
};
|
|
};
|
|
mediaProxy = {
|
|
publicUrl = "http://localhost:11111/media";
|
|
ttl = 0;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
networking.firewall.allowedTCPPorts = [ 8009 ];
|
|
};
|
|
|
|
client = { pkgs, ... }: {
|
|
environment.systemPackages = [
|
|
(pkgs.writers.writePython3Bin "do_test"
|
|
{
|
|
libraries = [ pkgs.python3Packages.matrix-nio ];
|
|
flakeIgnore = [
|
|
# We don't live in the dark ages anymore.
|
|
# Languages like Python that are whitespace heavy will overrun
|
|
# 79 characters..
|
|
"E501"
|
|
];
|
|
} ''
|
|
import sys
|
|
import socket
|
|
import functools
|
|
from time import sleep
|
|
import asyncio
|
|
|
|
from nio import AsyncClient, RoomMessageText, JoinResponse
|
|
|
|
|
|
async def matrix_room_message_text_callback(matrix: AsyncClient, msg: str, _r, e):
|
|
print("Received matrix text message: ", e)
|
|
if msg in e.body:
|
|
print("Received hi from IRC")
|
|
await matrix.close()
|
|
exit(0) # Actual exit point
|
|
|
|
|
|
class IRC:
|
|
def __init__(self):
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.connect(("ircd", 6667))
|
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
|
sock.send(b"USER bob bob bob :bob\n")
|
|
sock.send(b"NICK bob\n")
|
|
self.sock = sock
|
|
|
|
def join(self, room: str):
|
|
self.sock.send(f"JOIN {room}\n".encode())
|
|
|
|
def privmsg(self, room: str, msg: str):
|
|
self.sock.send(f"PRIVMSG {room} :{msg}\n".encode())
|
|
|
|
def expect_msg(self, body: str):
|
|
buffer = ""
|
|
while True:
|
|
buf = self.sock.recv(1024).decode()
|
|
buffer += buf
|
|
if body in buffer:
|
|
return
|
|
|
|
|
|
async def run(homeserver: str):
|
|
irc = IRC()
|
|
|
|
matrix = AsyncClient(homeserver)
|
|
response = await matrix.register("alice", "foobar")
|
|
print("Matrix register response: ", response)
|
|
|
|
response = await matrix.join("#irc_#test:homeserver")
|
|
print("Matrix join room response:", response)
|
|
assert isinstance(response, JoinResponse)
|
|
room_id = response.room_id
|
|
|
|
irc.join("#test")
|
|
# FIXME: what are we waiting on here? Matrix? IRC? Both?
|
|
# 10s seem bad for busy hydra machines.
|
|
sleep(10)
|
|
|
|
# Exchange messages
|
|
print("Sending text message to matrix room")
|
|
response = await matrix.room_send(
|
|
room_id=room_id,
|
|
message_type="m.room.message",
|
|
content={"msgtype": "m.text", "body": "hi from matrix"},
|
|
)
|
|
print("Matrix room send response: ", response)
|
|
irc.privmsg("#test", "hi from irc")
|
|
|
|
print("Waiting for the matrix message to appear on the IRC side...")
|
|
irc.expect_msg("hi from matrix")
|
|
|
|
callback = functools.partial(
|
|
matrix_room_message_text_callback, matrix, "hi from irc"
|
|
)
|
|
matrix.add_event_callback(callback, RoomMessageText)
|
|
|
|
print("Waiting for matrix message...")
|
|
await matrix.sync_forever()
|
|
|
|
exit(1) # Unreachable
|
|
|
|
|
|
if __name__ == "__main__":
|
|
asyncio.run(run(sys.argv[1]))
|
|
''
|
|
)
|
|
];
|
|
};
|
|
};
|
|
|
|
testScript = ''
|
|
import pathlib
|
|
import os
|
|
|
|
start_all()
|
|
|
|
ircd.wait_for_unit("ngircd.service")
|
|
ircd.wait_for_open_port(6667)
|
|
|
|
with subtest("start the appservice"):
|
|
appservice.wait_for_unit("matrix-appservice-irc.service")
|
|
appservice.wait_for_open_port(8009)
|
|
appservice.wait_for_file("/var/lib/matrix-appservice-irc/media-signingkey.jwk")
|
|
appservice.wait_for_open_port(11111)
|
|
|
|
with subtest("copy the registration file"):
|
|
appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
|
|
homeserver.copy_from_host(
|
|
str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
|
|
)
|
|
homeserver.succeed("chmod 444 /registration.yml")
|
|
|
|
with subtest("start the homeserver"):
|
|
homeserver.succeed(
|
|
"/run/current-system/specialisation/running/bin/switch-to-configuration test >&2"
|
|
)
|
|
|
|
homeserver.wait_for_unit("matrix-synapse.service")
|
|
homeserver.wait_for_open_port(8008)
|
|
|
|
with subtest("ensure messages can be exchanged"):
|
|
client.succeed("do_test ${homeserverUrl} >&2")
|
|
'';
|
|
}
|