3 homeserverUrl = "http://homeserver:8008";
6 name = "matrix-appservice-irc";
8 maintainers = pkgs.matrix-appservice-irc.meta.maintainers;
13 # We'll switch to this once the config is copied into place
14 specialisation.running.configuration = {
15 services.matrix-synapse = {
18 database.name = "sqlite3";
19 app_service_config_files = [ "/registration.yml" ];
21 enable_registration = true;
23 # don't use this in production, always use some form of verification
24 enable_registration_without_verification = true;
27 # The default but tls=false
34 "names" = [ "client" ];
37 "names" = [ "federation" ];
45 networking.firewall.allowedTCPPorts = [ 8008 ];
55 Info = Server Info Text
66 networking.firewall.allowedTCPPorts = [ 6667 ];
69 appservice = { pkgs, ... }: {
70 services.matrix-appservice-irc = {
72 registrationUrl = "http://appservice:8009";
75 homeserver.url = homeserverUrl;
76 homeserver.domain = "homeserver";
84 aliasTemplate = "#irc_$CHANNEL";
88 publicUrl = "http://localhost:11111/media";
95 networking.firewall.allowedTCPPorts = [ 8009 ];
98 client = { pkgs, ... }: {
99 environment.systemPackages = [
100 (pkgs.writers.writePython3Bin "do_test"
102 libraries = [ pkgs.python3Packages.matrix-nio ];
104 # We don't live in the dark ages anymore.
105 # Languages like Python that are whitespace heavy will overrun
113 from time import sleep
116 from nio import AsyncClient, RoomMessageText, JoinResponse
119 async def matrix_room_message_text_callback(matrix: AsyncClient, msg: str, _r, e):
120 print("Received matrix text message: ", e)
122 print("Received hi from IRC")
124 exit(0) # Actual exit point
129 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
130 sock.connect(("ircd", 6667))
131 sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
132 sock.send(b"USER bob bob bob :bob\n")
133 sock.send(b"NICK bob\n")
136 def join(self, room: str):
137 self.sock.send(f"JOIN {room}\n".encode())
139 def privmsg(self, room: str, msg: str):
140 self.sock.send(f"PRIVMSG {room} :{msg}\n".encode())
142 def expect_msg(self, body: str):
145 buf = self.sock.recv(1024).decode()
151 async def run(homeserver: str):
154 matrix = AsyncClient(homeserver)
155 response = await matrix.register("alice", "foobar")
156 print("Matrix register response: ", response)
158 response = await matrix.join("#irc_#test:homeserver")
159 print("Matrix join room response:", response)
160 assert isinstance(response, JoinResponse)
161 room_id = response.room_id
164 # FIXME: what are we waiting on here? Matrix? IRC? Both?
165 # 10s seem bad for busy hydra machines.
169 print("Sending text message to matrix room")
170 response = await matrix.room_send(
172 message_type="m.room.message",
173 content={"msgtype": "m.text", "body": "hi from matrix"},
175 print("Matrix room send response: ", response)
176 irc.privmsg("#test", "hi from irc")
178 print("Waiting for the matrix message to appear on the IRC side...")
179 irc.expect_msg("hi from matrix")
181 callback = functools.partial(
182 matrix_room_message_text_callback, matrix, "hi from irc"
184 matrix.add_event_callback(callback, RoomMessageText)
186 print("Waiting for matrix message...")
187 await matrix.sync_forever()
189 exit(1) # Unreachable
192 if __name__ == "__main__":
193 asyncio.run(run(sys.argv[1]))
206 ircd.wait_for_unit("ngircd.service")
207 ircd.wait_for_open_port(6667)
209 with subtest("start the appservice"):
210 appservice.wait_for_unit("matrix-appservice-irc.service")
211 appservice.wait_for_open_port(8009)
212 appservice.wait_for_file("/var/lib/matrix-appservice-irc/media-signingkey.jwk")
213 appservice.wait_for_open_port(11111)
215 with subtest("copy the registration file"):
216 appservice.copy_from_vm("/var/lib/matrix-appservice-irc/registration.yml")
217 homeserver.copy_from_host(
218 str(pathlib.Path(os.environ.get("out", os.getcwd())) / "registration.yml"), "/"
220 homeserver.succeed("chmod 444 /registration.yml")
222 with subtest("start the homeserver"):
224 "/run/current-system/specialisation/running/bin/switch-to-configuration test >&2"
227 homeserver.wait_for_unit("matrix-synapse.service")
228 homeserver.wait_for_open_port(8008)
230 with subtest("ensure messages can be exchanged"):
231 client.succeed("do_test ${homeserverUrl} >&2")