Rename project from system-stats-daemon to systant

- Updated all module names from SystemStatsDaemon to Systant
- Renamed application config from :system_stats_daemon to :systant
- Updated service files and documentation
- Release binary now at _build/prod/rel/systant/bin/systant

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ryan 2025-08-02 17:06:03 -07:00
parent 9d8306a64b
commit 92fc90e3b4
11 changed files with 104 additions and 45 deletions

View File

@ -1,4 +1,4 @@
# System Stats Daemon
# Systant
An Elixir application that runs as a systemd daemon to:
1. Publish system stats to MQTT every 30 seconds
@ -9,10 +9,10 @@ An Elixir application that runs as a systemd daemon to:
Edit `config/config.exs` to configure MQTT connection:
```elixir
config :system_stats_daemon, SystemStatsDaemon.MqttClient,
config :systant, Systant.MqttClient,
host: "localhost",
port: 1883,
client_id: "system_stats_daemon",
client_id: "systant",
username: nil,
password: nil,
stats_topic: "system/stats",
@ -35,24 +35,24 @@ mix run --no-halt
# Production release
MIX_ENV=prod mix release
_build/prod/rel/system_stats_daemon/bin/system_stats_daemon start
_build/prod/rel/systant/bin/systant start
```
## Systemd Installation
1. Build production release
2. Copy binary to `/usr/local/bin/`
3. Copy `system_stats_daemon.service` to `/etc/systemd/system/`
3. Copy `systant.service` to `/etc/systemd/system/`
4. Enable and start:
```bash
sudo systemctl enable system_stats_daemon
sudo systemctl start system_stats_daemon
sudo systemctl enable systant
sudo systemctl start systant
```
## Features
- Publishes "Hello world" stats every 30 seconds to `system/stats` topic
- Publishes "Hello from systant" stats every 30 seconds to `system/stats` topic
- Listens on `system/commands` topic and logs received messages
- Configurable MQTT connection settings
- Runs as systemd daemon with auto-restart

View File

@ -1,9 +1,9 @@
import Config
config :system_stats_daemon, SystemStatsDaemon.MqttClient,
config :systant, Systant.MqttClient,
host: "mqtt.home",
port: 1883,
client_id: "system_stats_daemon",
client_id: "systant",
username: "mqtt",
password: "pleasework",
stats_topic: "system/stats",

View File

@ -1,6 +1,6 @@
defmodule SystemStatsDaemon do
defmodule Systant do
@moduledoc """
Documentation for `SystemStatsDaemon`.
Documentation for `Systant`.
"""
@doc """
@ -8,7 +8,7 @@ defmodule SystemStatsDaemon do
## Examples
iex> SystemStatsDaemon.hello()
iex> Systant.hello()
:world
"""

View File

@ -1,4 +1,4 @@
defmodule SystemStatsDaemon.Application do
defmodule Systant.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false
@ -8,12 +8,12 @@ defmodule SystemStatsDaemon.Application do
@impl true
def start(_type, _args) do
children = [
{SystemStatsDaemon.MqttClient, []}
{Systant.MqttClient, []}
]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: SystemStatsDaemon.Supervisor]
opts = [strategy: :one_for_one, name: Systant.Supervisor]
Supervisor.start_link(children, opts)
end
end

View File

@ -1,4 +1,4 @@
defmodule SystemStatsDaemon.MqttClient do
defmodule Systant.MqttClient do
use GenServer
require Logger
@ -11,7 +11,7 @@ defmodule SystemStatsDaemon.MqttClient do
end
def init(_opts) do
config = Application.get_env(:system_stats_daemon, __MODULE__)
config = Application.get_env(:systant, __MODULE__)
Logger.info("Starting MQTT client with config: #{inspect(config)}")
# Use a unique client ID to avoid conflicts
@ -32,7 +32,7 @@ defmodule SystemStatsDaemon.MqttClient do
# Send immediate hello message
hello_msg = %{
message: "Hello - system_stats_daemon started",
message: "Hello - systant started",
timestamp: DateTime.utc_now() |> DateTime.to_iso8601(),
hostname: get_hostname()
}
@ -64,7 +64,7 @@ defmodule SystemStatsDaemon.MqttClient do
defp publish_stats(config, client_id) do
stats = %{
message: "Hello from system_stats_daemon",
message: "Hello from systant",
timestamp: DateTime.utc_now() |> DateTime.to_iso8601(),
hostname: get_hostname()
}

View File

@ -3,7 +3,7 @@ defmodule SystemStatsDaemon.MixProject do
def project do
[
app: :system_stats_daemon,
app: :systant,
version: "0.1.0",
elixir: "~> 1.18",
start_permanent: Mix.env() == :prod,
@ -16,7 +16,7 @@ defmodule SystemStatsDaemon.MixProject do
def application do
[
extra_applications: [:logger],
mod: {SystemStatsDaemon.Application, []}
mod: {Systant.Application, []}
]
end
@ -30,7 +30,7 @@ defmodule SystemStatsDaemon.MixProject do
defp releases do
[
system_stats_daemon: [
systant: [
include_executables_for: [:unix],
applications: [runtime_tools: :permanent]
]

View File

@ -3,15 +3,15 @@
with lib;
let
cfg = config.services.system-stats-daemon;
cfg = config.services.systant;
in
{
options.services.system-stats-daemon = {
enable = mkEnableOption "System Stats MQTT Daemon";
options.services.systant = {
enable = mkEnableOption "Systant MQTT Daemon";
package = mkOption {
type = types.package;
description = "The system-stats-daemon package to use";
description = "The systant package to use";
};
mqttHost = mkOption {
@ -58,8 +58,8 @@ in
};
config = mkIf cfg.enable {
systemd.services.system-stats-daemon = {
description = "System Stats MQTT Daemon";
systemd.services.systant = {
description = "Systant MQTT Daemon";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
@ -77,13 +77,13 @@ in
Type = "exec";
User = "root";
Group = "root";
ExecStart = "${cfg.package}/bin/system_stats_daemon start";
ExecStop = "${cfg.package}/bin/system_stats_daemon stop";
ExecStart = "${cfg.package}/bin/systant start";
ExecStop = "${cfg.package}/bin/systant stop";
Restart = "always";
RestartSec = 5;
StandardOutput = "journal";
StandardError = "journal";
SyslogIdentifier = "system_stats_daemon";
SyslogIdentifier = "systant";
WorkingDirectory = "${cfg.package}";
# Security settings

59
systant.nix Normal file
View File

@ -0,0 +1,59 @@
{ lib
, stdenv
, fetchgit
, elixir
, erlang
, rebar3
, git
}:
stdenv.mkDerivation rec {
pname = "systant";
version = "0.1.0";
src = fetchgit {
url = "https://git.ryanpandya.com/ryan/systant.git";
rev = "9d8306a64b7893ea0d25e2b08f470541fb4db7c8";
sha256 = lib.fakeSha256; # Replace with actual hash after first build attempt
};
nativeBuildInputs = [
elixir
erlang
rebar3
git
];
buildPhase = ''
runHook preBuild
export MIX_ENV=prod
export MIX_HOME=$TMPDIR/mix
export HEX_HOME=$TMPDIR/hex
export REBAR_CACHE_DIR=$TMPDIR/rebar3
mix local.hex --force
mix local.rebar --force
mix deps.get --only=prod
mix release
runHook postBuild
'';
installPhase = ''
runHook preInstall
mkdir -p $out
cp -r _build/prod/rel/systant/* $out/
runHook postInstall
'';
meta = with lib; {
description = "Systant - System stats MQTT daemon for monitoring system metrics";
homepage = "https://git.ryanpandya.com/ryan/systant";
license = licenses.mit; # Update if different
maintainers = [ ]; # Add your maintainer info if desired
platforms = platforms.linux;
};
}

View File

@ -1,19 +1,19 @@
[Unit]
Description=System Stats MQTT Daemon
Description=Systant MQTT Daemon
After=network.target
[Service]
Type=exec
User=root
Group=root
ExecStart=/opt/system_stats_daemon/bin/system_stats_daemon start
ExecStop=/opt/system_stats_daemon/bin/system_stats_daemon stop
ExecStart=/opt/systant/bin/systant start
ExecStop=/opt/systant/bin/systant stop
Restart=always
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=system_stats_daemon
WorkingDirectory=/opt/system_stats_daemon
SyslogIdentifier=systant
WorkingDirectory=/opt/systant
# Security settings - still apply restrictions where possible
NoNewPrivileges=true

8
test/systant_test.exs Normal file
View File

@ -0,0 +1,8 @@
defmodule SystantTest do
use ExUnit.Case
doctest Systant
test "greets the world" do
assert Systant.hello() == :world
end
end

View File

@ -1,8 +0,0 @@
defmodule SystemStatsDaemonTest do
use ExUnit.Case
doctest SystemStatsDaemon
test "greets the world" do
assert SystemStatsDaemon.hello() == :world
end
end