mirror of
https://github.com/hexedtech/codemp.git
synced 2025-03-31 16:41:33 +02:00
211 lines
5.6 KiB
Rust
211 lines
5.6 KiB
Rust
use std::{pin::Pin, sync::Arc};
|
|
|
|
use tonic::codegen::InterceptedService;
|
|
use tonic::service::Interceptor;
|
|
use tracing::debug;
|
|
|
|
use tokio_stream::wrappers::ReceiverStream;
|
|
use tonic::{Request, Response, Status};
|
|
use tokio::sync::{watch, mpsc};
|
|
|
|
pub mod proto {
|
|
tonic::include_proto!("workspace");
|
|
}
|
|
|
|
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!
|
|
|
|
struct WorkspaceExtension {
|
|
id: String
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub struct WorkspaceInterceptor {
|
|
state: Arc<StateManager>,
|
|
}
|
|
|
|
impl Interceptor for WorkspaceInterceptor {
|
|
fn call(&mut self, mut req: tonic::Request<()>) -> Result<tonic::Request<()>, 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<Box<dyn Stream<Item = Result<Event, Status>> + Send>>;
|
|
|
|
#[derive(Debug)]
|
|
pub struct WorkspaceService {
|
|
state: Arc<StateManager>,
|
|
}
|
|
|
|
#[tonic::async_trait]
|
|
impl Workspace for WorkspaceService {
|
|
type SubscribeStream = EventStream;
|
|
|
|
async fn create(
|
|
&self,
|
|
request: Request<WorkspaceRequest>,
|
|
) -> Result<Response<WorkspaceResponse>, 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::<WorkspaceExtension>().unwrap();
|
|
let r = request.into_inner();
|
|
|
|
let _w = WorkspaceInstance::new(ext.id);
|
|
|
|
let reply = WorkspaceResponse {
|
|
// session_key: r.session_key.clone(),
|
|
accepted: true,
|
|
};
|
|
|
|
// self.tx.send(AlterState::ADD{key: r.session_key.clone(), w}).await.unwrap();
|
|
|
|
Ok(Response::new(reply))
|
|
}
|
|
|
|
async fn subscribe(
|
|
&self,
|
|
req: Request<WorkspaceRequest>,
|
|
) -> Result<tonic::Response<EventStream>, Status> {
|
|
let r = req.into_inner();
|
|
match self.state.get(&r.session_key) {
|
|
Some(w) => {
|
|
let bus_clone = w.bus.clone();
|
|
let (_stop_tx, stop_rx) = watch::channel(true);
|
|
let (tx, rx) = mpsc::channel::<Result<Event, Status>>(128);
|
|
tokio::spawn(async move {
|
|
let mut event_receiver = bus_clone.subscribe();
|
|
while stop_rx.borrow().to_owned() {
|
|
let _res = event_receiver.recv().await.unwrap();
|
|
let broadcasting = Event { id: 1, body: Some("".to_string()) }; // TODO actually process packet
|
|
tx.send(Ok(broadcasting)).await.unwrap();
|
|
}
|
|
});
|
|
return Ok(Response::new(Box::pin(ReceiverStream::new(rx))));
|
|
},
|
|
None => Err(Status::not_found(format!(
|
|
"No active workspace with session_key '{}'",
|
|
r.session_key
|
|
)))
|
|
}
|
|
}
|
|
|
|
async fn buffers(
|
|
&self,
|
|
req: Request<WorkspaceRequest>,
|
|
) -> Result<Response<BufferList>, Status> {
|
|
let r = req.into_inner();
|
|
match self.state.get(&r.session_key) {
|
|
Some(w) => {
|
|
let mut out = Vec::new();
|
|
for (_k, v) in w.buffers.borrow().iter() {
|
|
out.push(v.name.clone());
|
|
}
|
|
Ok(Response::new(BufferList { path: out }))
|
|
}
|
|
None => Err(Status::not_found(format!(
|
|
"No active workspace with session_key '{}'",
|
|
r.session_key
|
|
))),
|
|
}
|
|
}
|
|
|
|
async fn new_buffer(
|
|
&self,
|
|
req: Request<BufferRequest>,
|
|
) -> Result<Response<WorkspaceResponse>, Status> {
|
|
let r = req.into_inner();
|
|
if let Some(w) = self.state.get(&r.session_key) {
|
|
let mut view = w.view();
|
|
let buf = Buffer::new(r.path, w.bus.clone());
|
|
view.buffers.add(buf).await;
|
|
|
|
Ok(Response::new(WorkspaceResponse { accepted: true }))
|
|
} else {
|
|
return Err(Status::not_found(format!(
|
|
"No active workspace with session_key '{}'",
|
|
r.session_key
|
|
)));
|
|
}
|
|
}
|
|
|
|
async fn remove_buffer(
|
|
&self,
|
|
req: Request<BufferRequest>,
|
|
) -> Result<Response<WorkspaceResponse>, Status> {
|
|
let r = req.into_inner();
|
|
match self.state.get(&r.session_key) {
|
|
Some(w) => {
|
|
let mut out = Vec::new();
|
|
for (_k, v) in w.buffers.borrow().iter() {
|
|
out.push(v.name.clone());
|
|
}
|
|
Ok(Response::new(WorkspaceResponse { accepted: true }))
|
|
}
|
|
None => Err(Status::not_found(format!(
|
|
"No active workspace with session_key '{}'",
|
|
r.session_key
|
|
))),
|
|
}
|
|
}
|
|
|
|
async fn list_users(
|
|
&self,
|
|
req: Request<WorkspaceRequest>,
|
|
) -> Result<Response<UsersList>, Status> {
|
|
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 new(state: Arc<StateManager>) -> WorkspaceService {
|
|
WorkspaceService { state }
|
|
}
|
|
|
|
pub fn server(self) -> InterceptedService<WorkspaceServer<WorkspaceService>, WorkspaceInterceptor> {
|
|
let state = self.state.clone();
|
|
WorkspaceServer::with_interceptor(self, WorkspaceInterceptor { state })
|
|
}
|
|
}
|