2023-08-20 00:46:55 +02:00
|
|
|
//! ### client
|
2024-01-25 02:13:45 +01:00
|
|
|
//!
|
2023-08-20 00:46:55 +02:00
|
|
|
//! codemp client manager, containing grpc services
|
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
use std::sync::Arc;
|
2024-01-25 16:31:38 +01:00
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
use dashmap::DashMap;
|
|
|
|
use tokio::sync::mpsc;
|
2024-01-25 02:13:45 +01:00
|
|
|
use tonic::service::interceptor::InterceptedService;
|
|
|
|
use tonic::service::Interceptor;
|
|
|
|
use tonic::transport::{Channel, Endpoint};
|
2024-02-07 01:12:05 +01:00
|
|
|
use tonic::IntoRequest;
|
2024-01-25 02:13:45 +01:00
|
|
|
use uuid::Uuid;
|
|
|
|
|
2024-02-07 01:09:28 +01:00
|
|
|
use crate::proto::auth::auth_client::AuthClient;
|
|
|
|
use crate::{
|
|
|
|
api::controller::ControllerWorker,
|
|
|
|
cursor::worker::CursorWorker,
|
|
|
|
proto::{
|
|
|
|
common::Empty,
|
|
|
|
buffer::buffer_client::BufferClient,
|
|
|
|
cursor::cursor_client::CursorClient,
|
|
|
|
auth::{Token, WorkspaceJoinRequest},
|
|
|
|
workspace::workspace_client::WorkspaceClient,
|
|
|
|
},
|
|
|
|
workspace::Workspace
|
|
|
|
};
|
2023-08-16 23:09:47 +02:00
|
|
|
|
2023-08-20 00:46:55 +02:00
|
|
|
/// codemp client manager
|
|
|
|
///
|
|
|
|
/// contains all required grpc services and the unique user id
|
|
|
|
/// will disconnect when dropped
|
|
|
|
/// can be used to interact with server
|
2023-08-17 02:58:55 +02:00
|
|
|
pub struct Client {
|
2024-01-25 02:13:45 +01:00
|
|
|
user_id: Uuid,
|
|
|
|
token_tx: Arc<tokio::sync::watch::Sender<Token>>,
|
2024-02-07 01:12:05 +01:00
|
|
|
workspaces: Arc<DashMap<String, Arc<Workspace>>>,
|
2024-01-25 02:13:45 +01:00
|
|
|
services: Arc<Services>
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
#[derive(Clone)]
|
|
|
|
pub(crate) struct ClientInterceptor {
|
|
|
|
token: tokio::sync::watch::Receiver<Token>
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
impl Interceptor for ClientInterceptor {
|
|
|
|
fn call(&mut self, mut request: tonic::Request<()>) -> Result<tonic::Request<()>, tonic::Status> {
|
|
|
|
if let Ok(token) = self.token.borrow().token.parse() {
|
|
|
|
request.metadata_mut().insert("auth", token);
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(request)
|
|
|
|
}
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub(crate) struct Services {
|
2024-02-07 01:09:28 +01:00
|
|
|
pub(crate) workspace: WorkspaceClient<InterceptedService<Channel, ClientInterceptor>>,
|
|
|
|
pub(crate) buffer: BufferClient<InterceptedService<Channel, ClientInterceptor>>,
|
|
|
|
pub(crate) cursor: CursorClient<InterceptedService<Channel, ClientInterceptor>>,
|
|
|
|
pub(crate) auth: AuthClient<Channel>,
|
2024-01-25 02:13:45 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO meno losco
|
2024-02-07 01:12:05 +01:00
|
|
|
fn parse_codemp_connection_string(string: &str) -> (String, String) {
|
2024-01-25 02:13:45 +01:00
|
|
|
let url = string.replace("codemp://", "");
|
|
|
|
let (host, workspace) = url.split_once('/').unwrap();
|
|
|
|
(format!("http://{}", host), workspace.to_string())
|
|
|
|
}
|
|
|
|
|
2023-08-17 02:58:55 +02:00
|
|
|
impl Client {
|
2023-08-20 00:46:55 +02:00
|
|
|
/// instantiate and connect a new client
|
2024-01-25 16:31:38 +01:00
|
|
|
pub async fn new(dest: &str) -> crate::Result<Self> {
|
2024-01-25 02:13:45 +01:00
|
|
|
let (_host, _workspace_id) = parse_codemp_connection_string(dest);
|
2023-08-16 23:09:47 +02:00
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
let channel = Endpoint::from_shared(dest.to_string())?
|
|
|
|
.connect()
|
|
|
|
.await?;
|
2023-08-16 23:09:47 +02:00
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
let (token_tx, token_rx) = tokio::sync::watch::channel(
|
|
|
|
Token { token: "".to_string() }
|
|
|
|
);
|
2023-08-19 04:02:21 +02:00
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
let inter = ClientInterceptor { token: token_rx };
|
|
|
|
|
|
|
|
let buffer = BufferClient::with_interceptor(channel.clone(), inter.clone());
|
|
|
|
let cursor = CursorClient::with_interceptor(channel.clone(), inter.clone());
|
|
|
|
let workspace = WorkspaceClient::with_interceptor(channel.clone(), inter.clone());
|
2024-02-07 01:12:05 +01:00
|
|
|
let auth = AuthClient::new(channel);
|
2024-01-25 02:13:45 +01:00
|
|
|
|
|
|
|
let user_id = uuid::Uuid::new_v4();
|
2023-08-19 04:02:21 +02:00
|
|
|
|
2024-01-25 02:13:45 +01:00
|
|
|
Ok(Client {
|
|
|
|
user_id,
|
|
|
|
token_tx: Arc::new(token_tx),
|
2024-02-07 01:12:05 +01:00
|
|
|
workspaces: Arc::new(DashMap::default()),
|
|
|
|
services: Arc::new(Services { workspace, buffer, cursor, auth })
|
2024-01-25 02:13:45 +01:00
|
|
|
})
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
|
|
|
|
2024-02-07 01:09:28 +01:00
|
|
|
pub async fn login(&self, username: String, password: String, workspace_id: Option<String>) -> crate::Result<()> {
|
|
|
|
Ok(self.token_tx.send(
|
|
|
|
self.services.auth.clone()
|
|
|
|
.login(WorkspaceJoinRequest { username, password, workspace_id})
|
|
|
|
.await?
|
|
|
|
.into_inner()
|
|
|
|
)?)
|
2024-01-25 16:31:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/// join a workspace, returns an [tokio::sync::RwLock] to interact with it
|
2024-02-07 01:12:05 +01:00
|
|
|
pub async fn join_workspace(&mut self, workspace: &str) -> crate::Result<Arc<Workspace>> {
|
|
|
|
let ws_stream = self.services.workspace.clone().attach(Empty{}.into_request()).await?.into_inner();
|
2024-01-25 02:13:45 +01:00
|
|
|
|
2024-02-07 21:24:31 +01:00
|
|
|
let (tx, rx) = mpsc::channel(256);
|
2024-02-07 01:12:05 +01:00
|
|
|
let cur_stream = self.services.cursor.clone()
|
2024-01-25 02:13:45 +01:00
|
|
|
.attach(tokio_stream::wrappers::ReceiverStream::new(rx))
|
|
|
|
.await?
|
|
|
|
.into_inner();
|
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
let worker = CursorWorker::default();
|
2024-01-25 02:13:45 +01:00
|
|
|
let controller = Arc::new(worker.subscribe());
|
2023-08-16 23:09:47 +02:00
|
|
|
tokio::spawn(async move {
|
2024-01-25 02:13:45 +01:00
|
|
|
tracing::debug!("controller worker started");
|
2024-02-07 01:12:05 +01:00
|
|
|
worker.work(tx, cur_stream).await;
|
2024-01-25 02:13:45 +01:00
|
|
|
tracing::debug!("controller worker stopped");
|
2023-08-16 23:09:47 +02:00
|
|
|
});
|
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
let ws = Arc::new(Workspace::new(
|
|
|
|
workspace.to_string(),
|
|
|
|
self.user_id,
|
|
|
|
self.token_tx.clone(),
|
|
|
|
controller,
|
|
|
|
self.services.clone()
|
2024-01-25 16:31:38 +01:00
|
|
|
));
|
2023-08-16 23:09:47 +02:00
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
ws.fetch_users().await?;
|
|
|
|
ws.fetch_buffers().await?;
|
2024-01-25 16:31:38 +01:00
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
ws.run_actor(ws_stream);
|
2024-01-25 16:31:38 +01:00
|
|
|
|
2024-02-07 01:12:05 +01:00
|
|
|
self.workspaces.insert(workspace.to_string(), ws.clone());
|
|
|
|
|
|
|
|
Ok(ws)
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|
2024-01-25 03:25:45 +01:00
|
|
|
|
2024-02-07 03:47:37 +01:00
|
|
|
pub fn get_workspace(&self, id: &str) -> Option<Arc<Workspace>> {
|
|
|
|
self.workspaces.get(id).map(|x| x.clone())
|
|
|
|
}
|
|
|
|
|
2024-01-25 16:31:38 +01:00
|
|
|
/// accessor for user id
|
2024-01-25 03:25:45 +01:00
|
|
|
pub fn user_id(&self) -> Uuid {
|
2024-02-07 01:12:05 +01:00
|
|
|
self.user_id
|
2024-01-25 03:25:45 +01:00
|
|
|
}
|
2023-08-16 23:09:47 +02:00
|
|
|
}
|