synops-common: delt lib for alle CLI-verktøy (oppgave 21.16)
Ny crate `tools/synops-common` samler duplisert kode som var
spredt over 13 CLI-verktøy:
- db::connect() — PG-pool fra DATABASE_URL (erstatter 10+ identiske blokker)
- cas::path() — CAS-stioppslag med to-nivå hash-katalog
- cas::root() — CAS_ROOT env med default
- cas::hash_bytes() / hash_file() / store() — SHA-256 hashing og lagring
- cas::mime_to_extension() — MIME → filendelse
- logging::init() — tracing til stderr med env-filter
- types::{NodeRow, EdgeRow, NodeSummary} — delte FromRow-structs
Alle verktøy (unntatt synops-tasks som ikke bruker DB) er refaktorert
til å bruke synops-common. Alle kompilerer og tester passerer.
This commit is contained in:
parent
d532e048b1
commit
6496434bd3
49 changed files with 17684 additions and 352 deletions
3
tasks.md
3
tasks.md
|
|
@ -262,8 +262,7 @@ kaller dem direkte. Samme verktøy, to brukere.
|
|||
### Infrastruktur
|
||||
|
||||
- [x] 21.15 Jobbkø-dispatcher: endre maskinrommets jobbkø-handlere til å spawne CLI-verktøy (`Command::new("synops-X")`) i stedet for inline-kode. Stdout → jobbresultat, stderr → feillogg, exitkode → status.
|
||||
- [~] 21.16 Felles lib: `synops-common` crate med PG-tilkobling, CAS-helpers, og node/edge-typer. Deles mellom alle CLI-verktøy for å unngå duplisering.
|
||||
> Påbegynt: 2026-03-18T10:40
|
||||
- [x] 21.16 Felles lib: `synops-common` crate med PG-tilkobling, CAS-helpers, og node/edge-typer. Deles mellom alle CLI-verktøy for å unngå duplisering.
|
||||
|
||||
## Fase 12: Herding
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@ eller maskinrommet-API. Ligger i PATH via symlink eller direkte kall.
|
|||
| `synops-feature-status` | Sjekk feature-status: spec, oppgaver, commits, feedback | Ferdig |
|
||||
| `synops-node` | Hent/vis en node med edges (UUID, --depth, --format json/md) | Ferdig |
|
||||
|
||||
## Delt bibliotek
|
||||
|
||||
| Crate | Beskrivelse |
|
||||
|-------|-------------|
|
||||
| `synops-common` | Delt lib: PG-tilkobling (`db`), CAS-helpers (`cas`), logging (`logging`), node/edge-typer (`types`) |
|
||||
|
||||
Alle CLI-verktøy (unntatt `synops-tasks`) bruker `synops-common` som dependency.
|
||||
Se `synops-common/src/lib.rs` for API-oversikt.
|
||||
|
||||
## Konvensjoner
|
||||
- Navnekonvensjon: `synops-<verb>` (f.eks. `synops-context`)
|
||||
- Shell-scripts eller Rust binaries
|
||||
|
|
|
|||
2448
tools/synops-audio/Cargo.lock
generated
Normal file
2448
tools/synops-audio/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -14,7 +14,5 @@ sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres",
|
|||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
uuid = { version = "1", features = ["v7", "serde"] }
|
||||
sha2 = "0.10"
|
||||
hex = "0.4"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use uuid::Uuid;
|
||||
|
|
@ -124,14 +123,7 @@ struct AudioProcessResult {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_audio=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_audio");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -147,7 +139,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let cas_root = std::env::var("CAS_ROOT").unwrap_or_else(|_| "/srv/synops/media/cas".into());
|
||||
let cas_root = synops_common::cas::root();
|
||||
|
||||
// 1. Parse EDL
|
||||
let edl: EdlDocument = serde_json::from_str(&cli.edl)
|
||||
|
|
@ -171,7 +163,7 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
}
|
||||
|
||||
// 3. Sjekk at kildefilen finnes i CAS
|
||||
let source_path = cas_path(&cas_root, &cli.cas_hash);
|
||||
let source_path = synops_common::cas::path(&cas_root, &cli.cas_hash);
|
||||
if !source_path.exists() {
|
||||
return Err(format!("Kildefil finnes ikke i CAS: {}", cli.cas_hash));
|
||||
}
|
||||
|
|
@ -292,14 +284,7 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
let requested_by = cli.requested_by
|
||||
.ok_or("--requested-by er påkrevd sammen med --write")?;
|
||||
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL må settes med --write".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let pnode_id = write_to_db(
|
||||
&db,
|
||||
|
|
@ -610,7 +595,7 @@ async fn resolve_silence_cuts(
|
|||
min_duration_ms,
|
||||
} = op
|
||||
{
|
||||
let source_path = cas_path(cas_root, &edl.source_hash);
|
||||
let source_path = synops_common::cas::path(cas_root, &edl.source_hash);
|
||||
let regions = detect_silence(&source_path, *threshold_db, *min_duration_ms).await?;
|
||||
for region in regions {
|
||||
// Behold 200ms stillhet på hver side for naturlig lyd,
|
||||
|
|
@ -753,21 +738,11 @@ fn build_filter_chain(
|
|||
|
||||
// ─── CAS-operasjoner ─────────────────────────────────────────────
|
||||
|
||||
/// CAS-filsti: {root}/{hash[0..2]}/{hash[2..4]}/{hash}
|
||||
fn cas_path(root: &str, hash: &str) -> PathBuf {
|
||||
PathBuf::from(root)
|
||||
.join(&hash[..2])
|
||||
.join(&hash[2..4])
|
||||
.join(hash)
|
||||
}
|
||||
|
||||
/// Beregn SHA-256, lagre i CAS med atomisk rename.
|
||||
async fn store_in_cas(cas_root: &str, data: &[u8]) -> Result<(String, u64), String> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
let hash = hex::encode(hasher.finalize());
|
||||
let hash = synops_common::cas::hash_bytes(data);
|
||||
|
||||
let dest = cas_path(cas_root, &hash);
|
||||
let dest = synops_common::cas::path(cas_root, &hash);
|
||||
|
||||
// Allerede lagret?
|
||||
if dest.exists() {
|
||||
|
|
@ -1077,7 +1052,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn cas_path_format() {
|
||||
let p = cas_path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
let p = synops_common::cas::path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
assert_eq!(
|
||||
p,
|
||||
PathBuf::from("/srv/synops/media/cas/b9/4d/b94d27b9934d3e08")
|
||||
|
|
|
|||
2280
tools/synops-common/Cargo.lock
generated
Normal file
2280
tools/synops-common/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
17
tools/synops-common/Cargo.toml
Normal file
17
tools/synops-common/Cargo.toml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
[package]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
description = "Delt bibliotek for Synops CLI-verktøy: PG-tilkobling, CAS-helpers, node/edge-typer"
|
||||
|
||||
[dependencies]
|
||||
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", "json"] }
|
||||
uuid = { version = "1", features = ["v7", "serde"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
sha2 = "0.10"
|
||||
hex = "0.4"
|
||||
tokio = { version = "1", features = ["fs"] }
|
||||
127
tools/synops-common/src/cas.rs
Normal file
127
tools/synops-common/src/cas.rs
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
//! Content-Addressable Store (CAS) utilities.
|
||||
//!
|
||||
//! CAS lagrer filer med SHA-256-hash som nøkkel, organisert i
|
||||
//! en to-nivå katalogstruktur: `{root}/{hash[0..2]}/{hash[2..4]}/{hash}`.
|
||||
//!
|
||||
//! Miljøvariabel: CAS_ROOT (default: /srv/synops/media/cas)
|
||||
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
/// Standard CAS-rotkatalog.
|
||||
pub const DEFAULT_CAS_ROOT: &str = "/srv/synops/media/cas";
|
||||
|
||||
/// Hent CAS-rotkatalog fra miljøvariabel eller bruk default.
|
||||
pub fn root() -> String {
|
||||
std::env::var("CAS_ROOT").unwrap_or_else(|_| DEFAULT_CAS_ROOT.into())
|
||||
}
|
||||
|
||||
/// Beregn filsti i CAS fra rot og hash.
|
||||
///
|
||||
/// Struktur: `{root}/{hash[0..2]}/{hash[2..4]}/{hash}`
|
||||
///
|
||||
/// # Eksempel
|
||||
/// ```
|
||||
/// use synops_common::cas;
|
||||
/// let p = cas::path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
/// assert_eq!(p.to_str().unwrap(), "/srv/synops/media/cas/b9/4d/b94d27b9934d3e08");
|
||||
/// ```
|
||||
pub fn path(root: &str, hash: &str) -> PathBuf {
|
||||
let (p1, rest) = hash.split_at(2.min(hash.len()));
|
||||
let (p2, _) = rest.split_at(2.min(rest.len()));
|
||||
PathBuf::from(root).join(p1).join(p2).join(hash)
|
||||
}
|
||||
|
||||
/// Beregn SHA-256 hash av bytes. Returnerer hex-streng.
|
||||
pub fn hash_bytes(data: &[u8]) -> String {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
hex::encode(hasher.finalize())
|
||||
}
|
||||
|
||||
/// Beregn SHA-256 hash av en fil. Returnerer hex-streng.
|
||||
pub async fn hash_file(file_path: &Path) -> Result<String, String> {
|
||||
let data = tokio::fs::read(file_path)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke lese fil {}: {e}", file_path.display()))?;
|
||||
Ok(hash_bytes(&data))
|
||||
}
|
||||
|
||||
/// Lagre bytes i CAS. Returnerer hash. Oppretter kataloger ved behov.
|
||||
pub async fn store(cas_root: &str, data: &[u8]) -> Result<String, String> {
|
||||
let hash = hash_bytes(data);
|
||||
let target = path(cas_root, &hash);
|
||||
|
||||
if target.exists() {
|
||||
return Ok(hash);
|
||||
}
|
||||
|
||||
if let Some(parent) = target.parent() {
|
||||
tokio::fs::create_dir_all(parent)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke opprette CAS-katalog: {e}"))?;
|
||||
}
|
||||
|
||||
tokio::fs::write(&target, data)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke skrive CAS-fil: {e}"))?;
|
||||
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
/// Konverter MIME-type til filendelse.
|
||||
pub fn mime_to_extension(mime: &str) -> &str {
|
||||
match mime {
|
||||
"audio/mpeg" | "audio/mp3" => "mp3",
|
||||
"audio/wav" | "audio/x-wav" => "wav",
|
||||
"audio/ogg" => "ogg",
|
||||
"audio/flac" | "audio/x-flac" => "flac",
|
||||
"audio/mp4" | "audio/m4a" | "audio/x-m4a" => "m4a",
|
||||
"audio/webm" => "webm",
|
||||
"video/mp4" => "mp4",
|
||||
"video/webm" => "webm",
|
||||
"image/jpeg" => "jpg",
|
||||
"image/png" => "png",
|
||||
"image/webp" => "webp",
|
||||
"image/gif" => "gif",
|
||||
"text/html" => "html",
|
||||
"application/pdf" => "pdf",
|
||||
_ => "bin",
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn cas_path_format() {
|
||||
let p = path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
assert_eq!(
|
||||
p,
|
||||
PathBuf::from("/srv/synops/media/cas/b9/4d/b94d27b9934d3e08")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cas_path_short_hash() {
|
||||
let p = path("/cas", "ab");
|
||||
assert_eq!(p, PathBuf::from("/cas/ab//ab"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn hash_known_value() {
|
||||
let hash = hash_bytes(b"hello world");
|
||||
assert_eq!(
|
||||
hash,
|
||||
"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mime_mapping() {
|
||||
assert_eq!(mime_to_extension("audio/mpeg"), "mp3");
|
||||
assert_eq!(mime_to_extension("image/png"), "png");
|
||||
assert_eq!(mime_to_extension("unknown/type"), "bin");
|
||||
}
|
||||
}
|
||||
33
tools/synops-common/src/db.rs
Normal file
33
tools/synops-common/src/db.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
//! PostgreSQL-tilkobling via DATABASE_URL.
|
||||
//!
|
||||
//! Standardisert oppkobling brukt av alle CLI-verktøy.
|
||||
//! Leser DATABASE_URL fra miljøvariabel, oppretter en pool med
|
||||
//! et lite antall connections (CLI-verktøy trenger sjelden mer enn 2).
|
||||
|
||||
use sqlx::postgres::{PgPool, PgPoolOptions};
|
||||
|
||||
/// Opprett en PostgreSQL-pool fra DATABASE_URL miljøvariabel.
|
||||
///
|
||||
/// Returnerer feil hvis DATABASE_URL ikke er satt eller tilkobling feiler.
|
||||
pub async fn connect() -> Result<PgPool, String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))
|
||||
}
|
||||
|
||||
/// Opprett en PostgreSQL-pool med egendefinert maks connections.
|
||||
pub async fn connect_with(max_connections: u32) -> Result<PgPool, String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
PgPoolOptions::new()
|
||||
.max_connections(max_connections)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))
|
||||
}
|
||||
14
tools/synops-common/src/lib.rs
Normal file
14
tools/synops-common/src/lib.rs
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
//! synops-common — Delt bibliotek for Synops CLI-verktøy.
|
||||
//!
|
||||
//! Samler funksjonalitet som deles mellom alle CLI-verktøy:
|
||||
//! - `db` — PostgreSQL-tilkobling via DATABASE_URL
|
||||
//! - `cas` — Content-addressable store (sti-oppslag, hashing, MIME)
|
||||
//! - `logging` — Standardisert tracing-oppsett (stderr, env-filter)
|
||||
//! - `types` — Node- og edge-typer fra databaseskjemaet
|
||||
//!
|
||||
//! Ref: docs/retninger/unix_filosofi.md, tools/README.md
|
||||
|
||||
pub mod cas;
|
||||
pub mod db;
|
||||
pub mod logging;
|
||||
pub mod types;
|
||||
23
tools/synops-common/src/logging.rs
Normal file
23
tools/synops-common/src/logging.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
//! Standardisert tracing-oppsett for CLI-verktøy.
|
||||
//!
|
||||
//! Alle CLI-verktøy logger til stderr med env-filter.
|
||||
//! RUST_LOG styrer nivå; uten den brukes `{crate_name}=info`.
|
||||
|
||||
/// Initialiser tracing med standard oppsett for et CLI-verktøy.
|
||||
///
|
||||
/// - Output til stderr (stdout er reservert for verktøyets resultat)
|
||||
/// - Env-filter fra RUST_LOG, fallback til `{crate_filter}=info`
|
||||
/// - Uten target-prefix (kortere linjer)
|
||||
///
|
||||
/// `crate_filter` bør være crate-navnet med bindestreker erstattet
|
||||
/// med understreker, f.eks. `"synops_audio"`.
|
||||
pub fn init(crate_filter: &str) {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| format!("{crate_filter}=info").parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
}
|
||||
51
tools/synops-common/src/types.rs
Normal file
51
tools/synops-common/src/types.rs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
//! Node- og edge-typer fra databaseskjemaet.
|
||||
//!
|
||||
//! Disse typene speiler SQL-skjemaet i `docs/primitiver/nodes.md` og
|
||||
//! `docs/primitiver/edges.md`. De er ment som delte FromRow-structs
|
||||
//! for de vanligste spørringene.
|
||||
//!
|
||||
//! node_kind og edge_type er freeform-strenger — ikke enums — fordi
|
||||
//! listen vokser organisk. Se docs for kjente verdier.
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use uuid::Uuid;
|
||||
|
||||
/// En rad fra `nodes`-tabellen.
|
||||
///
|
||||
/// Bruk med `sqlx::query_as::<_, NodeRow>(...)`. Husk å caste
|
||||
/// enums i SQL: `node_kind::text`, `visibility::text`.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct NodeRow {
|
||||
pub id: Uuid,
|
||||
pub node_kind: String,
|
||||
pub title: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub visibility: String,
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub created_by: Option<Uuid>,
|
||||
}
|
||||
|
||||
/// En rad fra `edges`-tabellen.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct EdgeRow {
|
||||
pub id: Uuid,
|
||||
pub source_id: Uuid,
|
||||
pub target_id: Uuid,
|
||||
pub edge_type: String,
|
||||
pub metadata: Option<serde_json::Value>,
|
||||
pub system: bool,
|
||||
pub created_at: DateTime<Utc>,
|
||||
pub created_by: Option<Uuid>,
|
||||
}
|
||||
|
||||
/// Forenklet node for listevisning og søkeresultater.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, sqlx::FromRow)]
|
||||
pub struct NodeSummary {
|
||||
pub id: Uuid,
|
||||
pub node_kind: String,
|
||||
pub title: Option<String>,
|
||||
pub visibility: String,
|
||||
pub created_at: DateTime<Utc>,
|
||||
}
|
||||
2449
tools/synops-context/Cargo.lock
generated
Normal file
2449
tools/synops-context/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -8,6 +8,7 @@ name = "synops-context"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
synops-common = { path = "../synops-common" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", "json"] }
|
||||
|
|
@ -16,4 +17,3 @@ serde_json = "1"
|
|||
uuid = { version = "1", features = ["v7", "serde"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
|
|
|||
|
|
@ -76,14 +76,7 @@ struct RelatedNodeRow {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_context=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_context");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -94,14 +87,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let comm_id = cli.communication_id;
|
||||
|
||||
|
|
|
|||
2461
tools/synops-feature-status/Cargo.lock
generated
Normal file
2461
tools/synops-feature-status/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -8,6 +8,7 @@ name = "synops-feature-status"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
synops-common = { path = "../synops-common" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", "json"] }
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ struct Cli {
|
|||
}
|
||||
|
||||
fn main() {
|
||||
synops_common::logging::init("synops_feature_status");
|
||||
let cli = Cli::parse();
|
||||
let repo = PathBuf::from(&cli.repo);
|
||||
|
||||
|
|
@ -430,48 +431,31 @@ fn parse_commit_lines(
|
|||
// --- Feedback fra database ---
|
||||
|
||||
fn run_feedback(key: &str) {
|
||||
let db_url = match resolve_database_url() {
|
||||
Some(url) => url,
|
||||
None => {
|
||||
println!("## Feedback\n");
|
||||
println!("_(DATABASE_URL ikke satt — feedback hoppes over)_\n");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(print_feedback(&db_url, key));
|
||||
}
|
||||
|
||||
fn resolve_database_url() -> Option<String> {
|
||||
if let Ok(url) = std::env::var("DATABASE_URL") {
|
||||
return Some(url);
|
||||
}
|
||||
|
||||
// Prøv maskinrommet.env
|
||||
if let Ok(content) = std::fs::read_to_string("/tmp/maskinrommet.env") {
|
||||
for line in content.lines() {
|
||||
if let Some(val) = line.strip_prefix("DATABASE_URL=") {
|
||||
return Some(val.to_string());
|
||||
// Sikre at DATABASE_URL er satt — prøv maskinrommet.env som fallback
|
||||
if std::env::var("DATABASE_URL").is_err() {
|
||||
if let Ok(content) = std::fs::read_to_string("/tmp/maskinrommet.env") {
|
||||
for line in content.lines() {
|
||||
if let Some(val) = line.strip_prefix("DATABASE_URL=") {
|
||||
// SAFETY: kalles tidlig i main, før noen tråder er startet.
|
||||
unsafe { std::env::set_var("DATABASE_URL", val); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||
rt.block_on(print_feedback(key));
|
||||
}
|
||||
|
||||
async fn print_feedback(db_url: &str, key: &str) {
|
||||
async fn print_feedback(key: &str) {
|
||||
println!("## Feedback\n");
|
||||
|
||||
let db = match sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(db_url)
|
||||
.await
|
||||
{
|
||||
let db = match synops_common::db::connect().await {
|
||||
Ok(pool) => pool,
|
||||
Err(e) => {
|
||||
eprintln!("Kunne ikke koble til database: {e}");
|
||||
println!("_(Databasefeil — feedback hoppes over)_\n");
|
||||
eprintln!("{e}");
|
||||
println!("_(DATABASE_URL ikke satt eller databasefeil — feedback hoppes over)_\n");
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
2450
tools/synops-node/Cargo.lock
generated
Normal file
2450
tools/synops-node/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,3 +17,4 @@ uuid = { version = "1", features = ["v7", "serde"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -117,14 +117,7 @@ struct FullOutput {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_node=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_node");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -135,14 +128,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
// Hent hovednoden
|
||||
let root_node = fetch_node(&db, cli.node_id).await?
|
||||
|
|
|
|||
17
tools/synops-prune/Cargo.lock
generated
17
tools/synops-prune/Cargo.lock
generated
|
|
@ -1605,6 +1605,22 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-prune"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1614,6 +1630,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ uuid = { version = "1", features = ["v7", "serde"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -457,14 +457,7 @@ async fn phase_critical(
|
|||
async fn main() {
|
||||
let cli = Cli::parse();
|
||||
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_prune");
|
||||
|
||||
let dry_run = cli.is_dry_run();
|
||||
|
||||
|
|
@ -476,14 +469,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli, dry_run: bool) -> Result<(), String> {
|
||||
let database_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&database_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
// Sjekk at CAS-katalogen eksisterer
|
||||
if !cli.cas_root.exists() {
|
||||
|
|
|
|||
19
tools/synops-render/Cargo.lock
generated
19
tools/synops-render/Cargo.lock
generated
|
|
@ -1839,16 +1839,31 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-render"
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-render"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tera",
|
||||
"tokio",
|
||||
"tracing",
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@ serde_json = "1"
|
|||
uuid = { version = "1", features = ["v7", "serde"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tera = "1"
|
||||
sha2 = "0.10"
|
||||
hex = "0.4"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@
|
|||
use chrono::{DateTime, Utc};
|
||||
use clap::Parser;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use tera::{Context, Tera};
|
||||
|
|
@ -375,18 +374,10 @@ mod tiptap;
|
|||
// CAS-lagring
|
||||
// =============================================================================
|
||||
|
||||
fn cas_path(root: &str, hash: &str) -> PathBuf {
|
||||
let (p1, rest) = hash.split_at(2.min(hash.len()));
|
||||
let (p2, _) = rest.split_at(2.min(rest.len()));
|
||||
PathBuf::from(root).join(p1).join(p2).join(hash)
|
||||
}
|
||||
|
||||
async fn store_in_cas(root: &str, data: &[u8]) -> Result<(String, u64, bool), String> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
let hash = hex::encode(hasher.finalize());
|
||||
let hash = synops_common::cas::hash_bytes(data);
|
||||
let size = data.len() as u64;
|
||||
let path = cas_path(root, &hash);
|
||||
let path = synops_common::cas::path(root, &hash);
|
||||
|
||||
if path.exists() {
|
||||
return Ok((hash, size, true));
|
||||
|
|
@ -971,14 +962,7 @@ async fn log_resource_usage(db: &sqlx::PgPool, node_id: Uuid, bytes: u64, operat
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_render");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -989,26 +973,12 @@ async fn main() {
|
|||
}
|
||||
|
||||
// Koble til database
|
||||
let db_url = std::env::var("DATABASE_URL").unwrap_or_else(|_| {
|
||||
if cli.write {
|
||||
eprintln!("DATABASE_URL er påkrevd med --write");
|
||||
process::exit(1);
|
||||
}
|
||||
// Uten --write trenger vi fortsatt DB for oppslag
|
||||
eprintln!("DATABASE_URL mangler — påkrevd for databaseoppslag");
|
||||
let db = synops_common::db::connect().await.unwrap_or_else(|e| {
|
||||
eprintln!("{e}");
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("Kunne ikke koble til database: {e}");
|
||||
process::exit(1);
|
||||
});
|
||||
|
||||
let cas_root = std::env::var("CAS_ROOT").unwrap_or_else(|_| "/srv/synops/media/cas".into());
|
||||
let cas_root = synops_common::cas::root();
|
||||
|
||||
let result = match cli.render_type.as_str() {
|
||||
"article" => {
|
||||
|
|
@ -1112,7 +1082,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_cas_path() {
|
||||
let path = cas_path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
let path = synops_common::cas::path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
assert!(path.to_string_lossy().contains("/b9/4d/"));
|
||||
}
|
||||
|
||||
|
|
|
|||
2450
tools/synops-respond/Cargo.lock
generated
Normal file
2450
tools/synops-respond/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,3 +17,4 @@ uuid = { version = "1", features = ["v7", "serde"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -71,14 +71,7 @@ struct ParticipantRow {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_respond=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_respond");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -89,14 +82,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let communication_id = cli.communication_id;
|
||||
let agent_node_id = cli.agent_node_id;
|
||||
|
|
|
|||
17
tools/synops-rss/Cargo.lock
generated
17
tools/synops-rss/Cargo.lock
generated
|
|
@ -1605,6 +1605,22 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-rss"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1614,6 +1630,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
|||
|
|
@ -17,3 +17,4 @@ uuid = { version = "1", features = ["v7", "serde"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -89,14 +89,7 @@ struct FeedItem {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_rss");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -105,19 +98,7 @@ async fn main() {
|
|||
process::exit(1);
|
||||
}
|
||||
|
||||
let db_url = match std::env::var("DATABASE_URL") {
|
||||
Ok(url) => url,
|
||||
Err(_) => {
|
||||
eprintln!("Feil: DATABASE_URL er ikke satt");
|
||||
process::exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
let db = match sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
{
|
||||
let db = match synops_common::db::connect().await {
|
||||
Ok(pool) => pool,
|
||||
Err(e) => {
|
||||
eprintln!("Feil: Kunne ikke koble til database: {e}");
|
||||
|
|
|
|||
2450
tools/synops-search/Cargo.lock
generated
Normal file
2450
tools/synops-search/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -17,3 +17,4 @@ uuid = { version = "1", features = ["v7", "serde"] }
|
|||
chrono = { version = "0.4", features = ["serde"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -45,14 +45,7 @@ struct SearchResult {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_search=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_search");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -63,14 +56,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let query = &cli.query;
|
||||
|
||||
|
|
|
|||
17
tools/synops-suggest-edges/Cargo.lock
generated
17
tools/synops-suggest-edges/Cargo.lock
generated
|
|
@ -1905,6 +1905,22 @@ dependencies = [
|
|||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-suggest-edges"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1915,6 +1931,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -140,14 +140,7 @@ Regler:
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_suggest_edges=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_suggest_edges");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -163,14 +156,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url =
|
||||
std::env::var("DATABASE_URL").map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let node_id = cli.node_id;
|
||||
|
||||
|
|
|
|||
17
tools/synops-summarize/Cargo.lock
generated
17
tools/synops-summarize/Cargo.lock
generated
|
|
@ -1905,6 +1905,22 @@ dependencies = [
|
|||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-summarize"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1915,6 +1931,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -110,14 +110,7 @@ Regler:
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_summarize=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_summarize");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -133,14 +126,7 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL er ikke satt".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let communication_id = cli.communication_id;
|
||||
|
||||
|
|
|
|||
231
tools/synops-tasks/Cargo.lock
generated
Normal file
231
tools/synops-tasks/Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "1.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"anstyle-parse",
|
||||
"anstyle-query",
|
||||
"anstyle-wincon",
|
||||
"colorchoice",
|
||||
"is_terminal_polyfill",
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle"
|
||||
version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000"
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-parse"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e"
|
||||
dependencies = [
|
||||
"utf8parse",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-query"
|
||||
version = "1.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell_polyfill",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
"clap_lex",
|
||||
"strsim",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "is_terminal_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell_polyfill"
|
||||
version = "1.70.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-automata"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-tasks"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.61.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
17
tools/synops-transcribe/Cargo.lock
generated
17
tools/synops-transcribe/Cargo.lock
generated
|
|
@ -1923,6 +1923,22 @@ dependencies = [
|
|||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"hex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"sqlx",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-transcribe"
|
||||
version = "0.1.0"
|
||||
|
|
@ -1933,6 +1949,7 @@ dependencies = [
|
|||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"tracing-subscriber",
|
||||
|
|
|
|||
|
|
@ -18,3 +18,4 @@ chrono = { version = "0.4", features = ["serde"] }
|
|||
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json", "multipart"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
synops-common = { path = "../synops-common" }
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
use chrono::Utc;
|
||||
use clap::Parser;
|
||||
use serde::Serialize;
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
@ -76,14 +75,7 @@ struct TranscribeResult {
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_transcribe=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_transcribe");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -99,11 +91,11 @@ async fn main() {
|
|||
}
|
||||
|
||||
async fn run(cli: Cli) -> Result<(), String> {
|
||||
let cas_root = std::env::var("CAS_ROOT").unwrap_or_else(|_| "/srv/synops/media/cas".into());
|
||||
let cas_root = synops_common::cas::root();
|
||||
let whisper_url = std::env::var("WHISPER_URL").unwrap_or_else(|_| "http://localhost:8000".into());
|
||||
|
||||
// 1. Les lydfil fra CAS
|
||||
let file_path = cas_path(&cas_root, &cli.cas_hash);
|
||||
let file_path = synops_common::cas::path(&cas_root, &cli.cas_hash);
|
||||
let file_data = tokio::fs::read(&file_path)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke lese CAS-fil {}: {e}", cli.cas_hash))?;
|
||||
|
|
@ -116,7 +108,7 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
);
|
||||
|
||||
// 2. Send til faster-whisper API (SRT-format)
|
||||
let file_ext = mime_to_extension(&cli.mime);
|
||||
let file_ext = synops_common::cas::mime_to_extension(&cli.mime);
|
||||
let file_name = format!("audio.{file_ext}");
|
||||
|
||||
let file_part = reqwest::multipart::Part::bytes(file_data)
|
||||
|
|
@ -187,14 +179,7 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
// 6. Skriv til database hvis --write
|
||||
if cli.write {
|
||||
let node_id = cli.node_id.unwrap(); // Allerede validert
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL må settes med --write".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
// Slett gamle segmenter for denne noden (idempotent)
|
||||
sqlx::query("DELETE FROM transcription_segments WHERE node_id = $1")
|
||||
|
|
@ -218,26 +203,6 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// CAS-filsti: {root}/{hash[0..2]}/{hash[2..4]}/{hash}
|
||||
fn cas_path(root: &str, hash: &str) -> PathBuf {
|
||||
PathBuf::from(root)
|
||||
.join(&hash[..2])
|
||||
.join(&hash[2..4])
|
||||
.join(hash)
|
||||
}
|
||||
|
||||
fn mime_to_extension(mime: &str) -> &str {
|
||||
match mime {
|
||||
"audio/mpeg" | "audio/mp3" => "mp3",
|
||||
"audio/wav" | "audio/x-wav" => "wav",
|
||||
"audio/ogg" => "ogg",
|
||||
"audio/flac" | "audio/x-flac" => "flac",
|
||||
"audio/mp4" | "audio/m4a" | "audio/x-m4a" => "m4a",
|
||||
"audio/webm" => "webm",
|
||||
_ => "wav",
|
||||
}
|
||||
}
|
||||
|
||||
// --- SRT-parsing ---
|
||||
|
||||
fn parse_srt(srt: &str) -> Result<Vec<Segment>, String> {
|
||||
|
|
@ -467,10 +432,10 @@ I dag snakker vi om fotball.
|
|||
|
||||
#[test]
|
||||
fn test_cas_path() {
|
||||
let p = cas_path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
let p = synops_common::cas::path("/srv/synops/media/cas", "b94d27b9934d3e08");
|
||||
assert_eq!(
|
||||
p,
|
||||
PathBuf::from("/srv/synops/media/cas/b9/4d/b94d27b9934d3e08")
|
||||
std::path::PathBuf::from("/srv/synops/media/cas/b9/4d/b94d27b9934d3e08")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
20
tools/synops-tts/Cargo.lock
generated
20
tools/synops-tts/Cargo.lock
generated
|
|
@ -1906,13 +1906,11 @@ dependencies = [
|
|||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-tts"
|
||||
name = "synops-common"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"hex",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2",
|
||||
|
|
@ -1923,6 +1921,22 @@ dependencies = [
|
|||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synops-tts"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sqlx",
|
||||
"synops-common",
|
||||
"tokio",
|
||||
"tracing",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "synstructure"
|
||||
version = "0.13.2"
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ name = "synops-tts"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
synops-common = { path = "../synops-common" }
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-rustls", "postgres", "uuid", "chrono", "json"] }
|
||||
|
|
@ -16,7 +17,4 @@ serde_json = "1"
|
|||
uuid = { version = "1", features = ["v7", "serde"] }
|
||||
chrono = { version = "0.4", features = ["serde"] }
|
||||
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "json"] }
|
||||
sha2 = "0.10"
|
||||
hex = "0.4"
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
// Ref: docs/retninger/unix_filosofi.md, docs/proposals/ghost_host_tts.md
|
||||
|
||||
use clap::Parser;
|
||||
use sha2::{Digest, Sha256};
|
||||
use std::path::PathBuf;
|
||||
use std::process;
|
||||
use uuid::Uuid;
|
||||
|
||||
|
|
@ -53,14 +51,7 @@ const MAX_TEXT_LENGTH: usize = 5000;
|
|||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
tracing_subscriber::EnvFilter::try_from_default_env()
|
||||
.unwrap_or_else(|_| "synops_tts=info".parse().unwrap()),
|
||||
)
|
||||
.with_target(false)
|
||||
.with_writer(std::io::stderr)
|
||||
.init();
|
||||
synops_common::logging::init("synops_tts");
|
||||
|
||||
let cli = Cli::parse();
|
||||
|
||||
|
|
@ -107,8 +98,8 @@ async fn run(cli: Cli) -> Result<(), String> {
|
|||
tracing::info!(audio_size = audio_bytes.len(), "Mottok lyd fra ElevenLabs");
|
||||
|
||||
// 2. Lagre i CAS
|
||||
let cas_root = std::env::var("CAS_ROOT").unwrap_or_else(|_| "/srv/synops/media/cas".into());
|
||||
let cas_hash = store_in_cas(&cas_root, &audio_bytes).await?;
|
||||
let cas_root = synops_common::cas::root();
|
||||
let cas_hash = synops_common::cas::store(&cas_root, &audio_bytes).await?;
|
||||
|
||||
tracing::info!(cas_hash = %cas_hash, "Lyd lagret i CAS");
|
||||
|
||||
|
|
@ -189,45 +180,6 @@ async fn call_elevenlabs(text: &str, voice_id: &str) -> Result<Vec<u8>, String>
|
|||
.map_err(|e| format!("Kunne ikke lese ElevenLabs-respons: {e}"))
|
||||
}
|
||||
|
||||
/// Lagre bytes i CAS. Returnerer SHA-256 hash.
|
||||
/// Atomisk skriving via temp-fil + rename.
|
||||
async fn store_in_cas(cas_root: &str, data: &[u8]) -> Result<String, String> {
|
||||
let mut hasher = Sha256::new();
|
||||
hasher.update(data);
|
||||
let hash = hex::encode(hasher.finalize());
|
||||
|
||||
let dir = PathBuf::from(cas_root)
|
||||
.join(&hash[..2])
|
||||
.join(&hash[2..4]);
|
||||
let final_path = dir.join(&hash);
|
||||
|
||||
// Allerede lagret? Returner direkte.
|
||||
if final_path.exists() {
|
||||
tracing::info!("CAS-deduplisering: filen finnes allerede");
|
||||
return Ok(hash);
|
||||
}
|
||||
|
||||
tokio::fs::create_dir_all(&dir)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke opprette CAS-dir {}: {e}", dir.display()))?;
|
||||
|
||||
let tmp_dir = PathBuf::from(cas_root).join("tmp");
|
||||
tokio::fs::create_dir_all(&tmp_dir)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke opprette CAS tmp-dir: {e}"))?;
|
||||
|
||||
let tmp_path = tmp_dir.join(format!("{hash}.tmp"));
|
||||
tokio::fs::write(&tmp_path, data)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke skrive CAS temp-fil: {e}"))?;
|
||||
|
||||
tokio::fs::rename(&tmp_path, &final_path)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke flytte CAS-fil: {e}"))?;
|
||||
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
/// Opprett media-node og has_media-edge i PostgreSQL.
|
||||
/// Returnerer media_node_id for STDB-synk.
|
||||
async fn write_to_db(
|
||||
|
|
@ -239,14 +191,7 @@ async fn write_to_db(
|
|||
source_node_id: Option<Uuid>,
|
||||
requested_by: Uuid,
|
||||
) -> Result<Uuid, String> {
|
||||
let db_url = std::env::var("DATABASE_URL")
|
||||
.map_err(|_| "DATABASE_URL må settes med --write".to_string())?;
|
||||
|
||||
let db = sqlx::postgres::PgPoolOptions::new()
|
||||
.max_connections(2)
|
||||
.connect(&db_url)
|
||||
.await
|
||||
.map_err(|e| format!("Kunne ikke koble til database: {e}"))?;
|
||||
let db = synops_common::db::connect().await?;
|
||||
|
||||
let media_node_id = Uuid::now_v7();
|
||||
let title = format!("TTS: {}", truncate(text, 60));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue