diff --git a/src/server/main.rs b/src/server/main.rs index 0d17897..1bf0bfc 100644 --- a/src/server/main.rs +++ b/src/server/main.rs @@ -30,8 +30,8 @@ async fn main() -> Result<(), Box> { info!("Starting server"); Server::builder() - .add_service(WorkspaceService::server(state.clone())) - .add_service(BufferService::server(state.clone())) + .add_service(WorkspaceService::new(state.clone()).server()) + .add_service(BufferService::new(state.clone()).server()) .serve(addr) .await?; diff --git a/src/server/service/buffer.rs b/src/server/service/buffer.rs index fc9a8d3..0da5181 100644 --- a/src/server/service/buffer.rs +++ b/src/server/service/buffer.rs @@ -145,8 +145,11 @@ impl Buffer for BufferService { } impl BufferService { - // TODO is this smart? Should I let main() instantiate servers? - pub fn server(state: Arc) -> BufferServer { - BufferServer::new(BufferService { state }) + pub fn new(state: Arc) -> BufferService { + BufferService { state } + } + + pub fn server(self) -> BufferServer { + BufferServer::new(self) } } diff --git a/src/server/service/workspace.rs b/src/server/service/workspace.rs index 2292d58..3318975 100644 --- a/src/server/service/workspace.rs +++ b/src/server/service/workspace.rs @@ -1,6 +1,8 @@ use std::{pin::Pin, sync::Arc}; -use tracing::{debug, error, info, warn}; +use tonic::codegen::InterceptedService; +use tonic::service::Interceptor; +use tracing::debug; use tokio_stream::wrappers::ReceiverStream; use tonic::{Request, Response, Status}; @@ -15,7 +17,47 @@ use tokio_stream::Stream; // TODO example used this? use proto::workspace_server::{Workspace, WorkspaceServer}; use proto::{BufferList, Event, WorkspaceRequest, WorkspaceResponse, UsersList, BufferRequest}; -use crate::actor::{buffer::Buffer, state::StateManager, workspace::{Workspace as WorkspaceInstance}}; // TODO fuck x2! +use crate::actor::{buffer::Buffer, state::StateManager, workspace::Workspace as WorkspaceInstance}; // TODO fuck x2! + +struct WorkspaceExtension { + id: String +} + +#[derive(Debug, Clone)] +pub struct WorkspaceInterceptor { + state: Arc, +} + +impl Interceptor for WorkspaceInterceptor { + fn call(&mut self, mut req: tonic::Request<()>) -> Result, Status> { + // Set an extension that can be retrieved by `say_hello` + let id; + + // TODO this is kinda spaghetti but I can't borrow immutably and mutably req inside this match + // tree... + match req.metadata().get("workspace") { + Some(value) => { + match value.to_str() { + Ok(w_id) => { + id = w_id.to_string(); + }, + Err(_) => return Err(Status::invalid_argument("Workspace key is not valid")), + } + }, + None => return Err(Status::unauthenticated("No workspace key included in request")) + } + + if !self.state.workspaces.borrow().contains_key(&id) { + return Err(Status::not_found(format!("Workspace '{}' could not be found", id))); + } + + req.extensions_mut().insert(WorkspaceExtension { id }); + Ok(req) + } +} + + + type EventStream = Pin> + Send>>; @@ -33,9 +75,11 @@ impl Workspace for WorkspaceService { request: Request, ) -> Result, Status> { debug!("create request: {:?}", request); + // We should always have an extension because of the interceptor but maybe don't unwrap? + let ext = request.extensions().get::().unwrap(); let r = request.into_inner(); - let _w = WorkspaceInstance::new(r.session_key.clone()); + let _w = WorkspaceInstance::new(ext.id); let reply = WorkspaceResponse { // session_key: r.session_key.clone(), @@ -137,13 +181,31 @@ impl Workspace for WorkspaceService { &self, req: Request, ) -> Result, Status> { - todo!() + let r = req.into_inner(); + match self.state.get(&r.session_key) { + Some(w) => { + let mut out = Vec::new(); + for (_k, v) in w.users.borrow().iter() { + out.push(v.name.clone()); + } + Ok(Response::new(UsersList { name: out })) + }, + None => Err(Status::not_found(format!( + "No active workspace with session_key '{}'", + r.session_key + ))), + } } } impl WorkspaceService { - pub fn server(state: Arc) -> WorkspaceServer { - WorkspaceServer::new(WorkspaceService { state }) + pub fn new(state: Arc) -> WorkspaceService { + WorkspaceService { state } + } + + pub fn server(self) -> InterceptedService, WorkspaceInterceptor> { + let state = self.state.clone(); + WorkspaceServer::with_interceptor(self, WorkspaceInterceptor { state }) } }