mirror of
https://github.com/hexedtech/codemp.git
synced 2025-03-31 00:21:35 +02:00
153 lines
4.9 KiB
Rust
153 lines
4.9 KiB
Rust
use std::{pin::Pin, sync::{Arc, RwLock}, collections::HashMap};
|
|
|
|
use tokio::sync::{mpsc, broadcast, oneshot};
|
|
use tonic::{Request, Response, Status};
|
|
|
|
use tokio_stream::{Stream, wrappers::ReceiverStream}; // TODO example used this?
|
|
|
|
use codemp::proto::{buffer_server::{Buffer, BufferServer}, RawOp, BufferPayload, BufferResponse, OperationRequest, CursorMov};
|
|
use tracing::info;
|
|
|
|
use super::actor::{BufferHandle, BufferStore};
|
|
|
|
type OperationStream = Pin<Box<dyn Stream<Item = Result<RawOp, Status>> + Send>>;
|
|
type CursorStream = Pin<Box<dyn Stream<Item = Result<CursorMov, Status>> + Send>>;
|
|
|
|
struct BufferMap {
|
|
store: HashMap<String, BufferHandle>,
|
|
}
|
|
|
|
impl From::<HashMap<String, BufferHandle>> for BufferMap {
|
|
fn from(value: HashMap<String, BufferHandle>) -> Self {
|
|
BufferMap { store: value }
|
|
}
|
|
}
|
|
|
|
impl BufferStore<String> for BufferMap {
|
|
fn get(&self, key: &String) -> Option<&BufferHandle> {
|
|
self.store.get(key)
|
|
}
|
|
fn put(&mut self, key: String, handle: BufferHandle) -> Option<BufferHandle> {
|
|
self.store.insert(key, handle)
|
|
}
|
|
}
|
|
|
|
pub struct BufferService {
|
|
map: Arc<RwLock<BufferMap>>,
|
|
cursor: broadcast::Sender<CursorMov>,
|
|
}
|
|
|
|
impl BufferService {
|
|
#[allow(unused)]
|
|
fn get_buffer(&self, path: &String) -> Result<BufferHandle, Status> {
|
|
match self.map.read().unwrap().get(path) {
|
|
Some(buf) => Ok(buf.clone()),
|
|
None => Err(Status::not_found("no buffer for given path")),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[tonic::async_trait]
|
|
impl Buffer for BufferService {
|
|
type AttachStream = OperationStream;
|
|
type ListenStream = CursorStream;
|
|
|
|
async fn attach(&self, req: Request<BufferPayload>) -> Result<Response<OperationStream>, Status> {
|
|
let request = req.into_inner();
|
|
let myself = request.user;
|
|
match self.map.read().unwrap().get(&request.path) {
|
|
None => Err(Status::not_found("path not found")),
|
|
Some(handle) => {
|
|
let (tx, rx) = mpsc::channel(128);
|
|
let mut sub = handle.subscribe();
|
|
tokio::spawn(async move {
|
|
while let Ok(v) = sub.recv().await {
|
|
if v.user == myself { continue }
|
|
tx.send(Ok(v)).await.unwrap(); // TODO unnecessary channel?
|
|
}
|
|
});
|
|
let output_stream = ReceiverStream::new(rx);
|
|
info!("registered new subscriber on buffer");
|
|
Ok(Response::new(Box::pin(output_stream)))
|
|
},
|
|
}
|
|
}
|
|
|
|
async fn listen(&self, req: Request<BufferPayload>) -> Result<Response<CursorStream>, Status> {
|
|
let mut sub = self.cursor.subscribe();
|
|
let myself = req.into_inner().user;
|
|
let (tx, rx) = mpsc::channel(128);
|
|
tokio::spawn(async move {
|
|
while let Ok(v) = sub.recv().await {
|
|
if v.user == myself { continue }
|
|
tx.send(Ok(v)).await.unwrap(); // TODO unnecessary channel?
|
|
}
|
|
});
|
|
let output_stream = ReceiverStream::new(rx);
|
|
info!("registered new subscriber to cursor updates");
|
|
Ok(Response::new(Box::pin(output_stream)))
|
|
}
|
|
|
|
async fn cursor(&self, req:Request<CursorMov>) -> Result<Response<BufferResponse>, Status> {
|
|
match self.cursor.send(req.into_inner()) {
|
|
Ok(_) => Ok(Response::new(BufferResponse { accepted: true, content: None})),
|
|
Err(e) => Err(Status::internal(format!("could not broadcast cursor update: {}", e))),
|
|
}
|
|
}
|
|
|
|
async fn edit(&self, req:Request<OperationRequest>) -> Result<Response<BufferResponse>, Status> {
|
|
let request = req.into_inner();
|
|
let tx = match self.map.read().unwrap().get(&request.path) {
|
|
Some(handle) => {
|
|
// if format!("{:x}", *handle.digest.borrow()) != request.hash {
|
|
// return Ok(Response::new(BufferResponse { accepted : false } ));
|
|
// }
|
|
handle.edit.clone()
|
|
},
|
|
None => return Err(Status::not_found("path not found")),
|
|
};
|
|
info!("sending edit to buffer: {}", request.opseq);
|
|
let (ack, status) = oneshot::channel();
|
|
match tx.send((ack, request)).await {
|
|
Err(e) => Err(Status::internal(format!("error sending edit to buffer actor: {}", e))),
|
|
Ok(()) => Ok(Response::new(BufferResponse {
|
|
accepted: status.await.unwrap_or(false),
|
|
content: None
|
|
}))
|
|
}
|
|
}
|
|
|
|
async fn create(&self, req:Request<BufferPayload>) -> Result<Response<BufferResponse>, Status> {
|
|
let request = req.into_inner();
|
|
let _handle = self.map.write().unwrap().handle(request.path, request.content);
|
|
info!("created new buffer");
|
|
let answ = BufferResponse { accepted: true, content: None };
|
|
Ok(Response::new(answ))
|
|
}
|
|
|
|
async fn sync(&self, req: Request<BufferPayload>) -> Result<Response<BufferResponse>, Status> {
|
|
let request = req.into_inner();
|
|
match self.map.read().unwrap().get(&request.path) {
|
|
None => Err(Status::not_found("requested buffer does not exist")),
|
|
Some(buf) => {
|
|
info!("synching buffer");
|
|
let answ = BufferResponse { accepted: true, content: Some(buf.content.borrow().clone()) };
|
|
Ok(Response::new(answ))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
impl BufferService {
|
|
pub fn new() -> BufferService {
|
|
let (cur_tx, _cur_rx) = broadcast::channel(64); // TODO hardcoded capacity
|
|
BufferService {
|
|
map: Arc::new(RwLock::new(HashMap::new().into())),
|
|
cursor: cur_tx,
|
|
}
|
|
}
|
|
|
|
pub fn server(self) -> BufferServer<BufferService> {
|
|
BufferServer::new(self)
|
|
}
|
|
}
|