diff --git a/src/serve_session.rs b/src/serve_session.rs index cfc6d4f1..05ff0d93 100644 --- a/src/serve_session.rs +++ b/src/serve_session.rs @@ -99,6 +99,10 @@ impl ServeSession { } impl ServeSession { + pub fn tree_handle(&self) -> Arc> { + Arc::clone(&self.tree) + } + pub fn tree(&self) -> MutexGuard<'_, RojoTree> { self.tree.lock().unwrap() } diff --git a/src/web/api.rs b/src/web/api.rs index 1c979e74..8be66359 100644 --- a/src/web/api.rs +++ b/src/web/api.rs @@ -13,8 +13,9 @@ use crate::{ serve_session::ServeSession, web::{ interface::{ - ErrorResponse, Instance, ReadResponse, ServerInfoResponse, SubscribeMessage, - SubscribeResponse, PROTOCOL_VERSION, SERVER_VERSION, + ErrorResponse, Instance, InstanceMetadata as WebInstanceMetadata, InstanceUpdate, + ReadResponse, ServerInfoResponse, SubscribeMessage, SubscribeResponse, + PROTOCOL_VERSION, SERVER_VERSION, }, util::{json, json_ok}, }, @@ -89,15 +90,46 @@ impl ApiService { message_queue.subscribe(input_cursor, sender); } + let tree_handle = self.serve_session.tree_handle(); + Box::new(receiver.then(move |result| match result { Ok((message_cursor, messages)) => { - // TODO: Transform applied patch sets into subscribe responses + let tree = tree_handle.lock().unwrap(); + let api_messages = messages .into_iter() .map(|message| { let removed_instances = message.removed; - let added_instances = HashMap::new(); // TODO - let updated_instances = Vec::new(); // TODO + + let mut added_instances = HashMap::new(); + for id in message.added { + let instance = tree.get_instance(id).unwrap(); + added_instances.insert(id, Instance::from_rojo_instance(instance)); + + for instance in tree.descendants(id) { + added_instances + .insert(instance.id(), Instance::from_rojo_instance(instance)); + } + } + + let updated_instances = message + .updated + .into_iter() + .map(|update| { + let changed_metadata = update + .changed_metadata + .as_ref() + .map(WebInstanceMetadata::from_rojo_metadata); + + InstanceUpdate { + id: update.id, + changed_name: update.changed_name, + changed_class_name: update.changed_class_name, + changed_properties: update.changed_properties, + changed_metadata, + } + }) + .collect(); SubscribeMessage { removed_instances, diff --git a/src/web/interface.rs b/src/web/interface.rs index a3ab3432..dcfc3bdf 100644 --- a/src/web/interface.rs +++ b/src/web/interface.rs @@ -8,7 +8,10 @@ use std::{ use rbx_dom_weak::{RbxId, RbxValue}; use serde::{Deserialize, Serialize}; -use crate::{session_id::SessionId, snapshot::InstanceWithMeta}; +use crate::{ + session_id::SessionId, + snapshot::{InstanceMetadata as RojoInstanceMetadata, InstanceWithMeta}, +}; /// Server version to report over the API, not exposed outside this crate. pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -31,7 +34,9 @@ pub struct InstanceUpdate { pub id: RbxId, pub changed_name: Option, pub changed_class_name: Option, - pub changed_properties: HashMap, + // TODO: Transform from HashMap> to something else, since + // null will get lost when decoding from JSON in some languages. + pub changed_properties: HashMap>, pub changed_metadata: Option, } @@ -41,6 +46,14 @@ pub struct InstanceMetadata { pub ignore_unknown_instances: bool, } +impl InstanceMetadata { + pub(crate) fn from_rojo_metadata(meta: &RojoInstanceMetadata) -> Self { + Self { + ignore_unknown_instances: meta.ignore_unknown_instances, + } + } +} + #[derive(Debug, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct Instance<'a> { @@ -52,15 +65,13 @@ pub struct Instance<'a> { } impl<'a> Instance<'a> { - pub fn from_rojo_instance<'b>(source: InstanceWithMeta<'b>) -> Instance<'b> { + pub(crate) fn from_rojo_instance<'b>(source: InstanceWithMeta<'b>) -> Instance<'b> { Instance { name: Cow::Borrowed(source.name()), class_name: Cow::Borrowed(source.class_name()), properties: Cow::Borrowed(source.properties()), children: Cow::Borrowed(source.children()), - metadata: Some(InstanceMetadata { - ignore_unknown_instances: source.metadata().ignore_unknown_instances, - }), + metadata: Some(InstanceMetadata::from_rojo_metadata(source.metadata())), } } }