2023-04-17 14:56:25 +02:00
|
|
|
use std::sync::Arc;
|
2023-04-16 03:24:18 +02:00
|
|
|
|
|
|
|
use operational_transform::OperationSeq;
|
2023-04-17 14:56:25 +02:00
|
|
|
use tonic::{transport::Channel, Status};
|
2023-04-20 04:26:59 +02:00
|
|
|
use tracing::{error, warn, debug};
|
2023-04-17 14:56:25 +02:00
|
|
|
use uuid::Uuid;
|
2023-04-16 03:24:18 +02:00
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
use crate::{
|
2023-07-04 22:54:25 +02:00
|
|
|
cursor::{CursorControllerHandle, CursorControllerWorker, CursorProvider},
|
2023-04-20 03:47:35 +02:00
|
|
|
operation::{OperationProcessor, OperationController},
|
2023-07-05 00:09:09 +02:00
|
|
|
proto::{buffer_client::BufferClient, BufferPayload, OperationRequest}, errors::IgnorableError,
|
2023-04-17 14:56:25 +02:00
|
|
|
};
|
2023-04-11 14:01:11 +02:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
2023-04-17 14:56:25 +02:00
|
|
|
pub struct CodempClient {
|
|
|
|
id: String,
|
2023-04-11 14:01:11 +02:00
|
|
|
client: BufferClient<Channel>,
|
|
|
|
}
|
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
impl From::<BufferClient<Channel>> for CodempClient {
|
|
|
|
fn from(value: BufferClient<Channel>) -> Self {
|
|
|
|
CodempClient { id: Uuid::new_v4().to_string(), client: value }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl CodempClient {
|
2023-07-04 22:54:25 +02:00
|
|
|
pub fn id(&self) -> &str { &self.id }
|
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
pub async fn create(&mut self, path: String, content: Option<String>) -> Result<bool, Status> {
|
2023-04-12 00:32:39 +02:00
|
|
|
let req = BufferPayload {
|
2023-04-16 03:24:18 +02:00
|
|
|
path, content,
|
2023-04-17 14:56:25 +02:00
|
|
|
user: self.id.clone(),
|
2023-04-12 00:32:39 +02:00
|
|
|
};
|
|
|
|
|
2023-04-16 03:24:18 +02:00
|
|
|
let res = self.client.create(req).await?;
|
2023-04-12 00:32:39 +02:00
|
|
|
|
2023-04-16 03:24:18 +02:00
|
|
|
Ok(res.into_inner().accepted)
|
2023-04-11 14:01:11 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 22:54:25 +02:00
|
|
|
pub async fn listen(&mut self) -> Result<CursorControllerHandle, Status> {
|
2023-04-17 14:56:25 +02:00
|
|
|
let req = BufferPayload {
|
|
|
|
path: "".into(),
|
|
|
|
content: None,
|
|
|
|
user: self.id.clone(),
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut stream = self.client.listen(req).await?.into_inner();
|
|
|
|
|
2023-07-04 22:54:25 +02:00
|
|
|
let mut controller = CursorControllerWorker::new(self.id().to_string());
|
|
|
|
let handle = controller.subscribe();
|
|
|
|
let mut _client = self.client.clone();
|
2023-04-17 14:56:25 +02:00
|
|
|
|
|
|
|
tokio::spawn(async move {
|
|
|
|
loop {
|
2023-07-04 22:54:25 +02:00
|
|
|
tokio::select!{
|
|
|
|
res = stream.message() => {
|
|
|
|
match res {
|
|
|
|
Err(e) => break error!("error receiving cursor: {}", e),
|
|
|
|
Ok(None) => break debug!("cursor worker clean exit"),
|
|
|
|
Ok(Some(x)) => { controller.broadcast(x); },
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Some(op) = controller.wait() => {
|
2023-07-05 00:09:09 +02:00
|
|
|
_client.moved(op).await
|
2023-07-04 22:54:25 +02:00
|
|
|
.unwrap_or_warn("could not send cursor update")
|
|
|
|
}
|
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-07-04 22:54:25 +02:00
|
|
|
Ok(handle)
|
2023-04-17 14:56:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn attach(&mut self, path: String) -> Result<Arc<OperationController>, Status> {
|
2023-04-16 03:24:18 +02:00
|
|
|
let req = BufferPayload {
|
2023-04-17 14:56:25 +02:00
|
|
|
path: path.clone(),
|
|
|
|
content: None,
|
|
|
|
user: self.id.clone(),
|
2023-04-16 03:24:18 +02:00
|
|
|
};
|
2023-04-11 14:01:11 +02:00
|
|
|
|
2023-04-16 03:24:18 +02:00
|
|
|
let content = self.client.sync(req.clone())
|
|
|
|
.await?
|
|
|
|
.into_inner()
|
|
|
|
.content;
|
2023-04-11 14:24:40 +02:00
|
|
|
|
2023-04-16 03:24:18 +02:00
|
|
|
let mut stream = self.client.attach(req).await?.into_inner();
|
2023-04-12 16:58:28 +02:00
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
let factory = Arc::new(OperationController::new(content.unwrap_or("".into())));
|
2023-04-12 03:29:42 +02:00
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
let _factory = factory.clone();
|
2023-04-20 04:26:59 +02:00
|
|
|
let _path = path.clone();
|
2023-07-01 14:01:08 +02:00
|
|
|
|
2023-04-12 03:29:42 +02:00
|
|
|
tokio::spawn(async move {
|
2023-04-16 03:24:18 +02:00
|
|
|
loop {
|
2023-04-20 04:26:59 +02:00
|
|
|
if !_factory.run() { break debug!("downstream worker clean exit") }
|
2023-04-16 03:24:18 +02:00
|
|
|
match stream.message().await {
|
2023-07-01 14:01:08 +02:00
|
|
|
Err(e) => break error!("error receiving update: {}", e),
|
|
|
|
Ok(None) => break warn!("stream closed for buffer {}", _path),
|
2023-04-16 03:24:18 +02:00
|
|
|
Ok(Some(x)) => match serde_json::from_str::<OperationSeq>(&x.opseq) {
|
2023-07-01 14:01:08 +02:00
|
|
|
Err(e) => error!("error deserializing opseq: {}", e),
|
2023-07-02 23:59:04 +02:00
|
|
|
Ok(v) => match _factory.process(v) {
|
2023-07-01 14:01:08 +02:00
|
|
|
Err(e) => break error!("could not apply operation from server: {}", e),
|
|
|
|
Ok(_range) => { } // range is obtained awaiting wait(), need to pass the OpSeq itself
|
2023-04-16 03:24:18 +02:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
2023-04-12 03:29:42 +02:00
|
|
|
}
|
|
|
|
});
|
2023-04-11 14:01:11 +02:00
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
let mut _client = self.client.clone();
|
|
|
|
let _uid = self.id.clone();
|
|
|
|
let _factory = factory.clone();
|
|
|
|
let _path = path.clone();
|
2023-04-16 03:24:18 +02:00
|
|
|
tokio::spawn(async move {
|
2023-04-17 14:56:25 +02:00
|
|
|
while let Some(op) = _factory.poll().await {
|
2023-04-20 03:47:35 +02:00
|
|
|
if !_factory.run() { break }
|
2023-04-17 14:56:25 +02:00
|
|
|
let req = OperationRequest {
|
|
|
|
hash: "".into(),
|
|
|
|
opseq: serde_json::to_string(&op).unwrap(),
|
|
|
|
path: _path.clone(),
|
|
|
|
user: _uid.clone(),
|
|
|
|
};
|
|
|
|
match _client.edit(req).await {
|
|
|
|
Ok(res) => match res.into_inner().accepted {
|
|
|
|
true => { _factory.ack().await; },
|
|
|
|
false => {
|
|
|
|
warn!("server rejected operation, retrying in 1s");
|
|
|
|
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
Err(e) => error!("could not send edit: {}", e),
|
|
|
|
}
|
2023-04-11 22:35:37 +02:00
|
|
|
}
|
2023-04-20 04:26:59 +02:00
|
|
|
debug!("upstream worker clean exit");
|
2023-04-16 03:24:18 +02:00
|
|
|
});
|
2023-04-11 22:35:37 +02:00
|
|
|
|
2023-04-17 14:56:25 +02:00
|
|
|
Ok(factory)
|
2023-04-11 14:01:11 +02:00
|
|
|
}
|
|
|
|
}
|