mirror of
https://github.com/rojo-rbx/rojo.git
synced 2026-04-23 14:15:24 +00:00
Glue message queue onto ServeSession, simplify some HTTP
This commit is contained in:
@@ -77,7 +77,7 @@ impl<T: Clone> MessageQueue<T> {
|
|||||||
message_listeners.push(listener);
|
message_listeners.push(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_message_cursor(&self) -> u32 {
|
pub fn cursor(&self) -> u32 {
|
||||||
self.messages.read().unwrap().len() as u32
|
self.messages.read().unwrap().len() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use crate::{project::Project, session_id::SessionId, snapshot::RojoTree};
|
use crate::{
|
||||||
|
message_queue::MessageQueue, project::Project, session_id::SessionId, snapshot::RojoTree,
|
||||||
|
};
|
||||||
|
|
||||||
/// Contains all of the state for a Rojo serve session.
|
/// Contains all of the state for a Rojo serve session.
|
||||||
pub struct ServeSession {
|
pub struct ServeSession {
|
||||||
root_project: Option<Project>,
|
root_project: Option<Project>,
|
||||||
session_id: SessionId,
|
session_id: SessionId,
|
||||||
tree: RojoTree,
|
tree: RojoTree,
|
||||||
|
message_queue: MessageQueue<()>, // TODO: Real message type
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ServeSession {
|
impl ServeSession {
|
||||||
pub fn new(tree: RojoTree, root_project: Option<Project>) -> ServeSession {
|
pub fn new(tree: RojoTree, root_project: Option<Project>) -> ServeSession {
|
||||||
let session_id = SessionId::new();
|
let session_id = SessionId::new();
|
||||||
|
let message_queue = MessageQueue::new();
|
||||||
|
|
||||||
ServeSession {
|
ServeSession {
|
||||||
session_id,
|
session_id,
|
||||||
root_project,
|
root_project,
|
||||||
tree,
|
tree,
|
||||||
|
message_queue,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +29,10 @@ impl ServeSession {
|
|||||||
&self.tree
|
&self.tree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn message_queue(&self) -> &MessageQueue<()> {
|
||||||
|
&self.message_queue
|
||||||
|
}
|
||||||
|
|
||||||
pub fn session_id(&self) -> SessionId {
|
pub fn session_id(&self) -> SessionId {
|
||||||
self.session_id
|
self.session_id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
//! Defines Rojo's HTTP API, all under /api. These endpoints generally return
|
//! Defines Rojo's HTTP API, all under /api. These endpoints generally return
|
||||||
//! JSON.
|
//! JSON.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::{collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
use futures::{future, Future};
|
use futures::{future, Future};
|
||||||
|
|
||||||
@@ -12,9 +12,10 @@ use crate::{
|
|||||||
serve_session::ServeSession,
|
serve_session::ServeSession,
|
||||||
web::{
|
web::{
|
||||||
interface::{
|
interface::{
|
||||||
ReadResponse, ServerInfoResponse, SubscribeResponse, PROTOCOL_VERSION, SERVER_VERSION,
|
NotFoundError, ReadResponse, ServerInfoResponse, SubscribeResponse, PROTOCOL_VERSION,
|
||||||
|
SERVER_VERSION,
|
||||||
},
|
},
|
||||||
util::response_json,
|
util::{json, json_ok},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -30,19 +31,14 @@ impl Service for ApiService {
|
|||||||
Box<dyn Future<Item = hyper::Response<Self::ReqBody>, Error = Self::Error> + Send>;
|
Box<dyn Future<Item = hyper::Response<Self::ReqBody>, Error = Self::Error> + Send>;
|
||||||
|
|
||||||
fn call(&mut self, request: hyper::Request<Self::ReqBody>) -> Self::Future {
|
fn call(&mut self, request: hyper::Request<Self::ReqBody>) -> Self::Future {
|
||||||
let response = match (request.method(), request.uri().path()) {
|
match (request.method(), request.uri().path()) {
|
||||||
(&Method::GET, "/api/rojo") => self.handle_api_rojo(),
|
(&Method::GET, "/api/rojo") => self.handle_api_rojo(),
|
||||||
(&Method::GET, path) if path.starts_with("/api/read/") => self.handle_api_read(request),
|
(&Method::GET, path) if path.starts_with("/api/read/") => self.handle_api_read(request),
|
||||||
(&Method::GET, path) if path.starts_with("/api/subscribe/") => {
|
(&Method::GET, path) if path.starts_with("/api/subscribe/") => {
|
||||||
return self.handle_api_subscribe(request);
|
self.handle_api_subscribe(request)
|
||||||
}
|
}
|
||||||
_ => Response::builder()
|
_ => json(NotFoundError, StatusCode::NOT_FOUND),
|
||||||
.status(StatusCode::NOT_FOUND)
|
}
|
||||||
.body(Body::empty())
|
|
||||||
.unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::new(future::ok(response))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,11 +48,11 @@ impl ApiService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a summary of information about the server
|
/// Get a summary of information about the server
|
||||||
fn handle_api_rojo(&self) -> Response<Body> {
|
fn handle_api_rojo(&self) -> <ApiService as Service>::Future {
|
||||||
let tree = self.serve_session.tree();
|
let tree = self.serve_session.tree();
|
||||||
let root_instance_id = tree.get_root_id();
|
let root_instance_id = tree.get_root_id();
|
||||||
|
|
||||||
response_json(&ServerInfoResponse {
|
json_ok(&ServerInfoResponse {
|
||||||
server_version: SERVER_VERSION.to_owned(),
|
server_version: SERVER_VERSION.to_owned(),
|
||||||
protocol_version: PROTOCOL_VERSION,
|
protocol_version: PROTOCOL_VERSION,
|
||||||
session_id: self.serve_session.session_id(),
|
session_id: self.serve_session.session_id(),
|
||||||
@@ -69,7 +65,7 @@ impl ApiService {
|
|||||||
/// there weren't any, subscribe to receive any new messages.
|
/// there weren't any, subscribe to receive any new messages.
|
||||||
fn handle_api_subscribe(&self, request: Request<Body>) -> <ApiService as Service>::Future {
|
fn handle_api_subscribe(&self, request: Request<Body>) -> <ApiService as Service>::Future {
|
||||||
let argument = &request.uri().path()["/api/subscribe/".len()..];
|
let argument = &request.uri().path()["/api/subscribe/".len()..];
|
||||||
let _cursor: u32 = match argument.parse() {
|
let _input_cursor: u32 = match argument.parse() {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Box::new(future::ok(
|
return Box::new(future::ok(
|
||||||
@@ -82,28 +78,44 @@ impl ApiService {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::new(future::ok(response_json(SubscribeResponse {
|
let message_queue = self.serve_session.message_queue();
|
||||||
|
let message_cursor = message_queue.cursor();
|
||||||
|
|
||||||
|
let messages = Vec::new(); // TODO
|
||||||
|
|
||||||
|
json_ok(SubscribeResponse {
|
||||||
session_id: self.serve_session.session_id(),
|
session_id: self.serve_session.session_id(),
|
||||||
})))
|
message_cursor,
|
||||||
|
messages,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_api_read(&self, request: Request<Body>) -> Response<Body> {
|
fn handle_api_read(&self, request: Request<Body>) -> <ApiService as Service>::Future {
|
||||||
let argument = &request.uri().path()["/api/read/".len()..];
|
let argument = &request.uri().path()["/api/read/".len()..];
|
||||||
let requested_ids: Option<Vec<RbxId>> = argument.split(',').map(RbxId::parse_str).collect();
|
let requested_ids: Option<Vec<RbxId>> = argument.split(',').map(RbxId::parse_str).collect();
|
||||||
|
|
||||||
let _requested_ids = match requested_ids {
|
let _requested_ids = match requested_ids {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
None => {
|
None => {
|
||||||
return Response::builder()
|
return Box::new(future::ok(
|
||||||
.status(StatusCode::BAD_REQUEST)
|
Response::builder()
|
||||||
.header(header::CONTENT_TYPE, "text/plain")
|
.status(StatusCode::BAD_REQUEST)
|
||||||
.body(Body::from("Malformed ID list"))
|
.header(header::CONTENT_TYPE, "text/plain")
|
||||||
.unwrap();
|
.body(Body::from("Malformed ID list"))
|
||||||
|
.unwrap(),
|
||||||
|
));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
response_json(ReadResponse {
|
let message_queue = self.serve_session.message_queue();
|
||||||
|
let message_cursor = message_queue.cursor();
|
||||||
|
|
||||||
|
let instances = HashMap::new(); // TODO
|
||||||
|
|
||||||
|
json_ok(ReadResponse {
|
||||||
session_id: self.serve_session.session_id(),
|
session_id: self.serve_session.session_id(),
|
||||||
|
message_cursor,
|
||||||
|
instances,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
//! Defines all the structs needed to interact with the Rojo Serve API.
|
//! Defines all the structs needed to interact with the Rojo Serve API.
|
||||||
|
|
||||||
use std::collections::HashSet;
|
use std::collections::{HashMap, HashSet};
|
||||||
|
|
||||||
use rbx_dom_weak::RbxId;
|
use rbx_dom_weak::RbxId;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
@@ -13,6 +13,14 @@ pub(crate) const SERVER_VERSION: &str = env!("CARGO_PKG_VERSION");
|
|||||||
/// Current protocol version, which is required to match.
|
/// Current protocol version, which is required to match.
|
||||||
pub const PROTOCOL_VERSION: u64 = 3;
|
pub const PROTOCOL_VERSION: u64 = 3;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct SubscribeMessage;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct Instance;
|
||||||
|
|
||||||
/// Response body from /api/rojo
|
/// Response body from /api/rojo
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
@@ -29,8 +37,8 @@ pub struct ServerInfoResponse {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ReadResponse {
|
pub struct ReadResponse {
|
||||||
pub session_id: SessionId,
|
pub session_id: SessionId,
|
||||||
// pub message_cursor: u32,
|
pub message_cursor: u32,
|
||||||
// pub instances: HashMap<RbxId, InstanceWithMetadata<'a>>,
|
pub instances: HashMap<RbxId, Instance>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Response body from /api/subscribe/{cursor}
|
/// Response body from /api/subscribe/{cursor}
|
||||||
@@ -38,6 +46,9 @@ pub struct ReadResponse {
|
|||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct SubscribeResponse {
|
pub struct SubscribeResponse {
|
||||||
pub session_id: SessionId,
|
pub session_id: SessionId,
|
||||||
// pub message_cursor: u32,
|
pub message_cursor: u32,
|
||||||
// pub messages: Cow<'a, [InstanceChanges]>,
|
pub messages: Vec<SubscribeMessage>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize)]
|
||||||
|
pub struct NotFoundError;
|
||||||
|
|||||||
@@ -6,7 +6,13 @@ use futures::{future, Future};
|
|||||||
use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode};
|
use hyper::{header, service::Service, Body, Method, Request, Response, StatusCode};
|
||||||
use ritz::html;
|
use ritz::html;
|
||||||
|
|
||||||
use crate::{serve_session::ServeSession, web::interface::SERVER_VERSION};
|
use crate::{
|
||||||
|
serve_session::ServeSession,
|
||||||
|
web::{
|
||||||
|
interface::{NotFoundError, SERVER_VERSION},
|
||||||
|
util::json,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static HOME_CSS: &str = include_str!("../../assets/index.css");
|
static HOME_CSS: &str = include_str!("../../assets/index.css");
|
||||||
|
|
||||||
@@ -26,10 +32,7 @@ impl Service for UiService {
|
|||||||
(&Method::GET, "/") => self.handle_home(),
|
(&Method::GET, "/") => self.handle_home(),
|
||||||
(&Method::GET, "/visualize/rbx") => self.handle_visualize_rbx(),
|
(&Method::GET, "/visualize/rbx") => self.handle_visualize_rbx(),
|
||||||
(&Method::GET, "/visualize/imfs") => self.handle_visualize_imfs(),
|
(&Method::GET, "/visualize/imfs") => self.handle_visualize_imfs(),
|
||||||
_ => Response::builder()
|
_ => return json(NotFoundError, StatusCode::NOT_FOUND),
|
||||||
.status(StatusCode::NOT_FOUND)
|
|
||||||
.body(Body::empty())
|
|
||||||
.unwrap(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Box::new(future::ok(response))
|
Box::new(future::ok(response))
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
use futures::{future, Future};
|
||||||
use hyper::{header::CONTENT_TYPE, Body, Response, StatusCode};
|
use hyper::{header::CONTENT_TYPE, Body, Response, StatusCode};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
pub fn response_json<T: Serialize>(value: T) -> Response<Body> {
|
fn response_json<T: Serialize>(value: T, code: StatusCode) -> Response<Body> {
|
||||||
let serialized = match serde_json::to_string(&value) {
|
let serialized = match serde_json::to_string(&value) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
@@ -14,7 +15,21 @@ pub fn response_json<T: Serialize>(value: T) -> Response<Body> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Response::builder()
|
Response::builder()
|
||||||
|
.status(code)
|
||||||
.header(CONTENT_TYPE, "application/json")
|
.header(CONTENT_TYPE, "application/json")
|
||||||
.body(Body::from(serialized))
|
.body(Body::from(serialized))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn json<T: Serialize>(
|
||||||
|
value: T,
|
||||||
|
code: StatusCode,
|
||||||
|
) -> Box<dyn Future<Item = hyper::Response<hyper::Body>, Error = hyper::Error> + Send> {
|
||||||
|
Box::new(future::ok(response_json(value, code)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn json_ok<T: Serialize>(
|
||||||
|
value: T,
|
||||||
|
) -> Box<dyn Future<Item = hyper::Response<hyper::Body>, Error = hyper::Error> + Send> {
|
||||||
|
json(value, StatusCode::OK)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user