Introduce MessageSession, for keeping track of messages to send to clients

This commit is contained in:
Lucien Greathouse 2018-05-26 01:11:05 -07:00
parent 92fa52c56f
commit d85383cfd4
7 changed files with 108 additions and 74 deletions

View file

@ -50,8 +50,7 @@ pub fn serve(project_path: &PathBuf, port: Option<u64>) {
port: port.unwrap_or(project.serve_port), port: port.unwrap_or(project.serve_port),
server_id, server_id,
rbx_session: session.get_rbx_session(), rbx_session: session.get_rbx_session(),
events: session.get_events(), message_session: session.get_message_session(),
event_listeners: session.get_event_listeners(),
}; };
println!("Server listening on port {}", web_config.port); println!("Server listening on port {}", web_config.port);

View file

@ -13,6 +13,7 @@ extern crate tempfile;
pub mod commands; pub mod commands;
pub mod file_route; pub mod file_route;
pub mod id; pub mod id;
pub mod message_session;
pub mod partition; pub mod partition;
pub mod partition_watcher; pub mod partition_watcher;
pub mod pathext; pub mod pathext;

View file

@ -0,0 +1,57 @@
use std::collections::HashMap;
use std::sync::{mpsc, Arc, RwLock, Mutex};
use id::{Id, get_id};
#[derive(Debug, Clone, Serialize)]
pub enum Message {
Something,
}
#[derive(Clone)]
pub struct MessageSession {
pub messages: Arc<RwLock<Vec<Message>>>,
pub message_listeners: Arc<Mutex<HashMap<Id, mpsc::Sender<()>>>>,
}
impl MessageSession {
pub fn new() -> MessageSession {
MessageSession {
messages: Arc::new(RwLock::new(Vec::new())),
message_listeners: Arc::new(Mutex::new(HashMap::new())),
}
}
pub fn push_messages(&self, new_messages: &[Message]) {
{
let mut messages = self.messages.write().unwrap();
messages.extend_from_slice(new_messages);
}
{
let message_listeners = self.message_listeners.lock().unwrap();
for listener in message_listeners.values() {
listener.send(()).unwrap();
}
}
}
pub fn subscribe(&self, sender: mpsc::Sender<()>) -> Id {
let id = get_id();
{
let mut message_listeners = self.message_listeners.lock().unwrap();
message_listeners.insert(id, sender);
}
id
}
pub fn unsubscribe(&self, id: Id) {
{
let mut message_listeners = self.message_listeners.lock().unwrap();
message_listeners.remove(&id);
}
}
}

View file

@ -6,7 +6,8 @@ use id::{Id, get_id};
use partition::Partition; use partition::Partition;
use rbx::RbxInstance; use rbx::RbxInstance;
use session::SessionConfig; use session::SessionConfig;
use vfs_session::{VfsSession, FileItem}; use vfs_session::{VfsSession, FileItem, FileChange};
use message_session::MessageSession;
fn file_to_instances(file_item: &FileItem, partition: &Partition, output: &mut HashMap<Id, RbxInstance>, instances_by_route: &mut HashMap<FileRoute, Id>) -> Id { fn file_to_instances(file_item: &FileItem, partition: &Partition, output: &mut HashMap<Id, RbxInstance>, instances_by_route: &mut HashMap<FileRoute, Id>) -> Id {
match file_item { match file_item {
@ -71,7 +72,7 @@ pub struct RbxSession {
} }
impl RbxSession { impl RbxSession {
pub fn new(config: SessionConfig, vfs_session: Arc<RwLock<VfsSession>>) -> RbxSession { pub fn new(config: SessionConfig, vfs_session: Arc<RwLock<VfsSession>>, message_session: MessageSession) -> RbxSession {
RbxSession { RbxSession {
config, config,
vfs_session, vfs_session,
@ -95,4 +96,8 @@ impl RbxSession {
self.partition_instances.insert(partition.name.clone(), root_id); self.partition_instances.insert(partition.name.clone(), root_id);
} }
} }
pub fn handle_change(&mut self, change: &FileChange) {
println!("Handle RBX change {:?}", change);
}
} }

View file

@ -1,12 +1,12 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{mpsc, Arc, RwLock, Mutex}; use std::sync::{mpsc, Arc, RwLock};
use std::thread; use std::thread;
use partition::Partition; use partition::Partition;
use rbx_session::RbxSession;
use vfs_session::VfsSession;
use partition_watcher::PartitionWatcher; use partition_watcher::PartitionWatcher;
use id::Id; use rbx_session::RbxSession;
use message_session::{MessageSession, Message};
use vfs_session::VfsSession;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct SessionConfig { pub struct SessionConfig {
@ -17,33 +17,25 @@ pub struct SessionConfig {
trait Middleware { trait Middleware {
} }
#[derive(Debug, Clone, Serialize)]
pub enum SessionEvent {
Something,
}
pub struct Session { pub struct Session {
config: SessionConfig, config: SessionConfig,
vfs_session: Arc<RwLock<VfsSession>>, vfs_session: Arc<RwLock<VfsSession>>,
rbx_session: Arc<RwLock<RbxSession>>, rbx_session: Arc<RwLock<RbxSession>>,
// middlewares: Vec<Box<Middleware>>, message_session: MessageSession,
watchers: Vec<PartitionWatcher>, watchers: Vec<PartitionWatcher>,
events: Arc<RwLock<Vec<SessionEvent>>>,
event_listeners: Arc<Mutex<HashMap<Id, mpsc::Sender<()>>>>,
} }
impl Session { impl Session {
pub fn new(config: SessionConfig) -> Session { pub fn new(config: SessionConfig) -> Session {
let message_session = MessageSession::new();
let vfs_session = Arc::new(RwLock::new(VfsSession::new(config.clone()))); let vfs_session = Arc::new(RwLock::new(VfsSession::new(config.clone())));
let rbx_session = Arc::new(RwLock::new(RbxSession::new(config.clone(), vfs_session.clone()))); let rbx_session = Arc::new(RwLock::new(RbxSession::new(config.clone(), vfs_session.clone(), message_session.clone())));
Session { Session {
vfs_session, vfs_session,
rbx_session, rbx_session,
// middlewares: Vec::new(),
watchers: Vec::new(), watchers: Vec::new(),
events: Arc::new(RwLock::new(Vec::new())), message_session,
event_listeners: Arc::new(Mutex::new(HashMap::new())),
config, config,
} }
} }
@ -69,8 +61,8 @@ impl Session {
{ {
let vfs_session = self.vfs_session.clone(); let vfs_session = self.vfs_session.clone();
let event_listeners = self.event_listeners.clone(); let rbx_session = self.rbx_session.clone();
let events = self.events.clone(); let message_session = self.message_session.clone();
thread::spawn(move || { thread::spawn(move || {
loop { loop {
@ -78,23 +70,15 @@ impl Session {
Ok(change) => { Ok(change) => {
{ {
let mut vfs_session = vfs_session.write().unwrap(); let mut vfs_session = vfs_session.write().unwrap();
vfs_session.handle_change(change); vfs_session.handle_change(&change);
}
// TODO: Handle change in RbxSession
{
let mut events = events.write().unwrap();
events.push(SessionEvent::Something);
} }
{ {
let listeners = event_listeners.lock().unwrap(); let mut rbx_session = rbx_session.write().unwrap();
rbx_session.handle_change(&change);
}
for listener in listeners.values() { message_session.push_messages(&[Message::Something]);
listener.send(()).unwrap();
}
}
}, },
Err(_) => break, Err(_) => break,
} }
@ -114,11 +98,7 @@ impl Session {
self.rbx_session.clone() self.rbx_session.clone()
} }
pub fn get_events(&self) -> Arc<RwLock<Vec<SessionEvent>>> { pub fn get_message_session(&self) -> MessageSession {
self.events.clone() self.message_session.clone()
}
pub fn get_event_listeners(&self) -> Arc<Mutex<HashMap<Id, mpsc::Sender<()>>>> {
self.event_listeners.clone()
} }
} }

View file

@ -64,7 +64,7 @@ impl VfsSession {
} }
} }
pub fn handle_change(&mut self, change: FileChange) -> Option<()> { pub fn handle_change(&mut self, change: &FileChange) -> Option<()> {
println!("Got file change {:?}", change); println!("Got file change {:?}", change);
match change { match change {

View file

@ -1,21 +1,20 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::{mpsc, RwLock, Mutex, Arc}; use std::sync::{mpsc, RwLock, Arc};
use rouille; use rouille;
use web_util::json_response; use web_util::json_response;
use id::{Id, get_id}; use id::Id;
use rbx::RbxInstance; use rbx::RbxInstance;
use rbx_session::RbxSession; use rbx_session::RbxSession;
use session::SessionEvent; use message_session::{MessageSession, Message};
/// The set of configuration the web server needs to start. /// The set of configuration the web server needs to start.
pub struct WebConfig { pub struct WebConfig {
pub port: u64, pub port: u64,
pub server_id: u64, pub server_id: u64,
pub rbx_session: Arc<RwLock<RbxSession>>, pub rbx_session: Arc<RwLock<RbxSession>>,
pub events: Arc<RwLock<Vec<SessionEvent>>>, pub message_session: MessageSession,
pub event_listeners: Arc<Mutex<HashMap<Id, mpsc::Sender<()>>>>,
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
@ -31,15 +30,15 @@ struct ServerInfoResponse<'a> {
struct ReadAllResponse<'a> { struct ReadAllResponse<'a> {
server_id: &'a str, server_id: &'a str,
instances: &'a HashMap<Id, RbxInstance>, instances: &'a HashMap<Id, RbxInstance>,
event_cursor: i32, message_cursor: i32,
} }
#[derive(Debug, Serialize)] #[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct SubscribeResponse<'a> { struct SubscribeResponse<'a> {
server_id: &'a str, server_id: &'a str,
events: &'a [SessionEvent], messages: &'a [Message],
event_cursor: i32, message_cursor: i32,
} }
/// Start the Rojo web server and park our current thread. /// Start the Rojo web server and park our current thread.
@ -68,46 +67,39 @@ pub fn start(config: WebConfig) {
// Did the client miss any messages since the last subscribe? // Did the client miss any messages since the last subscribe?
{ {
let events = config.events.read().unwrap(); let messages = config.message_session.messages.read().unwrap();
if cursor < events.len() as i32 - 1 { if cursor < messages.len() as i32 - 1 {
let new_events = &events[(cursor + 1) as usize..]; let new_messages = &messages[(cursor + 1) as usize..];
let new_cursor = cursor + new_events.len() as i32; let new_cursor = cursor + new_messages.len() as i32;
return json_response(SubscribeResponse { return json_response(SubscribeResponse {
server_id: &server_id, server_id: &server_id,
events: new_events, messages: new_messages,
event_cursor: new_cursor, message_cursor: new_cursor,
}); });
} }
} }
let sender_id = get_id();
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
{ let sender_id = config.message_session.subscribe(tx);
let mut event_listeners = config.event_listeners.lock().unwrap();
event_listeners.insert(sender_id, tx);
}
match rx.recv() { match rx.recv() {
Ok(_) => (), Ok(_) => (),
Err(_) => return rouille::Response::text("error!").with_status_code(500), Err(_) => return rouille::Response::text("error!").with_status_code(500),
} }
{ config.message_session.unsubscribe(sender_id);
let mut event_listeners = config.event_listeners.lock().unwrap();
event_listeners.remove(&sender_id);
}
{ {
let events = config.events.read().unwrap(); let messages = config.message_session.messages.read().unwrap();
let new_events = &events[(cursor + 1) as usize..]; let new_messages = &messages[(cursor + 1) as usize..];
let new_cursor = cursor + new_events.len() as i32; let new_cursor = cursor + new_messages.len() as i32;
return json_response(SubscribeResponse { return json_response(SubscribeResponse {
server_id: &server_id, server_id: &server_id,
events: new_events, messages: new_messages,
event_cursor: new_cursor, message_cursor: new_cursor,
}); });
} }
}, },
@ -115,14 +107,14 @@ pub fn start(config: WebConfig) {
(GET) (/read_all) => { (GET) (/read_all) => {
let rbx_session = config.rbx_session.read().unwrap(); let rbx_session = config.rbx_session.read().unwrap();
let event_cursor = { let message_cursor = {
let events = config.events.read().unwrap(); let messages = config.message_session.messages.read().unwrap();
events.len() as i32 - 1 messages.len() as i32 - 1
}; };
json_response(ReadAllResponse { json_response(ReadAllResponse {
server_id: &server_id, server_id: &server_id,
event_cursor, message_cursor,
instances: &rbx_session.instances, instances: &rbx_session.instances,
}) })
}, },