From 4ec99bab365e457e71d4d74ebf135cdb46b5b762 Mon Sep 17 00:00:00 2001 From: alemi Date: Sun, 10 Sep 2023 03:40:31 +0200 Subject: [PATCH] chore: modularized crate into features by default "client" is on so that it works like before but it's possible to cherry pick features out and (for example) only build the grpc proto structs --- Cargo.toml | 35 +++++++++++++++++++++-------------- src/api/controller.rs | 4 ++-- src/errors.rs | 43 +++++++++++++++++++++++++------------------ src/lib.rs | 17 ++++++++++++----- src/prelude.rs | 22 ++++++++++++++++------ 5 files changed, 76 insertions(+), 45 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5d7838f..fc279d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,24 +9,31 @@ name = "codemp" [dependencies] # core tracing = "0.1" -tonic = { version = "0.9", features = ["tls", "tls-roots"] } +# ot +operational-transform = { version = "0.6", features = ["serde"], optional = true } +# proto +tonic = { version = "0.9", features = ["tls", "tls-roots"], optional = true } prost = { version = "0.11.8", optional = true } -md5 = "0.7.0" -uuid = { version = "1.3.1", features = ["v4"] } -operational-transform = { version = "0.6", features = ["serde"] } -tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "sync", "full"], optional = false } -tokio-stream = { version = "0.1", optional = false } -serde = { version = "1", optional = false } -serde_json = { version = "1", optional = false } -tracing-subscriber = { version = "0.3", optional = true } -similar = { version = "2.2", features = ["inline"] } +# api +similar = { version = "2.2", features = ["inline"], optional = true } +tokio = { version = "1.0", features = ["macros", "rt-multi-thread", "sync", "full"], optional = true } +async-trait = { version = "0.1", optional = true } +# client +md5 = { version = "0.7.0", optional = true } +uuid = { version = "1.3.1", features = ["v4"], optional = true } +serde_json = { version = "1", optional = true } +tokio-stream = { version = "0.1", optional = true } +# global lazy_static = { version = "1.4", optional = true } [build-dependencies] tonic-build = "0.9" [features] -default = ["proto"] -proto = ["dep:prost"] -global = ["dep:lazy_static"] -sync = [] +default = ["client"] +api = ["ot", "dep:similar", "dep:tokio", "dep:async-trait"] +ot = ["dep:operational-transform"] +proto = ["dep:prost", "dep:tonic"] +client = ["proto", "api", "dep:tokio", "dep:tokio-stream", "dep:uuid", "dep:md5", "dep:serde_json"] +global = ["client", "dep:lazy_static"] +sync = ["client"] diff --git a/src/api/controller.rs b/src/api/controller.rs index 216407a..d7f3874 100644 --- a/src/api/controller.rs +++ b/src/api/controller.rs @@ -7,7 +7,7 @@ use crate::Result; use std::sync::Arc; use tokio::runtime::Runtime; -#[tonic::async_trait] +#[async_trait::async_trait] pub(crate) trait ControllerWorker { type Controller : Controller; type Tx; @@ -27,7 +27,7 @@ pub(crate) trait ControllerWorker { /// * if possible, prefer a pure [Controller::recv] consumer /// * a second possibility in preference is using a [Controller::callback] /// * if neither is feasible a [Controller::poll]/[Controller::try_recv] approach is available -#[tonic::async_trait] +#[async_trait::async_trait] pub trait Controller : Sized + Send + Sync { /// type of upstream values, used in [Self::send] type Input; diff --git a/src/errors.rs b/src/errors.rs index 58d7806..c076cc8 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -4,8 +4,6 @@ use std::{result::Result as StdResult, error::Error as StdError, fmt::Display}; -use tokio::sync::{mpsc, broadcast, watch}; -use tonic::{Status, Code}; use tracing::warn; /// an error which can be ignored with just a warning entry @@ -51,7 +49,7 @@ pub type Result = StdResult; pub enum Error { /// errors caused by tonic http layer Transport { - status: Code, + status: String, message: String, }, /// errors caused by async channels @@ -81,34 +79,43 @@ impl Display for Error { } } -impl From for Error { - fn from(status: Status) -> Self { - Error::Transport { status: status.code(), message: status.message().to_string() } - } -} - -impl From for Error { - fn from(err: tonic::transport::Error) -> Self { +#[cfg(feature = "client")] +impl From for Error { + fn from(status: tonic::Status) -> Self { Error::Transport { - status: Code::Unknown, message: format!("underlying transport error: {:?}", err) + status: status.code().to_string(), + message: status.message().to_string() } } } -impl From> for Error { - fn from(_value: mpsc::error::SendError) -> Self { +#[cfg(feature = "client")] +impl From for Error { + fn from(err: tonic::transport::Error) -> Self { + Error::Transport { + status: tonic::Code::Unknown.to_string(), + message: format!("underlying transport error: {:?}", err) + } + } +} + +#[cfg(feature = "client")] +impl From> for Error { + fn from(_value: tokio::sync::mpsc::error::SendError) -> Self { Error::Channel { send: true } } } -impl From for Error { - fn from(_value: broadcast::error::RecvError) -> Self { +#[cfg(feature = "client")] +impl From for Error { + fn from(_value: tokio::sync::broadcast::error::RecvError) -> Self { Error::Channel { send: false } } } -impl From for Error { - fn from(_value: watch::error::RecvError) -> Self { +#[cfg(feature = "client")] +impl From for Error { + fn from(_value: tokio::sync::watch::error::RecvError) -> Self { Error::Channel { send: false } } } diff --git a/src/lib.rs b/src/lib.rs index 4a48d0c..fe28ca9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,27 +143,33 @@ /// 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; /// client wrapper to handle memory persistence +#[cfg(feature = "client")] pub mod instance; /// all-in-one imports : `use codemp::prelude::*;` pub mod prelude; /// underlying OperationalTransform library used, re-exported +#[cfg(feature = "ot")] pub use operational_transform as ot; /// protocol types and services auto-generated by grpc @@ -175,11 +181,12 @@ pub mod proto { } - -pub use api::Controller; -pub use client::Client; pub use errors::Error; pub use errors::Result; -#[cfg(feature = "sync")] pub use instance::sync::Instance; -#[cfg(not(feature = "sync"))] pub use instance::a_sync::Instance; + +#[cfg(all(feature = "client", feature = "sync"))] +pub use instance::sync::Instance; + +#[cfg(all(feature = "client", not(feature = "sync")))] +pub use instance::a_sync::Instance; diff --git a/src/prelude.rs b/src/prelude.rs index 40320ff..2c3e5fa 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -5,21 +5,31 @@ pub use crate::{ Error as CodempError, Result as CodempResult, - - Client as CodempClient, +}; + +#[cfg(feature = "ot")] +pub use crate::ot::OperationSeq as CodempOperationSeq; + +#[cfg(feature = "api")] +pub use crate::{ api::Controller as CodempController, api::OperationFactory as CodempOperationFactory, +}; + +#[cfg(feature = "client")] +pub use crate::{ + client::Client as CodempClient, cursor::Controller as CodempCursorController, buffer::Controller as CodempBufferController, - - ot::OperationSeq as CodempOperationSeq, buffer::TextChange as CodempTextChange, + Instance as CodempInstance, +}; +#[cfg(feature = "proto")] +pub use crate::{ proto::CursorPosition as CodempCursorPosition, proto::CursorEvent as CodempCursorEvent, proto::RowCol as CodempRowCol, - - Instance as CodempInstance, }; #[cfg(feature = "global")]