Two way sync V0 (#282)

* Unfinished two-way sync API

* In-memory two-way sync complete

* Move PatchSet application into ChangeProcessor thread, where it can be synchronous

* Stop InstanceMap's signals when a ServeSession terminates

* Apply patch in ChangeProcessor

* Feature flag

* Fix error in ChangeProcessor due to wrong drop order
This commit is contained in:
Lucien Greathouse
2019-12-20 14:24:28 -08:00
committed by GitHub
parent 26e2e81188
commit a398338c02
9 changed files with 156 additions and 20 deletions

View File

@@ -3,19 +3,20 @@
use std::{collections::HashMap, sync::Arc};
use futures::Future;
use futures::{Future, Stream};
use hyper::{service::Service, Body, Method, Request, StatusCode};
use rbx_dom_weak::RbxId;
use crate::{
serve_session::ServeSession,
snapshot::{PatchSet, PatchUpdate},
vfs::VfsFetcher,
web::{
interface::{
ErrorResponse, Instance, InstanceMetadata as WebInstanceMetadata, InstanceUpdate,
ReadResponse, ServerInfoResponse, SubscribeMessage, SubscribeResponse,
PROTOCOL_VERSION, SERVER_VERSION,
ReadResponse, ServerInfoResponse, SubscribeMessage, SubscribeResponse, WriteRequest,
WriteResponse, PROTOCOL_VERSION, SERVER_VERSION,
},
util::{json, json_ok},
},
@@ -39,6 +40,11 @@ impl<F: VfsFetcher> Service for ApiService<F> {
(&Method::GET, path) if path.starts_with("/api/subscribe/") => {
self.handle_api_subscribe(request)
}
(&Method::POST, "/api/write") if cfg!(feature = "unstable_two_way_sync") => {
self.handle_api_write(request)
}
(_method, path) => json(
ErrorResponse::not_found(format!("Route not found: {}", path)),
StatusCode::NOT_FOUND,
@@ -145,6 +151,52 @@ impl<F: VfsFetcher> ApiService<F> {
}))
}
fn handle_api_write(&self, request: Request<Body>) -> <Self as Service>::Future {
let session_id = self.serve_session.session_id();
let tree_mutation_sender = self.serve_session.tree_mutation_sender();
Box::new(request.into_body().concat2().and_then(move |body| {
let request: WriteRequest = match serde_json::from_slice(&body) {
Ok(request) => request,
Err(err) => {
return json(
ErrorResponse::bad_request(format!("Invalid body: {}", err)),
StatusCode::BAD_REQUEST,
);
}
};
if request.session_id != session_id {
return json(
ErrorResponse::bad_request("Wrong session ID"),
StatusCode::BAD_REQUEST,
);
}
let updated_instances = request
.updated
.into_iter()
.map(|update| PatchUpdate {
id: update.id,
changed_class_name: update.changed_class_name,
changed_name: update.changed_name,
changed_properties: update.changed_properties,
changed_metadata: None,
})
.collect();
tree_mutation_sender
.send(PatchSet {
removed_instances: Vec::new(),
added_instances: Vec::new(),
updated_instances,
})
.unwrap();
json_ok(&WriteResponse { session_id })
}))
}
fn handle_api_read(&self, request: Request<Body>) -> <Self as Service>::Future {
let argument = &request.uri().path()["/api/read/".len()..];
let requested_ids: Option<Vec<RbxId>> = argument.split(',').map(RbxId::parse_str).collect();