nixos/mautrix-meta: add new instagram mode, fix tests (#549465)

This commit is contained in:
Sandro
2026-08-10 20:36:35 +00:00
committed by GitHub
4 changed files with 69 additions and 36 deletions

View File

@@ -18,6 +18,7 @@ let
settingsFileUnsubstituted = cfg: settingsFormat.generate "mautrix-meta-config.yaml" cfg.settings;
metaName = name: "mautrix-meta-${name}";
packageName = network: if network == "instagram" then "mautrix-instagram" else "mautrix-meta";
enabledInstances = lib.filterAttrs (
name: config: config.enable
@@ -200,8 +201,10 @@ in
'';
description = ''
{file}`config.yaml` configuration as a Nix attribute set.
Configuration options should match those described in
[example-config.yaml](https://github.com/mautrix/meta/blob/main/example-config.yaml).
Configuration options should match those described in the example configuration.
Get an example configuration by executing one of those commands
- `mautrix-meta -c example.yaml --generate-example-config`
- `mautrix-instagram -c example.yaml --generate-example-config`
Secret tokens should be specified using {option}`environmentFile`
instead
@@ -471,7 +474,7 @@ in
cp '${settingsFile cfg}' '${settingsFile cfg}.tmp'
echo "Generating registration file"
mautrix-meta \
${lib.getExe' upperCfg.package (packageName cfg.settings.network.mode)} \
--generate-registration \
--config='${settingsFile cfg}.tmp' \
--registration='${cfg.registrationFile}'
@@ -568,7 +571,7 @@ in
EnvironmentFile = cfg.environmentFile;
ExecStart = lib.escapeShellArgs [
(lib.getExe upperCfg.package)
(lib.getExe' upperCfg.package (packageName cfg.settings.network.mode))
"--config=${settingsFile cfg}"
];
};

View File

@@ -90,12 +90,21 @@ in
as_token = "$AS_TOKEN";
hs_token = "$HS_TOKEN";
database = {
type = "postgres";
uri = "postgres:///mautrix-meta-instagram?host=/var/run/postgresql";
bot = {
username = botUserName;
avatar = "";
};
};
bot.username = botUserName;
database = {
type = "postgres";
uri = "postgres:///mautrix-meta-instagram?host=/var/run/postgresql";
};
encryption = {
allow = false;
default = false;
require = false;
};
bridge.permissions."@${userName}:server" = "user";
@@ -127,13 +136,14 @@ in
import functools
import asyncio
from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse
from nio import AsyncClient, RoomMessageText, RoomCreateResponse, RoomInviteResponse
async def message_callback(matrix: AsyncClient, msg: str, _r, e):
async def message_callback(matrix: AsyncClient, expected_msg: str, expected_sender: str, _r, e):
print("Received matrix text message: ", e)
assert msg in e.body
exit(0) # Success!
if getattr(e, "sender", "") == expected_sender and expected_msg in getattr(e, "body", ""):
print("Success!")
exit(0) # Success!
async def run(homeserver: str):
@@ -151,9 +161,9 @@ in
assert isinstance(response, RoomInviteResponse)
callback = functools.partial(
message_callback, matrix, "Hello, I'm an Instagram bridge bot."
message_callback, matrix, "Hello, I'm a Instagram bridge bot.", "@${botUserName}:${homeserverDomain}"
)
matrix.add_event_callback(callback, RoomMessageNotice)
matrix.add_event_callback(callback, RoomMessageText)
print("Waiting for matrix message...")
await matrix.sync_forever(timeout=30000)
@@ -171,11 +181,10 @@ in
def extract_token(data):
stdout = data[1]
stdout = stdout.strip()
line = stdout.split('\n')[-1]
return line.split(':')[-1].strip("\" '\n")
return stdout.split(':')[-1].strip("\" '\n")
def get_token_from(token, file):
data = server.execute(f"cat {file} | grep {token}")
data = server.execute(f"grep -E '^\\s*{token}:' {file}")
return extract_token(data)
def get_as_token_from(file):

View File

@@ -4,7 +4,7 @@ let
homeserverUrl = "http://server:8008";
username = "alice";
instagramBotUsername = "instagrambot";
facebookBotUsername = "facebookbot";
metaBotUsername = "metabot";
in
{
name = "mautrix-meta-sqlite";
@@ -60,7 +60,16 @@ in
appservice = {
port = 8009;
bot.username = facebookBotUsername;
bot = {
username = metaBotUsername;
avatar = "";
};
};
encryption = {
allow = false;
default = false;
require = false;
};
bridge.permissions."@${username}:server" = "user";
@@ -79,7 +88,16 @@ in
appservice = {
port = 8010;
bot.username = instagramBotUsername;
bot = {
username = instagramBotUsername;
avatar = "";
};
};
encryption = {
allow = false;
default = false;
require = false;
};
bridge.permissions."@${username}:server" = "user";
@@ -136,16 +154,17 @@ in
import functools
import asyncio
from nio import AsyncClient, RoomMessageNotice, RoomCreateResponse, RoomInviteResponse
from nio import AsyncClient, RoomMessageText, RoomCreateResponse, RoomInviteResponse
async def message_callback(matrix: AsyncClient, msg: str, _r, e):
async def message_callback(matrix: AsyncClient, expected_msg: str, expected_sender: str, _r, e):
print("Received matrix text message: ", e)
assert msg in e.body
exit(0) # Success!
if getattr(e, "sender", "") == expected_sender and expected_msg in getattr(e, "body", ""):
print("Success!")
exit(0) # Success!
async def run(username: str, bot_username: str, homeserver: str):
async def run(username: str, bot_username: str, homeserver: str, expected_msg: str):
matrix = AsyncClient(homeserver, f"@{username}:${homeserverDomain}")
response = await matrix.login("foobar")
@@ -161,16 +180,16 @@ in
assert isinstance(response, RoomInviteResponse)
callback = functools.partial(
message_callback, matrix, "Hello, I'm an Instagram bridge bot."
message_callback, matrix, expected_msg, f"@{bot_username}:${homeserverDomain}"
)
matrix.add_event_callback(callback, RoomMessageNotice)
matrix.add_event_callback(callback, RoomMessageText)
print("Waiting for matrix message...")
await matrix.sync_forever(timeout=30000)
if __name__ == "__main__":
asyncio.run(run(sys.argv[1], sys.argv[2], sys.argv[3]))
asyncio.run(run(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4]))
''
)
];
@@ -181,11 +200,10 @@ in
def extract_token(data):
stdout = data[1]
stdout = stdout.strip()
line = stdout.split('\n')[-1]
return line.split(':')[-1].strip("\" '\n")
return stdout.split(':')[-1].strip("\" '\n")
def get_token_from(token, file):
data = server.execute(f"cat {file} | grep {token}")
data = server.execute(f"grep -E '^\\s*{token}:' {file}")
return extract_token(data)
def get_as_token_from(file):
@@ -216,8 +234,8 @@ in
client.succeed("register_user ${username} ${homeserverUrl} >&2")
with subtest("ensure messages can be exchanged"):
client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2")
client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2")
client.succeed("do_test ${username} ${metaBotUsername} ${homeserverUrl} \"Hello, I'm a Facebook Messenger bridge bot.\" >&2")
client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} \"Hello, I'm a Instagram bridge bot.\" >&2")
with subtest("ensure as_token and hs_token stays same after restart"):
generated_as_token_facebook = get_as_token_from(config_yaml)
@@ -252,7 +270,7 @@ in
assert generated_hs_token_facebook == new_hs_token_facebook, f"hs_token should stay the same after restart inside the registration file (is: {new_hs_token_facebook}, was: {generated_hs_token_facebook})"
with subtest("ensure messages can be exchanged after restart"):
client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} >&2")
client.succeed("do_test ${username} ${facebookBotUsername} ${homeserverUrl} >&2")
client.succeed("do_test ${username} ${instagramBotUsername} ${homeserverUrl} \"Hello, I'm a Instagram bridge bot.\" >&2")
client.succeed("do_test ${username} ${metaBotUsername} ${homeserverUrl} \"Hello, I'm a Facebook Messenger bridge bot.\" >&2")
'';
}

View File

@@ -18,7 +18,10 @@ buildGoModule rec {
version = "26.07";
tag = "v0.2607.0";
subPackages = [ "cmd/mautrix-meta" ];
subPackages = [
"cmd/mautrix-meta"
"cmd/mautrix-instagram"
];
src = fetchFromGitHub {
owner = "mautrix";