feat: trace-level matching, health watcher/worker status, timezone config

This commit is contained in:
Accusys
2026-05-21 01:08:30 +08:00
parent 8ede4be159
commit bebaa743ed
60 changed files with 6110 additions and 1586 deletions
+49 -21
View File
@@ -54,8 +54,7 @@ pub fn read_identity_file(uuid: &str) -> Result<IdentityFile> {
let path = identity_file_path(uuid);
let content = std::fs::read_to_string(&path)
.with_context(|| format!("Identity file not found: {} ({})", uuid, path.display()))?;
serde_json::from_str(&content)
.with_context(|| format!("Invalid identity.json: {}", uuid))
serde_json::from_str(&content).with_context(|| format!("Invalid identity.json: {}", uuid))
}
pub fn write_identity_file(file: &IdentityFile) -> Result<()> {
@@ -167,7 +166,10 @@ pub fn rebuild_index() -> Result<usize> {
entries.insert(uuid.clone(), file.name);
}
Err(e) => {
warn!("[identity-storage] Skipping {} in index rebuild: {}", uuid, e);
warn!(
"[identity-storage] Skipping {} in index rebuild: {}",
uuid, e
);
}
}
}
@@ -187,18 +189,16 @@ pub async fn save_identity_file_by_pool(pool: &sqlx::PgPool, uuid: &str) -> Resu
let identity_table = crate::core::db::schema::table_name("identities");
let fd_table = crate::core::db::schema::table_name("face_detections");
// Schema-aware column selection: dev uses 'name', public uses 'real_name'
let name_col = if identity_table.starts_with("dev.") { "name" } else { "real_name" };
let clean = uuid.replace('-', "");
let record = sqlx::query_as::<_, crate::core::db::IdentityDetailRecord>(
&format!(
"SELECT id, uuid::text, {} AS name, identity_type, source, status, metadata, reference_data, \
NULL::real[] as voice_embedding, NULL::real[] as identity_embedding, \
face_embedding::real[] as face_embedding, \
tmdb_id, tmdb_profile, created_at::timestamptz as created_at, NULL::timestamptz as updated_at \
FROM {} WHERE REPLACE(uuid::text, '-', '') = $1",
name_col, identity_table
"SELECT id, uuid::text, name, identity_type, source, status, metadata, reference_data, \
NULL::real[] as voice_embedding, NULL::real[] as identity_embedding, \
face_embedding::real[] as face_embedding, \
tmdb_id, tmdb_profile, created_at::timestamptz as created_at, NULL::timestamptz as updated_at \
FROM {} WHERE REPLACE(uuid::text, '-', '') = $1",
identity_table
)
)
.bind(&clean)
@@ -322,8 +322,13 @@ pub fn update_index_at(base: &std::path::Path, uuid: &str, name: &str) -> Result
let mut entries: HashMap<String, String> = if index_path.exists() {
let content = std::fs::read_to_string(&index_path)?;
let v: serde_json::Value = serde_json::from_str(&content).unwrap_or_default();
v["entries"].as_object()
.map(|obj| obj.iter().map(|(k, v)| (k.clone(), v.as_str().unwrap_or("").to_string())).collect())
v["entries"]
.as_object()
.map(|obj| {
obj.iter()
.map(|(k, v)| (k.clone(), v.as_str().unwrap_or("").to_string()))
.collect()
})
.unwrap_or_default()
} else {
HashMap::new()
@@ -338,7 +343,9 @@ pub fn update_index_at(base: &std::path::Path, uuid: &str, name: &str) -> Result
}
pub async fn save_identity_file(db: &PostgresDb, uuid: &str) -> Result<()> {
let record = db.get_identity_by_uuid(uuid).await?
let record = db
.get_identity_by_uuid(uuid)
.await?
.with_context(|| format!("Identity not found in DB: {}", uuid))?;
let identity_uuid = record.uuid.clone();
@@ -415,6 +422,7 @@ mod tests {
status: Some("confirmed".to_string()),
tmdb_id: Some(112),
tmdb_profile: Some("https://image.tmdb.org/t/p/w185/test.jpg".to_string()),
local_profile: None,
metadata: serde_json::json!({"tmdb_character": "Test Role"}),
file_bindings: vec![FileBinding {
file_uuid: "ffffffffffffffffffffffffffffffff".to_string(),
@@ -442,7 +450,9 @@ mod tests {
fn test_identity_dir_path() {
let uuid = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
let p = identity_dir(uuid);
assert!(p.to_string_lossy().ends_with(&format!("identities/{}", uuid)));
assert!(p
.to_string_lossy()
.ends_with(&format!("identities/{}", uuid)));
}
#[test]
@@ -463,7 +473,10 @@ mod tests {
let base = Path::new("/tmp/test_base");
let uuid = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
let p = identity_dir_at(base, uuid);
assert_eq!(p, Path::new("/tmp/test_base/identities/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"));
assert_eq!(
p,
Path::new("/tmp/test_base/identities/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")
);
}
#[test]
@@ -490,7 +503,10 @@ mod tests {
assert_eq!(read.name, file.name);
assert_eq!(read.source, file.source);
assert_eq!(read.tmdb_id, file.tmdb_id);
assert_eq!(read.file_bindings[0].face_count, file.file_bindings[0].face_count);
assert_eq!(
read.file_bindings[0].face_count,
file.file_bindings[0].face_count
);
let _ = std::fs::remove_dir_all(&tmp);
}
@@ -521,9 +537,21 @@ mod tests {
let _ = std::fs::remove_dir_all(&tmp);
let base = &tmp;
std::fs::create_dir_all(base.join("identities").join("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")).unwrap();
std::fs::create_dir_all(base.join("identities").join("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")).unwrap();
std::fs::create_dir_all(base.join("identities").join("cccccccccccccccccccccccccccccccc")).unwrap();
std::fs::create_dir_all(
base.join("identities")
.join("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"),
)
.unwrap();
std::fs::create_dir_all(
base.join("identities")
.join("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"),
)
.unwrap();
std::fs::create_dir_all(
base.join("identities")
.join("cccccccccccccccccccccccccccccccc"),
)
.unwrap();
std::fs::create_dir_all(base.join("identities").join("not_a_uuid")).unwrap();
std::fs::create_dir_all(base.join("identities").join("short")).unwrap();