Switch MusicLink to Matrix-native config

Replace Matterbridge settings with matrix config options.

Generate TOML with proper room list commas.
This commit is contained in:
Dan 2026-01-21 23:10:53 -08:00
parent 15427dddaf
commit eb76cc5ad2
3 changed files with 115 additions and 115 deletions

View file

@ -105,9 +105,17 @@
musiclink = {
enable = true;
matterbridge = {
enable = true;
slackChannel = "music";
matrix = {
server = "http://127.0.0.1:8008";
userId = "@musiclink:clarun.xyz";
rooms = [
"!whU7Geg7JPrBL5wHcW:clarun.xyz"
"!dT40EUcemb8e6bPiig:clarun.xyz"
"!DPQveBnfuDrbgOe6dm:clarun.xyz"
];
shadow = false;
healthAddr = ":8080";
stateStorePath = "data/matrix-state.db";
};
};
};

View file

@ -103,17 +103,47 @@ in
description = "Enable MusicLink bot";
};
matterbridge = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable bundled Matterbridge";
matrix = {
server = mkOption {
type = types.str;
default = "http://127.0.0.1:${toString cfg.matrix.port}";
description = "Matrix homeserver base URL";
};
slackChannel = mkOption {
userId = mkOption {
type = types.str;
default = "music";
description = "Slack channel for MusicLink";
default = "@musiclink:${cfg.matrix.serverName}";
description = "Matrix user ID for MusicLink";
};
rooms = mkOption {
type = types.listOf types.str;
default = [];
description = "Allowlisted Matrix room IDs";
};
tokenFile = mkOption {
type = types.path;
default = "/run/secrets/musiclink-matrix-token";
description = "Path to Matrix access token file";
};
shadow = mkOption {
type = types.bool;
default = false;
description = "Shadow mode (log responses without sending)";
};
healthAddr = mkOption {
type = types.str;
default = "";
description = "Health server listen address (optional)";
};
stateStorePath = mkOption {
type = types.str;
default = "data/matrix-state.db";
description = "Path to Matrix sync state store";
};
};
};
@ -298,9 +328,14 @@ in
# MusicLink Service
services.musiclink = mkIf cfg.musiclink.enable {
enable = true;
matterbridge = {
enable = cfg.musiclink.matterbridge.enable;
slackChannel = cfg.musiclink.matterbridge.slackChannel;
matrix = {
server = cfg.musiclink.matrix.server;
userId = cfg.musiclink.matrix.userId;
rooms = cfg.musiclink.matrix.rooms;
tokenFile = cfg.musiclink.matrix.tokenFile;
shadow = cfg.musiclink.matrix.shadow;
healthAddr = cfg.musiclink.matrix.healthAddr;
stateStorePath = cfg.musiclink.matrix.stateStorePath;
};
};

View file

@ -4,18 +4,10 @@ with lib;
let
cfg = config.services.musiclink;
musiclinkPkg = musiclink; # musiclink input passed via specialArgs is the package set? No, usually it's the flake itself if not mapped.
# But in flake.nix we did: musiclink = inputs.musiclink.packages.x86_64-linux.default;
# So `musiclink` here is the package.
matterbridgePkg = pkgs.matterbridge.overrideAttrs (old: {
patches = (old.patches or []) ++ [
./patches/matterbridge-api-websocket-max-message.patch
];
});
in {
options.services.musiclink = {
enable = mkEnableOption "MusicLink bot with Matterbridge";
enable = mkEnableOption "MusicLink bot";
package = mkOption {
type = types.package;
@ -23,100 +15,52 @@ in {
description = "The MusicLink bot package";
};
matterbridge = {
enable = mkOption {
type = types.bool;
default = true;
description = "Enable bundled Matterbridge instance";
};
port = mkOption {
type = types.port;
default = 4242;
description = "Matterbridge API port";
};
slackChannel = mkOption {
matrix = {
server = mkOption {
type = types.str;
default = "music";
description = "Slack channel to bridge";
description = "Matrix homeserver base URL";
};
userId = mkOption {
type = types.str;
description = "Matrix user ID for the bot";
};
rooms = mkOption {
type = types.listOf types.str;
description = "Allowlisted Matrix room IDs";
};
tokenFile = mkOption {
type = types.path;
default = "/run/secrets/musiclink-matrix-token";
description = "Path to Matrix access token file";
};
shadow = mkOption {
type = types.bool;
default = false;
description = "Shadow mode (log responses without sending)";
};
healthAddr = mkOption {
type = types.str;
default = "";
description = "Health server listen address (optional)";
};
stateStorePath = mkOption {
type = types.str;
default = "data/matrix-state.db";
description = "Path to Matrix sync state store";
};
};
};
config = mkIf cfg.enable {
# -------------------------------------------------------------------------
# Matterbridge Service
# -------------------------------------------------------------------------
systemd.services.musiclink-matterbridge = mkIf cfg.matterbridge.enable {
description = "Matterbridge for MusicLink";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
Type = "simple";
DynamicUser = true;
StateDirectory = "musiclink-matterbridge";
WorkingDirectory = "/var/lib/musiclink-matterbridge";
# Secrets
LoadCredential = [
"musiclink-matrix-token:/run/secrets/musiclink-matrix-token"
];
ExecStartPre = pkgs.writeShellScript "generate-matterbridge-config" ''
set -euo pipefail
MATRIX_TOKEN=$(cat $CREDENTIALS_DIRECTORY/musiclink-matrix-token)
cat > /var/lib/musiclink-matterbridge/matterbridge.toml <<EOF
[api.local]
BindAddress="127.0.0.1:${toString cfg.matterbridge.port}"
Token="musiclink-internal-token"
[matrix.clarun]
Server="http://127.0.0.1:8008"
Token="$MATRIX_TOKEN"
MxID="@musiclink:clarun.xyz"
[[gateway]]
name = "musiclink-gateway"
enable = true
[[gateway.inout]]
account = "api.local"
# Read/Write for bot testing room
[[gateway.inout]]
account = "matrix.clarun"
channel = "!whU7Geg7JPrBL5wHcW:clarun.xyz"
# Additional test room
[[gateway.inout]]
account = "matrix.clarun"
channel = "!dT40EUcemb8e6bPiig:clarun.xyz"
# #music room (bridged from Slack)
[[gateway.inout]]
account = "matrix.clarun"
channel = "!DPQveBnfuDrbgOe6dm:clarun.xyz"
EOF
'';
ExecStart = "${matterbridgePkg}/bin/matterbridge -conf /var/lib/musiclink-matterbridge/matterbridge.toml -debug";
Restart = "always";
RestartSec = "10s";
};
};
# -------------------------------------------------------------------------
# MusicLink Bot Service
# -------------------------------------------------------------------------
systemd.services.musiclink = {
description = "MusicLink Bot";
after = [ "musiclink-matterbridge.service" ];
wants = [ "musiclink-matterbridge.service" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
@ -125,17 +69,30 @@ EOF
StateDirectory = "musiclink";
WorkingDirectory = "/var/lib/musiclink";
LoadCredential = [
"musiclink-matrix-token:${cfg.matrix.tokenFile}"
];
ExecStartPre = pkgs.writeShellScript "generate-musiclink-config" ''
set -euo pipefail
MATRIX_TOKEN=$(cat $CREDENTIALS_DIRECTORY/musiclink-matrix-token)
cat > /var/lib/musiclink/config.toml <<EOF
[matterbridge]
url = "ws://127.0.0.1:${toString cfg.matterbridge.port}/api/websocket"
token = "musiclink-internal-token"
gateway = "musiclink-gateway"
username = "MusicLink"
[matrix]
shadow = ${lib.boolToString cfg.matrix.shadow}
healthAddr = "${cfg.matrix.healthAddr}"
server = "${cfg.matrix.server}"
accessToken = "$MATRIX_TOKEN"
userId = "${cfg.matrix.userId}"
rooms = [
${lib.concatMapStringsSep ",\n" (room: " \"${room}\"") cfg.matrix.rooms}
]
stateStorePath = "${cfg.matrix.stateStorePath}"
EOF
'';
ExecStart = "${cfg.package}/bin/musiclink";
ExecStart = "${cfg.package}/bin/musiclink -config /var/lib/musiclink/config.toml";
Restart = "always";
RestartSec = "10s";