mirror of
https://github.com/hexedtech/codemp-nvim.git
synced 2024-11-22 23:44:55 +01:00
feat: did some plumbing for events and cursors channels
This commit is contained in:
parent
495b8279fc
commit
e9500afd55
10 changed files with 219 additions and 90 deletions
|
@ -26,6 +26,7 @@ tokio-stream = "0.1"
|
||||||
rmpv = "1"
|
rmpv = "1"
|
||||||
operational-transform = "0.6"
|
operational-transform = "0.6"
|
||||||
nvim-rs = { version = "0.4", features = ["use_tokio"] } # TODO put this behind a conditional feature
|
nvim-rs = { version = "0.4", features = ["use_tokio"] } # TODO put this behind a conditional feature
|
||||||
|
uuid = { version = "1", features = ["v4", "fast-rng", "macro-diagnostics"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = "0.7"
|
tonic-build = "0.7"
|
||||||
|
|
|
@ -2,8 +2,9 @@ syntax = "proto3";
|
||||||
package session;
|
package session;
|
||||||
|
|
||||||
service Session {
|
service Session {
|
||||||
rpc Authenticate(SessionRequest) returns (SessionResponse);
|
// rpc Authenticate(SessionRequest) returns (SessionResponse);
|
||||||
rpc ListWorkspaces(SessionRequest) returns (WorkspaceList);
|
// rpc ListWorkspaces(SessionRequest) returns (WorkspaceList);
|
||||||
|
rpc CreateWorkspace(WorkspaceBuilderRequest) returns (SessionResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message SessionRequest {
|
message SessionRequest {
|
||||||
|
@ -15,6 +16,10 @@ message SessionResponse {
|
||||||
bool accepted = 2;
|
bool accepted = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message WorkspaceBuilderRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message WorkspaceList {
|
message WorkspaceList {
|
||||||
repeated string name = 1; // TODO add more fields
|
repeated string name = 1; // TODO add more fields
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,19 +2,30 @@ syntax = "proto3";
|
||||||
package workspace;
|
package workspace;
|
||||||
|
|
||||||
service Workspace {
|
service Workspace {
|
||||||
rpc Create (WorkspaceRequest) returns (WorkspaceResponse);
|
rpc Join (JoinRequest) returns (stream WorkspaceEvent);
|
||||||
rpc Subscribe (WorkspaceRequest) returns (stream Event);
|
rpc Subscribe (stream CursorUpdate) returns (stream CursorUpdate);
|
||||||
rpc Buffers (WorkspaceRequest) returns (BufferList);
|
|
||||||
rpc ListUsers (WorkspaceRequest) returns (UsersList);
|
rpc ListUsers (WorkspaceRequest) returns (UsersList);
|
||||||
|
rpc Buffers (WorkspaceRequest) returns (BufferList);
|
||||||
rpc NewBuffer (BufferRequest) returns (WorkspaceResponse);
|
rpc NewBuffer (BufferRequest) returns (WorkspaceResponse);
|
||||||
rpc RemoveBuffer (BufferRequest) returns (WorkspaceResponse);
|
rpc RemoveBuffer (BufferRequest) returns (WorkspaceResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message Event {
|
message JoinRequest {
|
||||||
|
string name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message WorkspaceEvent {
|
||||||
int32 id = 1;
|
int32 id = 1;
|
||||||
optional string body = 2;
|
optional string body = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message CursorUpdate {
|
||||||
|
string username = 1;
|
||||||
|
int32 buffer = 2;
|
||||||
|
int32 col = 3;
|
||||||
|
int32 row = 4;
|
||||||
|
}
|
||||||
|
|
||||||
message WorkspaceRequest {
|
message WorkspaceRequest {
|
||||||
string sessionKey = 1;
|
string sessionKey = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc, fmt::Display};
|
||||||
use tokio::sync::{mpsc, watch};
|
use tokio::sync::{mpsc, watch};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
||||||
|
@ -7,17 +7,31 @@ use crate::actor::workspace::Workspace;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct UserCursor{
|
pub struct UserCursor{
|
||||||
pub buffer: i64,
|
pub buffer: i32,
|
||||||
pub x: i32,
|
pub x: i32,
|
||||||
pub y: i32
|
pub y: i32
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for UserCursor {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "Cursor(buffer:{}, x:{}, y:{})", self.buffer, self.x, self.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub cursor: UserCursor,
|
pub cursor: UserCursor,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for User {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "User(name:{}, cursor:{})", self.name, self.cursor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum WorkspaceAction {
|
enum WorkspaceAction {
|
||||||
ADD {
|
ADD {
|
||||||
|
@ -41,7 +55,7 @@ impl WorkspacesView {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add(&mut self, w: Workspace) {
|
pub async fn add(&mut self, w: Workspace) {
|
||||||
self.op.send(WorkspaceAction::ADD { key: w.name.clone(), w: Box::new(w) }).await.unwrap();
|
self.op.send(WorkspaceAction::ADD { key: w.id.to_string(), w: Box::new(w) }).await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove(&mut self, key: String) {
|
pub async fn remove(&mut self, key: String) {
|
||||||
|
@ -52,8 +66,8 @@ impl WorkspacesView {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StateManager {
|
pub struct StateManager {
|
||||||
pub workspaces: WorkspacesView,
|
pub workspaces: WorkspacesView,
|
||||||
|
pub run: watch::Receiver<bool>,
|
||||||
run_tx: watch::Sender<bool>,
|
run_tx: watch::Sender<bool>,
|
||||||
run_rx: watch::Receiver<bool>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for StateManager {
|
impl Drop for StateManager {
|
||||||
|
@ -72,7 +86,7 @@ impl StateManager {
|
||||||
|
|
||||||
let s = StateManager {
|
let s = StateManager {
|
||||||
workspaces: WorkspacesView { watch: workspaces_rx, op: tx },
|
workspaces: WorkspacesView { watch: workspaces_rx, op: tx },
|
||||||
run_tx, run_rx,
|
run_tx, run: run_rx,
|
||||||
};
|
};
|
||||||
|
|
||||||
s.workspaces_worker(rx, workspaces_tx);
|
s.workspaces_worker(rx, workspaces_tx);
|
||||||
|
@ -81,7 +95,7 @@ impl StateManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workspaces_worker(&self, mut rx: mpsc::Receiver<WorkspaceAction>, tx: watch::Sender<HashMap<String, Arc<Workspace>>>) {
|
fn workspaces_worker(&self, mut rx: mpsc::Receiver<WorkspaceAction>, tx: watch::Sender<HashMap<String, Arc<Workspace>>>) {
|
||||||
let run = self.run_rx.clone();
|
let run = self.run.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut store = HashMap::new();
|
let mut store = HashMap::new();
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ use std::collections::HashMap;
|
||||||
use tokio::sync::{broadcast, mpsc, watch::{self, Ref}};
|
use tokio::sync::{broadcast, mpsc, watch::{self, Ref}};
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::events::Event;
|
use crate::{events::Event, service::workspace::proto::CursorUpdate};
|
||||||
|
|
||||||
use super::{buffer::{BufferView, Buffer}, state::{User, UserCursor}};
|
use super::{buffer::{BufferView, Buffer}, state::{User, UserCursor}};
|
||||||
|
|
||||||
|
@ -66,8 +66,10 @@ impl WorkspaceView {
|
||||||
// Must be clonable, containing references to the actual state maybe? Or maybe give everyone an Arc, idk
|
// Must be clonable, containing references to the actual state maybe? Or maybe give everyone an Arc, idk
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Workspace {
|
pub struct Workspace {
|
||||||
|
pub id: uuid::Uuid,
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub bus: broadcast::Sender<Event>,
|
pub bus: broadcast::Sender<Event>,
|
||||||
|
pub cursors: broadcast::Sender<CursorUpdate>,
|
||||||
|
|
||||||
pub buffers: BuffersTreeView,
|
pub buffers: BuffersTreeView,
|
||||||
pub users: UsersView,
|
pub users: UsersView,
|
||||||
|
@ -90,10 +92,13 @@ impl Workspace {
|
||||||
let (buffer_tx, buffer_rx) = watch::channel::<HashMap<String, BufferView>>(HashMap::new());
|
let (buffer_tx, buffer_rx) = watch::channel::<HashMap<String, BufferView>>(HashMap::new());
|
||||||
let (users_tx, users_rx) = watch::channel(HashMap::new());
|
let (users_tx, users_rx) = watch::channel(HashMap::new());
|
||||||
let (broadcast_tx, _broadcast_rx) = broadcast::channel::<Event>(32);
|
let (broadcast_tx, _broadcast_rx) = broadcast::channel::<Event>(32);
|
||||||
|
let (cursors_tx, _cursors_rx) = broadcast::channel::<CursorUpdate>(32);
|
||||||
|
|
||||||
let w = Workspace {
|
let w = Workspace {
|
||||||
|
id: uuid::Uuid::new_v4(),
|
||||||
name,
|
name,
|
||||||
bus: broadcast_tx,
|
bus: broadcast_tx,
|
||||||
|
cursors: cursors_tx,
|
||||||
buffers: BuffersTreeView{ op: op_buf_tx, watch: buffer_rx },
|
buffers: BuffersTreeView{ op: op_buf_tx, watch: buffer_rx },
|
||||||
users: UsersView{ op: op_usr_tx, watch: users_rx },
|
users: UsersView{ op: op_usr_tx, watch: users_rx },
|
||||||
run_tx,
|
run_tx,
|
||||||
|
@ -137,28 +142,42 @@ impl Workspace {
|
||||||
|
|
||||||
fn users_worker(&self, mut rx: mpsc::Receiver<UserAction>, tx: watch::Sender<HashMap<String, User>>) {
|
fn users_worker(&self, mut rx: mpsc::Receiver<UserAction>, tx: watch::Sender<HashMap<String, User>>) {
|
||||||
let bus = self.bus.clone();
|
let bus = self.bus.clone();
|
||||||
|
let cursors_tx = self.cursors.clone();
|
||||||
let run = self.run_rx.clone();
|
let run = self.run_rx.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
|
let mut cursors_rx = cursors_tx.subscribe();
|
||||||
let mut users : HashMap<String, User> = HashMap::new();
|
let mut users : HashMap<String, User> = HashMap::new();
|
||||||
|
|
||||||
while run.borrow().to_owned() {
|
while run.borrow().to_owned() {
|
||||||
match rx.recv().await.unwrap() {
|
tokio::select!{
|
||||||
|
action = rx.recv() => {
|
||||||
|
match action.unwrap() {
|
||||||
UserAction::ADD { user } => {
|
UserAction::ADD { user } => {
|
||||||
users.insert(user.name.clone(), user);
|
users.insert(user.name.clone(), user.clone());
|
||||||
|
bus.send(Event::UserJoin { user }).unwrap();
|
||||||
},
|
},
|
||||||
UserAction::REMOVE { name } => {
|
UserAction::REMOVE { name } => {
|
||||||
if let None = users.remove(&name) {
|
if let None = users.remove(&name) {
|
||||||
continue; // don't update channel since this was a no-op
|
continue; // don't update channel since this was a no-op
|
||||||
|
} else {
|
||||||
|
bus.send(Event::UserLeave { name }).unwrap();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UserAction::CURSOR { name, cursor } => {
|
UserAction::CURSOR { name, cursor } => {
|
||||||
if let Some(user) = users.get_mut(&name) {
|
if let Some(user) = users.get_mut(&name) {
|
||||||
user.cursor = cursor.clone();
|
user.cursor = cursor.clone();
|
||||||
bus.send(Event::Cursor{user: name, cursor}).unwrap();
|
|
||||||
} else {
|
} else {
|
||||||
continue; // don't update channel since this was a no-op
|
continue; // don't update channel since this was a no-op
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
cursor = cursors_rx.recv() => {
|
||||||
|
let cursor = cursor.unwrap();
|
||||||
|
if let Some(user) = users.get_mut(&cursor.username) {
|
||||||
|
user.cursor = UserCursor { buffer: cursor.buffer, x:cursor.col, y:cursor.row };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tx.send(
|
tx.send(
|
||||||
|
|
|
@ -1,14 +1,25 @@
|
||||||
use crate::actor::state::{User, UserCursor};
|
use std::fmt::Display;
|
||||||
|
use crate::actor::state::User;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
UserJoin { user: User },
|
UserJoin { user: User },
|
||||||
UserLeave { name: String },
|
UserLeave { name: String },
|
||||||
Cursor { user: String, cursor: UserCursor },
|
|
||||||
BufferNew { path: String },
|
BufferNew { path: String },
|
||||||
BufferDelete { path: String },
|
BufferDelete { path: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Event {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::UserJoin { user } => write!(f, "UserJoin(user:{})", user),
|
||||||
|
Self::UserLeave { name } => write!(f, "UserLeave(user:{})", name),
|
||||||
|
Self::BufferNew { path } => write!(f, "BufferNew(path:{})", path),
|
||||||
|
Self::BufferDelete { path } => write!(f, "BufferDelete(path:{})", path),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pub type Event = Box<dyn EventInterface>;
|
// pub type Event = Box<dyn EventInterface>;
|
||||||
//
|
//
|
||||||
// pub trait EventInterface {
|
// pub trait EventInterface {
|
||||||
|
|
|
@ -16,7 +16,7 @@ use tonic::transport::Server;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actor::state::StateManager,
|
actor::state::StateManager,
|
||||||
service::{buffer::BufferService, workspace::WorkspaceService},
|
service::{buffer::BufferService, workspace::WorkspaceService, session::SessionService},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
|
@ -30,6 +30,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
info!("Starting server");
|
info!("Starting server");
|
||||||
|
|
||||||
Server::builder()
|
Server::builder()
|
||||||
|
.add_service(SessionService::new(state.clone()).server())
|
||||||
.add_service(WorkspaceService::new(state.clone()).server())
|
.add_service(WorkspaceService::new(state.clone()).server())
|
||||||
.add_service(BufferService::new(state.clone()).server())
|
.add_service(BufferService::new(state.clone()).server())
|
||||||
.serve(addr)
|
.serve(addr)
|
||||||
|
|
|
@ -8,8 +8,6 @@ use operational_transform::OperationSeq;
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
pub mod proto {
|
pub mod proto {
|
||||||
tonic::include_proto!("session");
|
|
||||||
tonic::include_proto!("workspace");
|
|
||||||
tonic::include_proto!("buffer");
|
tonic::include_proto!("buffer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,23 +4,59 @@ pub mod proto {
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use tracing::debug;
|
use proto::{session_server::{Session}, WorkspaceBuilderRequest, SessionRequest, SessionResponse, WorkspaceList};
|
||||||
|
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status};
|
||||||
|
|
||||||
use proto::session_server::Session;
|
|
||||||
use proto::{SessionRequest, SessionResponse};
|
|
||||||
|
|
||||||
use crate::actor::{
|
use crate::actor::{
|
||||||
state::StateManager,
|
state::StateManager, workspace::Workspace, // TODO fuck x2!
|
||||||
workspace::Workspace as WorkspaceInstance, // TODO fuck x2!
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use self::proto::session_server::SessionServer;
|
||||||
|
|
||||||
|
use super::workspace::WorkspaceExtension;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SessionService {
|
pub struct SessionService {
|
||||||
state: Arc<StateManager>,
|
state: Arc<StateManager>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
// impl Session for SessionService {
|
impl Session for SessionService {
|
||||||
|
async fn create_workspace(
|
||||||
|
&self,
|
||||||
|
req: Request<WorkspaceBuilderRequest>,
|
||||||
|
) -> Result<Response<SessionResponse>, Status> {
|
||||||
|
let name = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
|
|
||||||
|
let w = Workspace::new(name);
|
||||||
|
let res = SessionResponse { accepted:true, session_key: w.id.to_string() };
|
||||||
|
|
||||||
|
self.state.view().add(w).await;
|
||||||
|
Ok(Response::new(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
// async fn authenticate(
|
||||||
|
// &self,
|
||||||
|
// req: Request<SessionRequest>,
|
||||||
|
// ) -> Result<Response<SessionResponse>, Status> {
|
||||||
|
// todo!()
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
// async fn list_workspaces(
|
||||||
|
// &self,
|
||||||
|
// req: Request<SessionRequest>,
|
||||||
|
// ) -> Result<Response<WorkspaceList>, Status> {
|
||||||
|
// todo!()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionService {
|
||||||
|
pub fn new(state: Arc<StateManager>) -> SessionService {
|
||||||
|
SessionService { state }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn server(self) -> SessionServer<SessionService> {
|
||||||
|
SessionServer::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -5,22 +5,23 @@ use tonic::service::Interceptor;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use tokio_stream::wrappers::ReceiverStream;
|
use tokio_stream::wrappers::ReceiverStream;
|
||||||
use tonic::{Request, Response, Status};
|
use tonic::{Request, Response, Status, Streaming};
|
||||||
use tokio::sync::{watch, mpsc};
|
use tokio::sync::{watch, mpsc};
|
||||||
|
|
||||||
pub mod proto {
|
pub mod proto {
|
||||||
tonic::include_proto!("workspace");
|
tonic::include_proto!("workspace");
|
||||||
}
|
}
|
||||||
|
|
||||||
use tokio_stream::Stream; // TODO example used this?
|
use tokio_stream::{Stream, StreamExt}; // TODO example used this?
|
||||||
|
|
||||||
use proto::workspace_server::{Workspace, WorkspaceServer};
|
use proto::workspace_server::{Workspace, WorkspaceServer};
|
||||||
use proto::{BufferList, Event, WorkspaceRequest, WorkspaceResponse, UsersList, BufferRequest};
|
use proto::{BufferList, WorkspaceEvent, WorkspaceRequest, WorkspaceResponse, UsersList, BufferRequest, CursorUpdate, JoinRequest};
|
||||||
|
|
||||||
|
use crate::actor::state::UserCursor;
|
||||||
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 {
|
pub struct WorkspaceExtension {
|
||||||
id: String
|
pub id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -57,9 +58,8 @@ impl Interceptor for WorkspaceInterceptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
type EventStream = Pin<Box<dyn Stream<Item = Result<WorkspaceEvent, Status>> + Send>>;
|
||||||
|
type CursorUpdateStream = Pin<Box<dyn Stream<Item = Result<CursorUpdate, Status>> + Send>>;
|
||||||
type EventStream = Pin<Box<dyn Stream<Item = Result<Event, Status>> + Send>>;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct WorkspaceService {
|
pub struct WorkspaceService {
|
||||||
|
@ -68,52 +68,85 @@ pub struct WorkspaceService {
|
||||||
|
|
||||||
#[tonic::async_trait]
|
#[tonic::async_trait]
|
||||||
impl Workspace for WorkspaceService {
|
impl Workspace for WorkspaceService {
|
||||||
type SubscribeStream = EventStream;
|
type JoinStream = EventStream;
|
||||||
|
type SubscribeStream = CursorUpdateStream;
|
||||||
|
|
||||||
async fn create(
|
async fn join(
|
||||||
&self,
|
&self,
|
||||||
request: Request<WorkspaceRequest>,
|
req: Request<JoinRequest>,
|
||||||
) -> Result<Response<WorkspaceResponse>, Status> {
|
) -> Result<tonic::Response<Self::JoinStream>, Status> {
|
||||||
debug!("create request: {:?}", request);
|
let session_id = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
// We should always have an extension because of the interceptor but maybe don't unwrap?
|
let r = req.into_inner();
|
||||||
let ext = request.extensions().get::<WorkspaceExtension>().unwrap();
|
let run = self.state.run.clone();
|
||||||
let r = request.into_inner();
|
let user_name = r.name.clone();
|
||||||
|
match self.state.get(&session_id) {
|
||||||
let _w = WorkspaceInstance::new(ext.id);
|
Some(w) => {
|
||||||
|
let (tx, rx) = mpsc::channel::<Result<WorkspaceEvent, Status>>(128);
|
||||||
let reply = WorkspaceResponse {
|
tokio::spawn(async move {
|
||||||
// session_key: r.session_key.clone(),
|
let mut event_receiver = w.bus.subscribe();
|
||||||
accepted: true,
|
w.view().users.add(
|
||||||
};
|
crate::actor::state::User {
|
||||||
|
name: r.name.clone(),
|
||||||
// self.tx.send(AlterState::ADD{key: r.session_key.clone(), w}).await.unwrap();
|
cursor: UserCursor { buffer:0, x:0, y:0 }
|
||||||
|
}
|
||||||
Ok(Response::new(reply))
|
);
|
||||||
|
while run.borrow().to_owned() {
|
||||||
|
let res = event_receiver.recv().await.unwrap();
|
||||||
|
let broadcasting = WorkspaceEvent { id: 1, body: Some(res.to_string()) }; // TODO actually process packet
|
||||||
|
tx.send(Ok(broadcasting)).await.unwrap();
|
||||||
|
}
|
||||||
|
w.view().users.remove(user_name);
|
||||||
|
});
|
||||||
|
return Ok(Response::new(Box::pin(ReceiverStream::new(rx))));
|
||||||
|
},
|
||||||
|
None => Err(Status::not_found(format!(
|
||||||
|
"No active workspace with session_key '{}'",
|
||||||
|
session_id
|
||||||
|
)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn subscribe(
|
async fn subscribe(
|
||||||
&self,
|
&self,
|
||||||
req: Request<WorkspaceRequest>,
|
req: tonic::Request<Streaming<CursorUpdate>>,
|
||||||
) -> Result<tonic::Response<EventStream>, Status> {
|
) -> Result<Response<Self::SubscribeStream>, Status> {
|
||||||
let r = req.into_inner();
|
let s_id = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
match self.state.get(&r.session_key) {
|
let mut r = req.into_inner();
|
||||||
|
match self.state.get(&s_id) {
|
||||||
Some(w) => {
|
Some(w) => {
|
||||||
let bus_clone = w.bus.clone();
|
let cursors_ref = w.cursors.clone();
|
||||||
let (_stop_tx, stop_rx) = watch::channel(true);
|
let (_stop_tx, stop_rx) = watch::channel(true);
|
||||||
let (tx, rx) = mpsc::channel::<Result<Event, Status>>(128);
|
let (tx, rx) = mpsc::channel::<Result<CursorUpdate, Status>>(128);
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let mut event_receiver = bus_clone.subscribe();
|
let mut workspace_bus = cursors_ref.subscribe();
|
||||||
while stop_rx.borrow().to_owned() {
|
while stop_rx.borrow().to_owned() {
|
||||||
let _res = event_receiver.recv().await.unwrap();
|
tokio::select!{
|
||||||
let broadcasting = Event { id: 1, body: Some("".to_string()) }; // TODO actually process packet
|
remote = workspace_bus.recv() => {
|
||||||
tx.send(Ok(broadcasting)).await.unwrap();
|
if let Ok(cur) = remote {
|
||||||
|
tx.send(Ok(cur)).await.unwrap();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
local = r.next() => {
|
||||||
|
match local {
|
||||||
|
Some(request) => {
|
||||||
|
match request {
|
||||||
|
Ok(cur) => {
|
||||||
|
cursors_ref.send(cur).unwrap();
|
||||||
|
},
|
||||||
|
Err(e) => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => {},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return Ok(Response::new(Box::pin(ReceiverStream::new(rx))));
|
return Ok(Response::new(Box::pin(ReceiverStream::new(rx))));
|
||||||
},
|
},
|
||||||
None => Err(Status::not_found(format!(
|
None => Err(Status::not_found(format!(
|
||||||
"No active workspace with session_key '{}'",
|
"No active workspace with session_key '{}'",
|
||||||
r.session_key
|
s_id
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -142,8 +175,9 @@ impl Workspace for WorkspaceService {
|
||||||
&self,
|
&self,
|
||||||
req: Request<BufferRequest>,
|
req: Request<BufferRequest>,
|
||||||
) -> Result<Response<WorkspaceResponse>, Status> {
|
) -> Result<Response<WorkspaceResponse>, Status> {
|
||||||
|
let session_id = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
let r = req.into_inner();
|
let r = req.into_inner();
|
||||||
if let Some(w) = self.state.get(&r.session_key) {
|
if let Some(w) = self.state.get(&session_id) {
|
||||||
let mut view = w.view();
|
let mut view = w.view();
|
||||||
let buf = Buffer::new(r.path, w.bus.clone());
|
let buf = Buffer::new(r.path, w.bus.clone());
|
||||||
view.buffers.add(buf).await;
|
view.buffers.add(buf).await;
|
||||||
|
@ -161,13 +195,11 @@ impl Workspace for WorkspaceService {
|
||||||
&self,
|
&self,
|
||||||
req: Request<BufferRequest>,
|
req: Request<BufferRequest>,
|
||||||
) -> Result<Response<WorkspaceResponse>, Status> {
|
) -> Result<Response<WorkspaceResponse>, Status> {
|
||||||
|
let session_id = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
let r = req.into_inner();
|
let r = req.into_inner();
|
||||||
match self.state.get(&r.session_key) {
|
match self.state.get(&session_id) {
|
||||||
Some(w) => {
|
Some(w) => {
|
||||||
let mut out = Vec::new();
|
w.view().buffers.remove(r.path);
|
||||||
for (_k, v) in w.buffers.borrow().iter() {
|
|
||||||
out.push(v.name.clone());
|
|
||||||
}
|
|
||||||
Ok(Response::new(WorkspaceResponse { accepted: true }))
|
Ok(Response::new(WorkspaceResponse { accepted: true }))
|
||||||
}
|
}
|
||||||
None => Err(Status::not_found(format!(
|
None => Err(Status::not_found(format!(
|
||||||
|
@ -181,8 +213,9 @@ impl Workspace for WorkspaceService {
|
||||||
&self,
|
&self,
|
||||||
req: Request<WorkspaceRequest>,
|
req: Request<WorkspaceRequest>,
|
||||||
) -> Result<Response<UsersList>, Status> {
|
) -> Result<Response<UsersList>, Status> {
|
||||||
|
let session_id = req.extensions().get::<WorkspaceExtension>().unwrap().id.clone();
|
||||||
let r = req.into_inner();
|
let r = req.into_inner();
|
||||||
match self.state.get(&r.session_key) {
|
match self.state.get(&session_id) {
|
||||||
Some(w) => {
|
Some(w) => {
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
for (_k, v) in w.users.borrow().iter() {
|
for (_k, v) in w.users.borrow().iter() {
|
||||||
|
|
Loading…
Reference in a new issue