diff --git a/Cargo.toml b/Cargo.toml index 838f969..fd90c85 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,30 +10,19 @@ name = "codemp" # core tracing = "0.1" # woot -codemp-woot = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/woot.git", features = ["serde"], tag = "v0.1.2", optional = true } +codemp-woot = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/woot.git", features = ["serde"], tag = "v0.1.2" } # proto -uuid = { version = "1.3.1", features = ["v4"], optional = true } -tonic = { version = "0.9", features = ["tls", "tls-roots"], optional = true } -prost = { version = "0.11.8", optional = true } +codemp-proto = { git = "ssh://git@github.com/codewithotherpeopleandchangenamelater/codemp-proto.git", tag = "v0.6.1" } +uuid = { version = "1.7", features = ["v4"] } +tonic = { version = "0.11.0", features = ["tls", "tls-roots"] } # api -similar = { version = "2.2", features = ["inline"], optional = true } -tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "sync"], optional = true } -async-trait = { version = "0.1", optional = true } +similar = { version = "2.2", features = ["inline"] } +tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "sync"] } +async-trait = { version = "0.1" } # client -md5 = { version = "0.7.0", optional = true } -serde_json = { version = "1", optional = true } -tokio-stream = { version = "0.1", optional = true } +md5 = { version = "0.7.0" } +serde_json = { version = "1" } +tokio-stream = { version = "0.1" } serde = { version = "1.0.193", features = ["derive"] } -dashmap = { version = "5.5.3", optional = true } -postcard = { version = "1.0.8", optional = true } - -[build-dependencies] -tonic-build = "0.9" - -[features] -default = [] -api = ["dep:async-trait"] -woot = ["dep:codemp-woot", "dep:similar"] -proto = ["dep:prost", "dep:tonic", "dep:uuid"] -client = ["proto", "api", "dep:tokio", "dep:tokio-stream", "dep:uuid", "dep:md5", "dep:serde_json", "dep:dashmap", "dep:postcard"] -server = ["proto", "woot"] +dashmap = { version = "5.5.3" } +postcard = { version = "1.0.8" } diff --git a/build.rs b/build.rs deleted file mode 100644 index d4f38c1..0000000 --- a/build.rs +++ /dev/null @@ -1,18 +0,0 @@ -fn main() -> Result<(), Box> { - tonic_build::configure() - // .build_client(cfg!(feature = "client")) - // .build_server(cfg!(feature = "server")) // FIXME if false, build fails???? - // .build_transport(cfg!(feature = "proto")) - .compile( - &[ - "proto/common.proto", - "proto/cursor.proto", - "proto/files.proto", - "proto/auth.proto", - "proto/workspace.proto", - "proto/buffer.proto", - ], - &["proto"], - )?; - Ok(()) - } diff --git a/proto/auth.proto b/proto/auth.proto deleted file mode 100644 index 39f7a20..0000000 --- a/proto/auth.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto2"; - -package auth; - -// authenticates users, issuing tokens -service Auth { - // send credentials and join a workspace, returns ready to use token - rpc Login (WorkspaceJoinRequest) returns (Token); -} - -message Token { - required string token = 1; -} - -// TODO one-request-to-do-it-all from login to workspace access -message WorkspaceJoinRequest { - required string username = 1; - required string password = 2; - optional string workspace_id = 3; -} diff --git a/proto/buffer.proto b/proto/buffer.proto deleted file mode 100644 index e018440..0000000 --- a/proto/buffer.proto +++ /dev/null @@ -1,20 +0,0 @@ -syntax = "proto2"; - -import "common.proto"; - -package buffer; - -// handle buffer changes, keep in sync users -service Buffer { - // attach to a buffer and receive operations - rpc Attach (stream Operation) returns (stream BufferEvent); -} - -message Operation { - required bytes data = 1; -} - -message BufferEvent { - required Operation op = 1; - required common.Identity user = 2; -} diff --git a/proto/common.proto b/proto/common.proto deleted file mode 100644 index 6b7ce31..0000000 --- a/proto/common.proto +++ /dev/null @@ -1,18 +0,0 @@ -syntax = "proto2"; - -package common; - - -// a wrapper payload representing an uuid -message Identity { - // uuid bytes, as string - required string id = 1; -} - -// a collection of identities -message IdentityList { - repeated Identity users = 1; -} - -//generic Empty message -message Empty { } diff --git a/proto/cursor.proto b/proto/cursor.proto deleted file mode 100644 index 0b4861b..0000000 --- a/proto/cursor.proto +++ /dev/null @@ -1,36 +0,0 @@ -syntax = "proto2"; - -package cursor; -import "common.proto"; -import "files.proto"; - -// handle cursor events and broadcast to all users -service Cursor { - // subscribe to a workspace's cursor events - rpc Attach (stream cursor.CursorPosition) returns (stream cursor.CursorEvent); -} - - -// a tuple indicating row and column -message RowCol { - required int32 row = 1; - required int32 col = 2; -} - -// cursor position object -message CursorPosition { - // path of current buffer this cursor is into - required files.BufferNode buffer = 1; - // cursor start position - required RowCol start = 2; - // cursor end position - required RowCol end = 3; -} - -// cursor event, with user id and cursor position -message CursorEvent { - // user moving the cursor - required common.Identity user = 1; - // new cursor position - required CursorPosition position = 2; -} diff --git a/proto/files.proto b/proto/files.proto deleted file mode 100644 index 5df3461..0000000 --- a/proto/files.proto +++ /dev/null @@ -1,11 +0,0 @@ -syntax = "proto2"; - -package files; - -message BufferNode { - required string path = 1; -} - -message BufferTree { - repeated BufferNode buffers = 1; -} diff --git a/proto/workspace.proto b/proto/workspace.proto deleted file mode 100644 index 26eaa04..0000000 --- a/proto/workspace.proto +++ /dev/null @@ -1,54 +0,0 @@ -syntax = "proto2"; - -package workspace; - -import "common.proto"; -import "files.proto"; -import "auth.proto"; - -service Workspace { - rpc Attach (common.Empty) returns (stream WorkspaceEvent); - - rpc CreateBuffer (files.BufferNode) returns (common.Empty); - rpc AccessBuffer (files.BufferNode) returns (BufferCredentials); - rpc DeleteBuffer (files.BufferNode) returns (common.Empty); - - rpc ListBuffers (common.Empty) returns (files.BufferTree); - rpc ListUsers (common.Empty) returns (common.IdentityList); - rpc ListBufferUsers (files.BufferNode) returns (common.IdentityList); -} - -message WorkspaceEvent { - message UserJoin { - required common.Identity user = 1; - } - message UserLeave { - required common.Identity user = 1; - } - message FileCreate { - required string path = 1; - } - message FileRename { - required string before = 1; - required string after = 2; - } - message FileDelete { - required string path = 1; - } - - oneof event { - UserJoin join = 1; - UserLeave leave = 2; - FileCreate create = 3; - FileRename rename = 4; - FileDelete delete = 5; - } -} - -// TODO this is very ugly because we can't just return a new token (which is already smelly but whatev), we also need to tell the underlying id so that -// the client can put it as metadata while attaching, because it can't really know the underlying id that the server is using for each buffer without -// parsing the token itself. meehhhhhh, this bleeds underlying implementation to the upper levels, how can we avoid this?? -message BufferCredentials { - required common.Identity id = 1; - required auth.Token token = 2; -} diff --git a/src/api/change.rs b/src/api/change.rs index c04e18d..b5ece0d 100644 --- a/src/api/change.rs +++ b/src/api/change.rs @@ -3,7 +3,6 @@ //! an editor-friendly representation of a text change in a buffer //! to easily interface with codemp from various editors -#[cfg(feature = "woot")] use crate::woot::{WootResult, woot::Woot, crdt::{TextEditor, CRDT, Op}}; /// an editor-friendly representation of a text change in a buffer @@ -30,7 +29,6 @@ pub struct TextChange { } impl TextChange { - #[cfg(feature = "woot")] /// create a new TextChange from the difference of given strings pub fn from_diff(before: &str, after: &str) -> TextChange { let diff = similar::TextDiff::from_chars(before, after); @@ -61,7 +59,6 @@ impl TextChange { } } - #[cfg(feature = "woot")] /// consume the [TextChange], transforming it into a Vec of [woot::crdt::Op] pub fn transform(self, woot: &Woot) -> WootResult> { let mut out = Vec::new(); @@ -114,12 +111,11 @@ impl TextChange { /// convert from byte index to row and column /// txt must be the whole content of the buffer, in order to count lines - #[cfg(feature = "proto")] - pub fn index_to_rowcol(txt: &str, index: usize) -> crate::proto::cursor::RowCol { + pub fn index_to_rowcol(txt: &str, index: usize) -> codemp_proto::cursor::RowCol { // FIXME might panic, use .get() let row = txt[..index].matches('\n').count() as i32; let col = txt[..index].split('\n').last().unwrap_or("").len() as i32; - crate::proto::cursor::RowCol { row, col } + codemp_proto::cursor::RowCol { row, col } } } diff --git a/src/buffer/worker.rs b/src/buffer/worker.rs index e98ea7c..297c3e1 100644 --- a/src/buffer/worker.rs +++ b/src/buffer/worker.rs @@ -10,7 +10,7 @@ use woot::woot::Woot; use crate::errors::IgnorableError; use crate::api::controller::ControllerWorker; use crate::api::TextChange; -use crate::proto::buffer::{BufferEvent, Operation}; +use codemp_proto::buffer::{BufferEvent, Operation}; use super::controller::BufferController; diff --git a/src/client.rs b/src/client.rs index beb5c26..1f6c361 100644 --- a/src/client.rs +++ b/src/client.rs @@ -12,17 +12,17 @@ use tonic::transport::{Channel, Endpoint}; use tonic::IntoRequest; use uuid::Uuid; -use crate::proto::auth::auth_client::AuthClient; +use codemp_proto::auth::auth_client::AuthClient; +use codemp_proto::{ + common::Empty, + buffer::buffer_client::BufferClient, + cursor::cursor_client::CursorClient, + auth::{Token, WorkspaceJoinRequest}, + workspace::workspace_client::WorkspaceClient, +}; 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 }; diff --git a/src/cursor/controller.rs b/src/cursor/controller.rs index a959b1a..5cc583d 100644 --- a/src/cursor/controller.rs +++ b/src/cursor/controller.rs @@ -5,8 +5,8 @@ use tokio::sync::{mpsc, broadcast::{self, error::{TryRecvError, RecvError}}, Mutex, watch}; use tonic::async_trait; -use crate::{api::Controller, errors::IgnorableError, proto::cursor::{CursorEvent, CursorPosition}}; - +use crate::{api::Controller, errors::IgnorableError}; +use codemp_proto::cursor::{CursorEvent, CursorPosition}; /// the cursor controller implementation /// /// this contains diff --git a/src/cursor/mod.rs b/src/cursor/mod.rs index 59d68f3..ed318dc 100644 --- a/src/cursor/mod.rs +++ b/src/cursor/mod.rs @@ -11,27 +11,3 @@ pub(crate) mod worker; pub mod controller; pub use controller::CursorController as Controller; - -use crate::proto::cursor::RowCol; - -impl From:: for (i32, i32) { - fn from(pos: RowCol) -> (i32, i32) { - (pos.row, pos.col) - } -} - -impl From::<(i32, i32)> for RowCol { - fn from((row, col): (i32, i32)) -> Self { - RowCol { row, col } - } -} - -impl PartialOrd for RowCol { - fn partial_cmp(&self, other: &Self) -> Option { - match self.row.partial_cmp(&other.row) { - Some(core::cmp::Ordering::Equal) => {} - ord => return ord, - } - self.col.partial_cmp(&other.col) - } -} diff --git a/src/cursor/worker.rs b/src/cursor/worker.rs index 3f45dfc..268665d 100644 --- a/src/cursor/worker.rs +++ b/src/cursor/worker.rs @@ -3,7 +3,8 @@ use std::sync::Arc; use tokio::sync::{mpsc, broadcast::{self}, Mutex, watch}; use tonic::{Streaming, async_trait}; -use crate::{api::controller::ControllerWorker, errors::IgnorableError, proto::cursor::{CursorPosition, CursorEvent}}; +use crate::{api::controller::ControllerWorker, errors::IgnorableError}; +use codemp_proto::cursor::{CursorPosition, CursorEvent}; use super::controller::CursorController; diff --git a/src/errors.rs b/src/errors.rs index ac4d616..f4ded8a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -82,7 +82,6 @@ impl Display for Error { } } -#[cfg(feature = "client")] impl From for Error { fn from(status: tonic::Status) -> Self { Error::Transport { @@ -92,7 +91,6 @@ impl From for Error { } } -#[cfg(feature = "client")] impl From for Error { fn from(err: tonic::transport::Error) -> Self { Error::Transport { @@ -102,28 +100,24 @@ impl From for Error { } } -#[cfg(feature = "client")] impl From> for Error { fn from(_value: tokio::sync::mpsc::error::SendError) -> Self { Error::Channel { send: true } } } -#[cfg(feature = "client")] impl From> for Error { fn from(_value: tokio::sync::watch::error::SendError) -> Self { Error::Channel { send: true } } } -#[cfg(feature = "client")] impl From for Error { fn from(_value: tokio::sync::broadcast::error::RecvError) -> Self { Error::Channel { send: false } } } -#[cfg(feature = "client")] impl From for Error { fn from(_value: tokio::sync::watch::error::RecvError) -> Self { Error::Channel { send: false } diff --git a/src/instance.rs b/src/instance.rs index 90397b4..2299738 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -5,22 +5,18 @@ //! the global instance reference is immutable and lazy-loaded, and requires `global` feature. /// static global instance, allocated only if feature `global` is active -#[cfg(feature = "global")] pub mod global { - #[cfg(not(feature = "sync"))] lazy_static::lazy_static! { /// the global instance of codemp session pub static ref INSTANCE : super::a_sync::Instance = super::a_sync::Instance::default(); } - #[cfg(feature = "sync")] lazy_static::lazy_static! { /// the global instance of codemp session pub static ref INSTANCE : super::sync::Instance = super::sync::Instance::default(); } } -#[cfg(feature = "global")] pub use global::INSTANCE; /// async implementation of session instance diff --git a/src/lib.rs b/src/lib.rs index 5421e05..7cd9c06 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,105 +116,33 @@ #![doc(html_no_source)] - /// public traits exposed to clients -#[cfg(feature = "api")] pub mod api; /// cursor related types and controller -#[cfg(feature = "client")] pub mod cursor; /// buffer operations, factory, controller and types -#[cfg(feature = "client")] pub mod buffer; /// crate error types and helpers pub mod errors; /// underlying client session manager -#[cfg(feature = "client")] pub mod client; /// workspace operations -#[cfg(feature = "client")] pub mod workspace; /// all-in-one imports : `use codemp::prelude::*;` pub mod prelude; /// underlying OperationalTransform library used, re-exported -#[cfg(feature = "woot")] pub use woot; -/// protocol types and services auto-generated by grpc -#[cfg(feature = "proto")] -#[allow(non_snake_case)] -pub mod proto { - pub mod common { - tonic::include_proto!("common"); - - impl From for Identity { - fn from(id: uuid::Uuid) -> Self { - Identity { id: id.to_string() } - } - } - - impl From<&uuid::Uuid> for Identity { - fn from(id: &uuid::Uuid) -> Self { - Identity { id: id.to_string() } - } - } - - impl From for uuid::Uuid { - fn from(value: Identity) -> Self { - uuid::Uuid::parse_str(&value.id).expect("invalid uuid in identity") - } - } - - impl From<&Identity> for uuid::Uuid { - fn from(value: &Identity) -> Self { - uuid::Uuid::parse_str(&value.id).expect("invalid uuid in identity") - } - } - } - - - pub mod files { - tonic::include_proto!("files"); - - impl From for BufferNode { - fn from(value: String) -> Self { - BufferNode { path: value } - } - } - - impl From<&str> for BufferNode { - fn from(value: &str) -> Self { - BufferNode { path: value.to_string() } - } - } - - impl From for String { - fn from(value: BufferNode) -> Self { - value.path - } - } - } - - pub mod buffer { tonic::include_proto!("buffer"); } - pub mod cursor { tonic::include_proto!("cursor"); } - pub mod workspace { tonic::include_proto!("workspace"); } - pub mod auth { tonic::include_proto!("auth"); } -} - pub use errors::Error; pub use errors::Result; -#[cfg(feature = "client")] pub use client::Client; -#[cfg(feature = "client")] pub use workspace::Workspace; - - diff --git a/src/prelude.rs b/src/prelude.rs index c01864c..30e46ab 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -7,16 +7,13 @@ pub use crate::{ Result as CodempResult, }; -#[cfg(feature = "woot")] pub use crate::woot::crdt::Op as CodempOp; -#[cfg(feature = "api")] pub use crate::api::{ Controller as CodempController, TextChange as CodempTextChange, }; -#[cfg(feature = "client")] pub use crate::{ // Instance as CodempInstance, client::Client as CodempClient, @@ -25,10 +22,3 @@ pub use crate::{ cursor::Controller as CodempCursorController, buffer::Controller as CodempBufferController, }; - -#[cfg(feature = "proto")] -pub use crate::{ - proto::cursor::CursorPosition as CodempCursorPosition, - proto::cursor::CursorEvent as CodempCursorEvent, - proto::cursor::RowCol as CodempRowCol, -}; diff --git a/src/workspace.rs b/src/workspace.rs index 9c42b23..7f141b7 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -5,8 +5,8 @@ use tonic::Streaming; use uuid::Uuid; use crate::{ api::controller::ControllerWorker, buffer::{self, worker::BufferWorker}, client::Services, cursor, - proto::{auth::Token, common::{Identity, Empty}, files::BufferNode, workspace::{WorkspaceEvent, workspace_event::{Event as WorkspaceEventInner, FileCreate, FileDelete, FileRename, UserJoin, UserLeave}}} }; +use codemp_proto::{auth::Token, common::{Identity, Empty}, files::BufferNode, workspace::{WorkspaceEvent, workspace_event::{Event as WorkspaceEventInner, FileCreate, FileDelete, FileRename, UserJoin, UserLeave}}}; //TODO may contain more info in the future #[derive(Debug, Clone)]