187 lines
6.4 KiB
Nix
187 lines
6.4 KiB
Nix
{
|
|
description = "Crypto alert Telegram bot that monitors Bybit prices";
|
|
|
|
inputs = {
|
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
flake-utils.url = "github:numtide/flake-utils";
|
|
};
|
|
|
|
outputs = { self, nixpkgs, flake-utils }:
|
|
flake-utils.lib.eachDefaultSystem (system:
|
|
let
|
|
pkgs = nixpkgs.legacyPackages.${system};
|
|
in
|
|
{
|
|
packages.default = pkgs.buildGoModule {
|
|
pname = "crypto-alert-bot";
|
|
version = "0.1.0";
|
|
src = ./.;
|
|
|
|
vendorHash = "sha256-toXJCeMHa61YCFIYtsTl4dime015AF5LlB62QmYVaA8=";
|
|
|
|
subPackages = [ "cmd/app" ];
|
|
|
|
meta = with pkgs.lib; {
|
|
description = "Telegram bot for Bybit cryptocurrency price alerts";
|
|
mainProgram = "app";
|
|
};
|
|
};
|
|
|
|
devShells.default = pkgs.mkShell {
|
|
packages = with pkgs; [
|
|
go
|
|
gopls
|
|
gotools
|
|
golangci-lint
|
|
go-migrate # provides the `migrate` CLI
|
|
];
|
|
shellHook = ''
|
|
echo "crypto-alert-bot dev shell"
|
|
echo " Run: CONFIG_PATH=./internal/config/local.yml go run ./cmd/app/main.go"
|
|
'';
|
|
};
|
|
}
|
|
) // {
|
|
# NixOS module — import this in your NixOS config to run the bot as a service.
|
|
#
|
|
# The module manages PostgreSQL automatically (creates the DB and user,
|
|
# connects via Unix socket with peer auth). The only settings you must
|
|
# provide are the Telegram token file and optionally log/provider tuning.
|
|
#
|
|
# Minimal example:
|
|
# services.crypto-alert-bot = {
|
|
# enable = true;
|
|
# telegramTokenFile = "/run/secrets/telegram-token";
|
|
# };
|
|
nixosModules.default = { config, lib, pkgs, ... }:
|
|
with lib;
|
|
let
|
|
cfg = config.services.crypto-alert-bot;
|
|
svcUser = "crypto-alert-bot";
|
|
|
|
# The config YAML is fully static (no secrets); the Telegram token is
|
|
# read from a file at ExecStartPre time and written into a per-run copy.
|
|
staticConfig = pkgs.writeText "crypto-alert-bot-base.yml" ''
|
|
logger:
|
|
service_name: "${cfg.logServiceName}"
|
|
encoding: "${cfg.logEncoding}"
|
|
level: "${cfg.logLevel}"
|
|
postgresql:
|
|
address: "/run/postgresql"
|
|
user: "${svcUser}"
|
|
db_name: "${cfg.dbName}"
|
|
telegram:
|
|
token: "__TELEGRAM_TOKEN__"
|
|
providers:
|
|
bybit:
|
|
base_url: "${cfg.bybitBaseUrl}"
|
|
'';
|
|
|
|
# Runs as root (+ prefix) before the main process. Copies the static
|
|
# config into the runtime directory and splices in the Telegram token.
|
|
configSetupScript = pkgs.writeShellScript "crypto-alert-bot-setup-config" ''
|
|
set -euo pipefail
|
|
token=$(< ${lib.escapeShellArg cfg.telegramTokenFile})
|
|
install -m 600 -o ${svcUser} ${staticConfig} /run/crypto-alert-bot/config.yml
|
|
sed -i "s|__TELEGRAM_TOKEN__|$token|" /run/crypto-alert-bot/config.yml
|
|
'';
|
|
in
|
|
{
|
|
options.services.crypto-alert-bot = {
|
|
enable = mkEnableOption "crypto alert bot";
|
|
|
|
package = mkOption {
|
|
type = types.package;
|
|
default = self.packages.${pkgs.system}.default;
|
|
defaultText = literalExpression "self.packages.\${system}.default";
|
|
description = "The crypto-alert-bot package to use.";
|
|
};
|
|
|
|
dbName = mkOption {
|
|
type = types.str;
|
|
default = svcUser;
|
|
description = "PostgreSQL database name (created automatically).";
|
|
};
|
|
|
|
telegramTokenFile = mkOption {
|
|
type = types.path;
|
|
description = "Path to a file containing the Telegram bot token (e.g. managed by agenix or sops-nix).";
|
|
};
|
|
|
|
logServiceName = mkOption {
|
|
type = types.str;
|
|
default = "alert-bot";
|
|
description = "Service name printed in log lines.";
|
|
};
|
|
|
|
logEncoding = mkOption {
|
|
type = types.enum [ "console" "json" ];
|
|
default = "json";
|
|
description = "Log output encoding.";
|
|
};
|
|
|
|
logLevel = mkOption {
|
|
type = types.enum [ "debug" "info" "warn" "error" ];
|
|
default = "info";
|
|
description = "Minimum log level.";
|
|
};
|
|
|
|
bybitBaseUrl = mkOption {
|
|
type = types.str;
|
|
default = "https://api.bybit.com";
|
|
description = "Bybit REST API base URL.";
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
# Create a stable system user whose name matches the PostgreSQL role
|
|
# so that peer (Unix socket) authentication works without a password.
|
|
users.users.${svcUser} = {
|
|
isSystemUser = true;
|
|
group = svcUser;
|
|
description = "Crypto alert bot service user";
|
|
};
|
|
users.groups.${svcUser} = {};
|
|
|
|
# Provision the database and role automatically.
|
|
services.postgresql = {
|
|
enable = true;
|
|
ensureDatabases = [ cfg.dbName ];
|
|
ensureUsers = [{
|
|
name = svcUser;
|
|
ensureDBOwnership = true;
|
|
}];
|
|
};
|
|
|
|
systemd.services.crypto-alert-bot = {
|
|
description = "Crypto Alert Telegram Bot";
|
|
wantedBy = [ "multi-user.target" ];
|
|
after = [ "network.target" "postgresql.service" ];
|
|
requires = [ "postgresql.service" ];
|
|
|
|
serviceConfig = {
|
|
# '+' prefix → root, so we can write to the RuntimeDirectory
|
|
# before switching to the unprivileged service user.
|
|
ExecStartPre = "+${configSetupScript}";
|
|
ExecStart = "${cfg.package}/bin/app";
|
|
Environment = "CONFIG_PATH=/run/crypto-alert-bot/config.yml";
|
|
|
|
User = svcUser;
|
|
Group = svcUser;
|
|
|
|
RuntimeDirectory = "crypto-alert-bot";
|
|
RuntimeDirectoryMode = "0700";
|
|
|
|
Restart = "on-failure";
|
|
RestartSec = "5s";
|
|
|
|
NoNewPrivileges = true;
|
|
PrivateTmp = true;
|
|
ProtectSystem = "strict";
|
|
ProtectHome = true;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|