Summary Files Commits Branches @commit @diff @stats
path: root / modules / server / retro-aim-server.nix
blob: f3fce5a956c58d84e267be38e7b92a0c3bf58168 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
{ lib, config, options, pkgs, ... }: let
  cfg = config.services.retro-aim-server;
in {
  options.services.retro-aim-server = with lib; {
    enable = mkEnableOption "Enable the retro-aim-server service";

    API_HOST = mkOption {
      type = types.str;
      default = "127.0.0.1";
      example = "example.com";
      description = "Specifies the IP address or hostname that the management API binds to for incoming connections (127.0.0.1 restricts to same machine only).";
    };

    API_PORT = mkOption {
      type = types.port;
      default = 8080;
      description = "The port that the management API service binds to.";
    };

    KERBEROS_PORT = mkOption {
      type = types.port;
      default = 1088;
      description = "The port that the Kerberos server binds to.";
    };

    ALERT_PORT = mkOption {
      type = types.port;
      default = 5194;
      description = "The port that the Alert service binds to.";
    };

    AUTH_PORT = mkOption {
      type = types.port;
      default = 5190;
      description = "The port that the auth service binds to.";
    };

    BART_PORT = mkOption {
      type = types.port;
      default = 5195;
      description = "The port that the BART service binds to.";
    };

    BOS_PORT = mkOption {
      type = types.port;
      default = 5191;
      description = "The port that the BOS service binds to.";
    };

    CHAT_NAV_PORT = mkOption {
      type = types.port;
      default = 5193;
      description = "The port that the chat nav service binds to.";
    };

    CHAT_PORT = mkOption {
      type = types.port;
      default = 5192;
      description = "The port that the chat service binds to.";
    };

    ADMIN_PORT = mkOption {
      type = types.port;
      default = 5196;
      description = "The port that the admin service binds to.";
    };

    ODIR_PORT = mkOption {
      type = types.port;
      default = 5197;
      description = "The port that the ODir service binds to.";
    };

    DB_PATH = mkOption {
      type = types.str;
      default = "oscar.sqlite";
      example = "/var/lib/ras/oscar.sqlite";
      description = "The path to the SQLite database file. The file and DB schema are auto-created if they doesn't exist.";
    };

    DISABLE_AUTH = mkOption {
      type = types.bool;
      default = true;
      example = false;
      description = ''
        Disable password check and auto-create new users at login time. Useful for
        quickly creating new accounts during development without having to register
        new users via the management API.
      '';
    };

    LOG_LEVEL = mkOption {
      type = types.enum [ "trace" "debug" "info" "warn" "error" ];
      default = "info";
      example = "debug";
      description = "Set logging granularity. Possible values: 'trace', 'debug', 'info', 'warn', 'error'.";
    };

    OSCAR_HOST = mkOption {
      type = types.str;
      default = "127.0.0.1";
      example = "example.com";
      description = ''
        The hostname that AIM clients connect to in order to reach OSCAR services
        (auth, BOS, BUCP, etc). Make sure the hostname is reachable by all clients.
        For local development, the default loopback address should work provided the
        server and AIM client(s) are running on the same machine. For LAN-only
        clients, a private IP address (e.g. 192.168..) or hostname should suffice. For
        clients connecting over the Internet, specify your public IP address and
        ensure that TCP ports 5190-5197 are open on your firewall.
      '';
    };

    TOC_HOST = mkOption {
      type = types.str;
      default = "0.0.0.0";
      example = "example.com";
      description = "Specifies the IP address or hostname that the TOC service binds to for incoming connections (0.0.0.0 listens on all interfaces).";
    };

    TOC_PORT = mkOption {
      type = types.port;
      default = 9898;
      description = "The port that the TOC service binds to.";
    };

    extraConfig = mkOption {
      type = types.lines;
      default = "";
      description = "Extra server configuration, see https://github.com/mk6i/retro-aim-server/blob/main/config/settings.env for more information";
    };

    user = mkOption {
      type = types.str;
      default = "ras";
      description = "User account under which retro-aim-server service runs. If left default, user will be automatically created.";
    };

    group = mkOption {
      type = types.str;
      default = "ras";
      description = "Group account under which retro-aim-server service runs. If left default, group will be automatically created.";
    };
  };

  config = with lib; mkIf cfg.enable {
    systemd = {
      packages = [ pkgs.retro-aim-server ];
      services.retro-aim-server = {
        serviceConfig = {
          User = cfg.user;
          Group = cfg.group;
          StateDirectory = [ cfg.user ];
          WorkingDirectory = [ "/var/lib/${cfg.user}" ];
          ExecStart = "${pkgs.retro-aim-server}/bin/server -config /etc/ras/settings.env";
        };
        restartTriggers = [ config.environment.etc."ras/settings.env".source ];
        wantedBy = [ "multi-user.target" ];
      };
    };

    environment.etc."ras/settings.env".text = let
        toString = value:
          if builtins.isBool value
          then lib.boolToString value
          else builtins.toString value;
      in (lib.concatLines (
            lib.attrsets.mapAttrsToList
              (name: value:
                if lib.hasInfix "_" name
                then "export ${name}=${toString value}"
                else "")
              cfg)) + cfg.extraConfig;

    users.users = lib.optionalAttrs (cfg.user == options.services.retro-aim-server.user.default) {
      ${cfg.user} = {
        isSystemUser = true;
        group = cfg.group;
        description = "retro-aim-server management user";
      };
    };

    users.groups = lib.optionalAttrs (cfg.group == options.services.retro-aim-server.group.default) {
      "ras" = { };
    };

    networking.firewall = {
      allowedTCPPorts = builtins.filter (x: ! builtins.isNull x)
        (lib.attrsets.mapAttrsToList
          (name: value:
            if options.services.retro-aim-server.${name}.type == types.port
            then value
            else null)
          cfg);
    };
  };
}