src.nth.io/

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock2
-rw-r--r--Cargo.toml2
-rw-r--r--README.md45
-rw-r--r--examples/config.example.json4
-rw-r--r--examples/mattertimectl.service (renamed from examples/mattertimesync.service)8
-rw-r--r--examples/mattertimectl.timer (renamed from examples/mattertimesync.timer)0
-rw-r--r--src/config.rs14
-rw-r--r--src/controller/mod.rs4
-rw-r--r--src/main.rs4
9 files changed, 43 insertions, 40 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d402e52..3ae21ba 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -946,7 +946,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad"
[[package]]
-name = "mattertimesync"
+name = "mattertimectl"
version = "0.1.0"
dependencies = [
"anyhow",
diff --git a/Cargo.toml b/Cargo.toml
index df47edf..0f43824 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,5 @@
[package]
-name = "mattertimesync"
+name = "mattertimectl"
version = "0.1.0"
edition = "2024"
description = "CLI Matter controller that synchronizes the clocks of Matter devices via the standard Time Synchronization cluster"
diff --git a/README.md b/README.md
index 0b33e60..85492f4 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,7 @@
-# mattertimesync
+# mattertimectl
+
+> Main repository: [src.nth.io/luke/mattertimectl](https://src.nth.io/luke/mattertimectl). The
+> [GitHub mirror](https://github.com/lukehoersten/mattertimectl) is a backup.
A small CLI Matter controller that sets the clocks of Matter devices via the standard Time
Synchronization cluster. Rust implementation, built on [rs-matter](https://crates.io/crates/rs-matter)
@@ -66,21 +69,21 @@ The same principles as the TypeScript implementation this replaces, plus the Rus
Local, read-only (no device contact):
```bash
-mattertimesync status [--node <id>] [--json] # config, identity, and per-device sync state
+mattertimectl status [--node <id>] [--json] # config, identity, and per-device sync state
```
Fabric interrogation (connects to the device, reads only):
```bash
-mattertimesync inspect [--node <id>] [--json]
+mattertimectl inspect [--node <id>] [--json]
```
Fabric-writing:
```bash
-mattertimesync commission <pairing-code> # writes the device's fabric table + local storage
-mattertimesync sync [--node <id>] [--time <hh:mm>] [--json] # set clock, time zone, DST offsets
-mattertimesync decommission [--node <id>] # device(s) drop this controller's fabric
+mattertimectl commission <pairing-code> # writes the device's fabric table + local storage
+mattertimectl sync [--node <id>] [--time <hh:mm>] [--json] # set clock, time zone, DST offsets
+mattertimectl decommission [--node <id>] # device(s) drop this controller's fabric
```
No command writes local state alone; the registry and sync results change only as part of a
@@ -93,12 +96,12 @@ Exit codes: 0 success, 1 runtime failure (timer retries), 2 usage/config error.
## Configuration
-`/etc/mattertimesync/config.json` by default; override with `--config <path>`. Same file format as
+`/etc/mattertimectl/config.json` by default; override with `--config <path>`. Same file format as
the TypeScript implementation (see `examples/config.example.json`):
```json
{
- "storagePath": "/var/lib/mattertimesync",
+ "storagePath": "/var/lib/mattertimectl",
"timezone": "America/Chicago",
"logLevel": "info",
"fabricLabel": "My Home"
@@ -110,7 +113,7 @@ the TypeScript implementation (see `examples/config.example.json`):
| `storagePath` | (required) | Directory for persistent Matter fabric state. Contains secrets. |
| `timezone` | `America/Chicago` | IANA time-zone name. Never a fixed UTC offset; DST is derived. |
| `logLevel` | `info` | `debug`, `info`, `warn`, or `error`. |
-| `fabricLabel` | `Matter Time Sync` | Label other ecosystems show for this controller (max 32 chars). |
+| `fabricLabel` | `Matter Time Controller` | Label other ecosystems show for this controller (max 32 chars). |
Unknown fields are rejected loudly. Matter requires fabric labels to be unique per device and Apple
Home labels its own entry with the home's name, so use a variant like "Lakeside Time Sync" rather
@@ -119,7 +122,7 @@ than the home name itself; `sync` pushes label changes to each device.
## Build and deploy
```bash
-cargo build --release # target/release/mattertimesync, one self-contained binary
+cargo build --release # target/release/mattertimectl, one self-contained binary
cargo test
```
@@ -129,30 +132,30 @@ The binary must match the target's architecture; the simplest path is building o
```bash
# on the Pi, one-time toolchain install (user-local, ~/.rustup and ~/.cargo)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --profile minimal
-git clone <repository> && cd mattertimesync
+git clone <repository> && cd mattertimectl
~/.cargo/bin/cargo build --release
```
The target machine needs nothing but the binary (and a tzdb, present on any Linux). On the target:
```bash
-sudo install -D -m 0755 mattertimesync /opt/mattertimesync/mattertimesync
-sudo useradd --system --home /var/lib/mattertimesync --shell /usr/sbin/nologin mattertimesync
-sudo mkdir -p /etc/mattertimesync /var/lib/mattertimesync
-sudo chown mattertimesync:mattertimesync /var/lib/mattertimesync
-sudo chmod 700 /var/lib/mattertimesync
-sudo cp examples/mattertimesync.service examples/mattertimesync.timer /etc/systemd/system/
+sudo install -D -m 0755 mattertimectl /opt/mattertimectl/mattertimectl
+sudo useradd --system --home /var/lib/mattertimectl --shell /usr/sbin/nologin mattertimectl
+sudo mkdir -p /etc/mattertimectl /var/lib/mattertimectl
+sudo chown mattertimectl:mattertimectl /var/lib/mattertimectl
+sudo chmod 700 /var/lib/mattertimectl
+sudo cp examples/mattertimectl.service examples/mattertimectl.timer /etc/systemd/system/
sudo systemctl daemon-reload
```
Commission (as the service user, within the pairing window opened in the primary ecosystem):
```bash
-sudo -u mattertimesync /opt/mattertimesync/mattertimesync \
- --config /etc/mattertimesync/config.json commission 12345678901
+sudo -u mattertimectl /opt/mattertimectl/mattertimectl \
+ --config /etc/mattertimectl/config.json commission 12345678901
```
-Then `sudo systemctl enable --now mattertimesync.timer` (2 minutes after boot, hourly thereafter).
+Then `sudo systemctl enable --now mattertimectl.timer` (2 minutes after boot, hourly thereafter).
## Security notes
@@ -179,7 +182,7 @@ key, not a storage path. Migration is one re-pairing:
additional admin (Matter allows several; the fabric table has at least 5 slots). Both
implementations can sync side by side while validating.
2. Once satisfied, `decommission` with the **old** implementation so the device drops its fabric,
- point `mattertimesync.service` at this binary, and delete the old storage directory.
+ point `mattertimectl.service` at this binary, and delete the old storage directory.
## Troubleshooting
diff --git a/examples/config.example.json b/examples/config.example.json
index 831630c..5409179 100644
--- a/examples/config.example.json
+++ b/examples/config.example.json
@@ -1,6 +1,6 @@
{
- "storagePath": "/var/lib/mattertimesync",
+ "storagePath": "/var/lib/mattertimectl",
"timezone": "America/Chicago",
"logLevel": "info",
- "fabricLabel": "Rust Matter Time Sync"
+ "fabricLabel": "Rust Matter Time Controller"
}
diff --git a/examples/mattertimesync.service b/examples/mattertimectl.service
index 8fc48c1..43a662b 100644
--- a/examples/mattertimesync.service
+++ b/examples/mattertimectl.service
@@ -5,11 +5,11 @@ After=network-online.target time-sync.target
[Service]
Type=oneshot
-User=mattertimesync
-Group=mattertimesync
-ExecStart=/opt/mattertimesync/mattertimesync --config /etc/mattertimesync/config.json sync
+User=mattertimectl
+Group=mattertimectl
+ExecStart=/opt/mattertimectl/mattertimectl --config /etc/mattertimectl/config.json sync
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
-ReadWritePaths=/var/lib/mattertimesync
+ReadWritePaths=/var/lib/mattertimectl
diff --git a/examples/mattertimesync.timer b/examples/mattertimectl.timer
index 4d7b64a..4d7b64a 100644
--- a/examples/mattertimesync.timer
+++ b/examples/mattertimectl.timer
diff --git a/src/config.rs b/src/config.rs
index 3e53975..8288d4e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -1,5 +1,5 @@
//! Validated JSON configuration, file-compatible with the TypeScript
-//! implementation (`/etc/mattertimesync/config.json`, camelCase keys).
+//! implementation (`/etc/mattertimectl/config.json`, camelCase keys).
//!
//! Unknown fields are rejected loudly via serde's `deny_unknown_fields`;
//! device membership deliberately lives in controller storage, not here.
@@ -10,7 +10,7 @@ use std::path::PathBuf;
use jiff::tz::TimeZone;
use serde::Deserialize;
-pub const DEFAULT_CONFIG_PATH: &str = "/etc/mattertimesync/config.json";
+pub const DEFAULT_CONFIG_PATH: &str = "/etc/mattertimectl/config.json";
/// Matter FabricDescriptorStruct label limit.
const FABRIC_LABEL_MAX_LENGTH: usize = 32;
@@ -94,7 +94,7 @@ fn default_timezone() -> String {
}
fn default_fabric_label() -> String {
- "Matter Time Sync".into()
+ "Matter Time Controller".into()
}
impl Config {
@@ -168,18 +168,18 @@ impl Config {
mod tests {
use super::*;
- const MINIMAL: &str = r#"{ "storagePath": "/var/lib/mattertimesync" }"#;
+ const MINIMAL: &str = r#"{ "storagePath": "/var/lib/mattertimectl" }"#;
#[test]
fn minimal_config_applies_defaults() {
let config = Config::parse(MINIMAL).unwrap();
assert_eq!(
config.storage_path,
- PathBuf::from("/var/lib/mattertimesync")
+ PathBuf::from("/var/lib/mattertimectl")
);
assert_eq!(config.timezone, "America/Chicago");
assert_eq!(config.log_level, LogLevel::Info);
- assert_eq!(config.fabric_label, "Matter Time Sync");
+ assert_eq!(config.fabric_label, "Matter Time Controller");
}
#[test]
@@ -220,7 +220,7 @@ mod tests {
let config = Config::parse(r#"{ "storagePath": "/var/lib/$USER/mts" }"#).unwrap();
assert!(config.path_warnings()[0].contains("unexpanded shell variable"));
- let config = Config::parse(r#"{ "storagePath": "/var/lib/mattertimesync" }"#).unwrap();
+ let config = Config::parse(r#"{ "storagePath": "/var/lib/mattertimectl" }"#).unwrap();
assert!(config.path_warnings().is_empty());
}
diff --git a/src/controller/mod.rs b/src/controller/mod.rs
index 739615c..c712c68 100644
--- a/src/controller/mod.rs
+++ b/src/controller/mod.rs
@@ -558,7 +558,7 @@ fn lock_storage(storage: &Path) -> anyhow::Result<std::fs::File> {
let rc = unsafe { libc::flock(file.as_raw_fd(), libc::LOCK_EX | libc::LOCK_NB) };
if rc != 0 {
bail!(
- "another mattertimesync instance is already running against {}",
+ "another mattertimectl instance is already running against {}",
storage.display()
);
}
@@ -590,7 +590,7 @@ fn prepare_storage_dir(path: &Path) -> anyhow::Result<()> {
.context("chmod storage directory")?;
} else {
log::warn!(
- "storagePath {} already exists and does not look like a mattertimesync storage \
+ "storagePath {} already exists and does not look like a mattertimectl storage \
directory; leaving its permissions unchanged (it should be mode 0700, owned by the \
service user)",
path.display()
diff --git a/src/main.rs b/src/main.rs
index f372f8e..d245578 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,4 @@
-//! mattertimesync: a one-shot CLI Matter controller that sets the clocks of
+//! mattertimectl: a one-shot CLI Matter controller that sets the clocks of
//! Matter devices via the standard Time Synchronization cluster.
//!
//! # CLI invariants
@@ -54,7 +54,7 @@ use crate::time::MatterMicros;
#[derive(Parser)]
#[command(
- name = "mattertimesync",
+ name = "mattertimectl",
version,
about,
disable_help_subcommand = true