use std::{cell::RefCell, collections::HashMap, rc::Rc};
use audi::{Listener, ListenerSet};
use endr::ObjectID;
use futures::{channel::mpsc::channel, future, stream, FutureExt, SinkExt, StreamExt};
use crate::ContentType;
struct JsonStreamContentInner {
weak_doc: Option<crate::doc::WeakDoc>,
latest_per_log: HashMap<ObjectID, litl::Val>,
change_listeners: ListenerSet<HashMap<ObjectID, litl::Val>>,
}
#[derive(Clone)]
pub struct JsonStreamContent(Rc<RefCell<JsonStreamContentInner>>);
impl JsonStreamContent {
pub fn new_empty() -> JsonStreamContent {
JsonStreamContent(Rc::new(RefCell::new(JsonStreamContentInner {
weak_doc: None,
latest_per_log: HashMap::new(),
change_listeners: ListenerSet::new(),
})))
}
pub fn get_latest(&self, log_id: &ObjectID) -> Option<litl::Val> {
self.0.borrow().latest_per_log.get(log_id).cloned()
}
pub async fn add_update_listener(&self, listener: Listener<HashMap<ObjectID, litl::Val>>) {
let listeners = self.0.borrow().change_listeners.clone();
let latest_per_log = self.0.borrow().latest_per_log.clone();
listeners
.add_with_initial_msg(listener, Some(latest_per_log))
.await;
}
pub fn updates(
&self,
listener_prefix: String,
) -> impl futures::Stream<Item = HashMap<ObjectID, litl::Val>> {
let (updates_tx, updates_rx) = channel(1000000);
let self_clone = self.clone();
stream::once(async move {
self_clone
.add_update_listener(Listener::new(
&format!("{}_{:?}", listener_prefix, rand07::random::<u64>()),
updates_tx,
))
.await;
updates_rx
})
.flatten()
.boxed_local()
}
pub async fn add_val(&self, val: litl::Val) {
let doc = self
.0
.borrow()
.weak_doc
.as_ref()
.unwrap()
.upgrade()
.unwrap();
let (mut out, _) = doc.start_writing();
out.send(val).await.unwrap();
}
}
impl ContentType for JsonStreamContent {
fn content_type(&self) -> &'static str {
return "json_stream1";
}
fn connect_and_init(&self, weak_doc: crate::doc::WeakDoc, _require_intro: bool) {
let mut self_ref = self.0.borrow_mut();
self_ref.weak_doc = Some(weak_doc);
}
fn follow_new_log(
&self,
log_id: endr::ObjectID,
diffs: std::pin::Pin<Box<dyn futures::Stream<Item = super::ContentDiff>>>,
) -> std::pin::Pin<Box<dyn futures::Future<Output = ()>>> {
let self_for_stream = self.clone();
diffs
.filter(|diff| future::ready(diff.decrypted_entries.len() > 0))
.for_each(move |diff| {
let self_for_stream = self_for_stream.clone();
async move {
if let Some(last_val) = diff.decrypted_entries.last() {
self_for_stream
.0
.borrow_mut()
.latest_per_log
.insert(log_id.clone(), last_val.clone());
let listeners = self_for_stream.0.borrow().change_listeners.clone();
let latest_per_log = self_for_stream.0.borrow().latest_per_log.clone();
listeners.broadcast(latest_per_log).await;
}
}
})
.boxed_local()
}
}