flake
This commit is contained in:
parent
8a76cca5fb
commit
7eb4977b99
6 changed files with 537 additions and 5 deletions
187
flake.nix
Normal file
187
flake.nix
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
{
|
||||
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;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue