Skip to main content

max / pom

Config, dashboard, and database updates for monitoring improvements Updated monitoring configs for hetzner and astra. Dashboard and DB enhancements. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Author: Max J. <87768334+MaxJMath@users.noreply.github.com> · 2026-03-18 20:51 UTC
Commit: 20b0c7f6825ff842ffe4f6d58ad6f6971f0d8d21
Parent: 8096760
7 files changed, +56 insertions, -10 deletions
M Cargo.lock +1 -1
@@ -1665,7 +1665,7 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6"
1665 1665
1666 1666 [[package]]
1667 1667 name = "pom"
1668 - version = "0.3.0"
1668 + version = "0.3.1"
1669 1669 dependencies = [
1670 1670 "axum",
1671 1671 "chrono",
M Cargo.toml +1 -1
@@ -1,6 +1,6 @@
1 1 [package]
2 2 name = "pom"
3 - version = "0.3.0"
3 + version = "0.3.1"
4 4 edition = "2024"
5 5 license-file = "LICENSE"
6 6
@@ -1,7 +1,7 @@
1 1 [serve]
2 2 interval_secs = 300
3 3 prune_days = 30
4 - listen = "0.0.0.0:9100"
4 + listen = "100.106.221.39:9100"
5 5 peer_heartbeat_secs = 60
6 6 route_check_interval_secs = 300
7 7 dashboard = true
@@ -1,7 +1,7 @@
1 1 [serve]
2 2 interval_secs = 300
3 3 prune_days = 30
4 - listen = "0.0.0.0:9100"
4 + listen = "100.120.174.96:9100"
5 5 peer_heartbeat_secs = 60
6 6 route_check_interval_secs = 300
7 7 dashboard = false
M src/config.rs +2 -2
@@ -392,7 +392,7 @@ mod tests {
392 392 let toml = r#"
393 393 [serve]
394 394 interval_secs = 120
395 - listen = "0.0.0.0:9100"
395 + listen = "127.0.0.1:9100"
396 396 peer_heartbeat_secs = 30
397 397
398 398 [instance]
@@ -415,7 +415,7 @@ grace_count = 5
415 415
416 416 let config: Config = toml::from_str(toml).unwrap();
417 417 assert_eq!(config.serve.interval_secs, 120);
418 - assert_eq!(config.serve.listen, "0.0.0.0:9100");
418 + assert_eq!(config.serve.listen, "127.0.0.1:9100");
419 419 assert_eq!(config.serve.peer_heartbeat_secs, 30);
420 420 assert_eq!(config.instance.name.as_deref(), Some("hetzner"));
421 421 assert_eq!(config.target_names(), vec!["mnw"]);
M src/dashboard.rs +34 -2
@@ -14,9 +14,21 @@ pub async fn dashboard_handler(AxumState(state): AxumState<ApiState>) -> impl In
14 14 Html(render_dashboard(&instance_name, version, api_token, has_mesh))
15 15 }
16 16
17 - /// Escape a string for safe embedding in a JS string literal.
17 + /// Escape a string for safe embedding in a JS string literal (double-quoted).
18 18 pub(crate) fn escape_js(s: &str) -> String {
19 - s.replace('\\', "\\\\").replace('"', "\\\"")
19 + let mut out = String::with_capacity(s.len());
20 + for ch in s.chars() {
21 + match ch {
22 + '\\' => out.push_str("\\\\"),
23 + '"' => out.push_str("\\\""),
24 + '\n' => out.push_str("\\n"),
25 + '\r' => out.push_str("\\r"),
26 + '<' => out.push_str("\\x3c"),
27 + '\0' => out.push_str("\\0"),
28 + _ => out.push(ch),
29 + }
30 + }
31 + out
20 32 }
21 33
22 34 fn render_dashboard(instance_name: &str, version: &str, api_token: &str, has_mesh: bool) -> String {
@@ -436,4 +448,24 @@ mod tests {
436 448 fn escape_js_empty() {
437 449 assert_eq!(escape_js(""), "");
438 450 }
451 +
452 + #[test]
453 + fn escape_js_newline() {
454 + assert_eq!(escape_js("a\nb"), "a\\nb");
455 + }
456 +
457 + #[test]
458 + fn escape_js_carriage_return() {
459 + assert_eq!(escape_js("a\rb"), "a\\rb");
460 + }
461 +
462 + #[test]
463 + fn escape_js_script_close_tag() {
464 + assert_eq!(escape_js("</script>"), "\\x3c/script>");
465 + }
466 +
467 + #[test]
468 + fn escape_js_null() {
469 + assert_eq!(escape_js("a\0b"), "a\\0b");
470 + }
439 471 }
M src/db.rs +16 -2
@@ -239,6 +239,7 @@ async fn has_existing_tables(pool: &SqlitePool) -> Result<bool> {
239 239 }
240 240
241 241 /// Execute a single migration's SQL and record it in schema_version.
242 + /// Wrapped in an explicit transaction so partial failures roll back cleanly.
242 243 async fn run_one_migration(
243 244 pool: &SqlitePool,
244 245 version: i64,
@@ -247,15 +248,28 @@ async fn run_one_migration(
247 248 ) -> Result<()> {
248 249 info!(version, description, "running migration");
249 250
251 + let mut tx = pool.begin().await?;
252 +
250 253 // Execute each statement in the migration SQL
251 254 for statement in sql.split(';') {
252 255 let trimmed = statement.trim();
253 256 if !trimmed.is_empty() {
254 - sqlx::query(trimmed).execute(pool).await?;
257 + sqlx::query(trimmed).execute(&mut *tx).await?;
255 258 }
256 259 }
257 260
258 - stamp_version(pool, version, description).await?;
261 + // Record the version inside the same transaction
262 + let now = chrono::Utc::now().to_rfc3339();
263 + sqlx::query(
264 + "INSERT INTO schema_version (version, description, applied_at) VALUES (?, ?, ?)",
265 + )
266 + .bind(version)
267 + .bind(description)
268 + .bind(&now)
269 + .execute(&mut *tx)
270 + .await?;
271 +
272 + tx.commit().await?;
259 273 Ok(())
260 274 }
261 275