use std::sync::Arc; use anyhow::Result; use jacquard::types::string::Did; use k256::ecdsa::SigningKey; use tokio::sync::broadcast; use crate::db::{Db, SeqLabel}; use crate::labels::sign_label; pub struct Labeler { pub db: Arc, pub did: Did, key: SigningKey, published: broadcast::Sender, } impl Labeler { pub fn new(db: Arc, did: Did, key: SigningKey) -> Self { let (published, _) = broadcast::channel(1024); Self { db, did, key, published, } } /// Live labels for `subscribeLabels`. pub fn subscribe(&self) -> broadcast::Receiver { self.published.subscribe() } pub fn current_city(&self, subject: &Did<&str>) -> Result> { Ok(self.db.active_vals(subject.as_str())?.into_iter().next()) } /// Make `city` the account's only city label; `None` removes it. pub fn set_city(&self, subject: &Did<&str>, city: Option<&str>) -> Result<()> { let active = self.db.active_vals(subject.as_str())?; for val in active.iter().filter(|v| Some(v.as_str()) != city) { self.emit(subject, val, true)?; } if let Some(city) = city.filter(|c| !active.iter().any(|v| v == c)) { self.emit(subject, city, false)?; } Ok(()) } fn emit(&self, subject: &Did<&str>, val: &str, neg: bool) -> Result<()> { let label = sign_label(&self.key, &self.did, subject, val, neg)?; let seq = self.db.insert_label(&label)?; // no receivers just means no one is subscribed right now let _ = self.published.send(SeqLabel { seq, label }); println!( "{} {val} on {subject} (seq {seq})", if neg { "negated" } else { "applied" } ); Ok(()) } }