From 95ece68ae69ce39a5ff0ec71a9aa1e966ddbbcd3 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 6 Aug 2024 00:16:52 +0200 Subject: [PATCH 1/5] fix: removed filler error --- src/errors.rs | 5 ----- src/ffi/python.rs | 5 +---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/errors.rs b/src/errors.rs index f4ded8a..4668c24 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -63,11 +63,6 @@ pub enum Error { /// errors caused by wrong interlocking, safe to retry Deadlocked, - - /// if you see these errors someone is being lazy (: - Filler { // TODO filler error, remove later - message: String, - }, } impl StdError for Error {} diff --git a/src/ffi/python.rs b/src/ffi/python.rs index a7563e4..80fb8f4 100644 --- a/src/ffi/python.rs +++ b/src/ffi/python.rs @@ -25,10 +25,7 @@ impl From for PyErr { CodempError::InvalidState { msg } => { PyRuntimeError::new_err(format!("Invalid state: {}", msg)) } - CodempError::Deadlocked => PyRuntimeError::new_err(format!("Deadlock, retry.")), - CodempError::Filler { message } => { - PyBaseException::new_err(format!("Generic error: {}", message)) - } + CodempError::Deadlocked => PyRuntimeError::new_err(format!("Deadlock, retry.")) } } } From e85833a40fb7f818cd6fead28ec3c2764c80f992 Mon Sep 17 00:00:00 2001 From: zaaarf Date: Tue, 6 Aug 2024 23:00:04 +0200 Subject: [PATCH 2/5] chore: migrate errors to thiserror --- Cargo.toml | 11 ++++------- src/errors.rs | 24 +++++++++--------------- 2 files changed, 13 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c5f1c91..d6b38ad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ crate-type = ["cdylib"] [dependencies] # core tracing = "0.1" +thiserror = { version = "1.0.57" } # woot codemp-woot = { git = "ssh://git@github.com/hexedtech/woot.git", features = ["serde"], tag = "v0.1.2" } # proto @@ -34,13 +35,9 @@ tracing-subscriber = { version = "0.3.18", optional = true } # glue (java) jni = { version = "0.21.1", features = ["invocation"], optional = true } -jni-sys = { version = "0.3.0", optional = true } -rifgen = { git = "https://github.com/Kofituo/rifgen.git", rev = "d27d9785b2febcf5527f1deb6a846be5d583f7d7", optional = true } -log = { version = "0.4.21", optional = true } - +#jni-sys = { version = "0.3.0", optional = true } # glue (lua) mlua = { version = "0.9.6", features = ["module", "luajit", "send"], optional = true } -thiserror = { version = "1.0.57", optional = true } derive_more = { version = "0.99.17", optional = true } # glue (js) @@ -64,8 +61,8 @@ pyo3-build-config = { version = "0.19.2", optional = true } [features] default = [] -lua = ["mlua", "thiserror", "derive_more", "lazy_static", "tracing-subscriber"] -java = ["lazy_static", "jni", "jni-sys", "flapigen", "rifgen", "log"] +lua = ["mlua", "derive_more", "lazy_static", "tracing-subscriber"] +java = ["lazy_static", "jni", "tracing-subscriber"] java-artifact = ["java"] # also builds the jar js = ["napi-build", "tracing-subscriber", "rmpv", "napi", "napi-derive", "futures"] python = ["pyo3", "pyo3-asyncio", "tracing-subscriber", "pyo3-build-config"] diff --git a/src/errors.rs b/src/errors.rs index 4668c24..e792dd3 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -2,7 +2,7 @@ //! //! library error helpers and types -use std::{result::Result as StdResult, error::Error as StdError, fmt::Display}; +use std::result::Result as StdResult; use tracing::warn; @@ -45,36 +45,30 @@ pub type Result = StdResult; // TODO split this into specific errors for various parts of the library /// codemp error type for library issues -#[derive(Debug)] +#[derive(Debug, thiserror::Error)] pub enum Error { /// errors caused by tonic http layer + #[error("tonic error (status: {status}, message: {message})")] Transport { status: String, message: String, }, + /// errors caused by async channels + #[error("channel error, send: {send}")] Channel { send: bool }, + /// errors caused by wrong usage of library objects + #[error("invalid state error: {msg}")] InvalidState { msg: String, }, /// errors caused by wrong interlocking, safe to retry - Deadlocked, -} - -impl StdError for Error {} - -impl Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self::Transport { status, message } => write!(f, "Transport error: ({}) {}", status, message), - Self::Channel { send } => write!(f, "Channel error (send:{})", send), - _ => write!(f, "Unknown error"), - } - } + #[error("deadlocked error")] + Deadlocked } impl From for Error { From 05a4c88967538fd2c7218cb52f81cd7e9b43abde Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 6 Aug 2024 23:00:45 +0200 Subject: [PATCH 3/5] fix: controller with 1 generic --- src/api/controller.rs | 5 +---- src/buffer/controller.rs | 2 -- src/cursor/controller.rs | 2 -- 3 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/api/controller.rs b/src/api/controller.rs index 18e5136..12ed35e 100644 --- a/src/api/controller.rs +++ b/src/api/controller.rs @@ -25,14 +25,11 @@ pub(crate) trait ControllerWorker { /// * if async is not feasible a [Controller::poll]/[Controller::try_recv] approach is possible #[async_trait::async_trait] pub trait Controller : Sized + Send + Sync { - /// type of upstream values, used in [Self::send] - type Input; - /// enqueue a new value to be sent to all other users /// /// success or failure of this function does not imply validity of sent operation, /// because it's integrated asynchronously on the background worker - fn send(&self, x: Self::Input) -> Result<()>; + fn send(&self, x: T) -> Result<()>; /// get next value from other users, blocking until one is available /// diff --git a/src/buffer/controller.rs b/src/buffer/controller.rs index 129f492..21dca71 100644 --- a/src/buffer/controller.rs +++ b/src/buffer/controller.rs @@ -77,8 +77,6 @@ impl Drop for StopOnDrop { #[async_trait] impl Controller for BufferController { - type Input = TextChange; - /// block until a text change is available /// this returns immediately if one is already available async fn poll(&self) -> crate::Result<()> { diff --git a/src/cursor/controller.rs b/src/cursor/controller.rs index 320871a..3f579d1 100644 --- a/src/cursor/controller.rs +++ b/src/cursor/controller.rs @@ -67,8 +67,6 @@ impl CursorController { #[async_trait] impl Controller for CursorController { - type Input = Cursor; - /// enqueue a cursor event to be broadcast to current workspace /// will automatically invert cursor start/end if they are inverted fn send(&self, mut cursor: Cursor) -> crate::Result<()> { From cd9a2d6247c0c151d0497574fc4a9fec06630673 Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 6 Aug 2024 23:01:44 +0200 Subject: [PATCH 4/5] fix: lib name is codemp_lua, override addr via env use CODEMP_SERVER_ADDRESS --- src/ffi/lua.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ffi/lua.rs b/src/ffi/lua.rs index 7b5d66f..287f8b8 100644 --- a/src/ffi/lua.rs +++ b/src/ffi/lua.rs @@ -19,8 +19,9 @@ struct GlobalState { impl Default for GlobalState { fn default() -> Self { let rt = Runtime::new().expect("could not create tokio runtime"); + let addr = std::env::var("CODEMP_SERVER_ADDRESS").unwrap_or_else(|_|"http://codemp.alemi.dev:50053".to_string()); let client = rt.block_on( - CodempClient::new("http://codemp.alemi.dev:50053") + CodempClient::new(&addr) ).expect("could not connect to codemp servers"); GlobalState { client: std::sync::RwLock::new(client), runtime: rt } } @@ -248,7 +249,7 @@ fn setup_tracing(_: &Lua, (debug,): (Option,)) -> LuaResult { // define module and exports #[mlua::lua_module] -fn libcodemp(lua: &Lua) -> LuaResult { +fn codemp_lua(lua: &Lua) -> LuaResult { let exports = lua.create_table()?; // core proto functions From 2cc23f2ec24057e886ee9097a54676744e7834cd Mon Sep 17 00:00:00 2001 From: alemi Date: Tue, 6 Aug 2024 23:02:28 +0200 Subject: [PATCH 5/5] feat: lua logger improvements distinct fn for setup and get, setup is idempotent --- src/ffi/lua.rs | 58 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/src/ffi/lua.rs b/src/ffi/lua.rs index 287f8b8..04994a7 100644 --- a/src/ffi/lua.rs +++ b/src/ffi/lua.rs @@ -1,14 +1,18 @@ use std::io::Write; -use std::sync::{mpsc, Arc, Mutex}; +use std::sync::atomic::AtomicBool; +use std::sync::Mutex; use crate::api::Cursor; use crate::prelude::*; use mlua::prelude::*; use tokio::runtime::Runtime; +use tokio::sync::broadcast; lazy_static::lazy_static!{ // TODO use a runtime::Builder::new_current_thread() runtime to not behave like malware static ref STATE : GlobalState = GlobalState::default(); + static ref LOG : broadcast::Sender = broadcast::channel(32).0; + static ref ONCE : AtomicBool = AtomicBool::new(false); } struct GlobalState { @@ -199,36 +203,29 @@ impl LuaUserData for CodempTextChange { // setup library logging to file #[derive(Debug, derive_more::From)] -struct LuaLogger(Arc>>); +struct LuaLogger(broadcast::Receiver); impl LuaUserData for LuaLogger { fn add_methods<'lua, M: LuaUserDataMethods<'lua, Self>>(methods: &mut M) { - methods.add_method("recv", |_, this, ()| { - Ok( - this.0 - .lock() - .expect("logger mutex poisoned") - .recv() - .expect("logger channel closed") - ) + methods.add_method_mut("recv", |_, this, ()| { + Ok(this.0.blocking_recv().expect("logger channel closed")) }); } } #[derive(Debug, Clone)] -struct LuaLoggerProducer(mpsc::Sender); +struct LuaLoggerProducer; impl Write for LuaLoggerProducer { fn write(&mut self, buf: &[u8]) -> std::io::Result { - self.0.send(String::from_utf8_lossy(buf).to_string()) - .expect("could not write on logger channel"); + let _ = LOG.send(String::from_utf8_lossy(buf).to_string()); Ok(buf.len()) } fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } -fn setup_tracing(_: &Lua, (debug,): (Option,)) -> LuaResult { - let (tx, rx) = mpsc::channel(); - let level = if debug.unwrap_or(false) { tracing::Level::DEBUG } else {tracing::Level::INFO }; +fn setup_logger(_: &Lua, (debug, path): (Option, Option)) -> LuaResult<()> { + if ONCE.load(std::sync::atomic::Ordering::Relaxed) { return Ok(()) } + let format = tracing_subscriber::fmt::format() .with_level(true) .with_target(true) @@ -239,12 +236,27 @@ fn setup_tracing(_: &Lua, (debug,): (Option,)) -> LuaResult { .with_line_number(false) .with_source_location(false) .compact(); - tracing_subscriber::fmt() + + let level = if debug.unwrap_or_default() { tracing::Level::DEBUG } else {tracing::Level::INFO }; + + let builder = tracing_subscriber::fmt() .event_format(format) - .with_max_level(level) - .with_writer(Mutex::new(LuaLoggerProducer(tx))) - .init(); - Ok(LuaLogger(Arc::new(Mutex::new(rx)))) + .with_max_level(level); + + if let Some(path) = path { + let logfile = std::fs::File::create(path).expect("failed creating logfile"); + builder.with_writer(Mutex::new(logfile)).init(); + } else { + builder.with_writer(Mutex::new(LuaLoggerProducer)).init(); + } + + ONCE.store(true, std::sync::atomic::Ordering::Relaxed); + Ok(()) +} + +fn get_logger(_: &Lua, (): ()) -> LuaResult { + let sub = LOG.subscribe(); + Ok(LuaLogger(sub)) } // define module and exports @@ -259,9 +271,9 @@ fn codemp_lua(lua: &Lua) -> LuaResult { exports.set("get_workspace", lua.create_function(get_workspace)?)?; // debug exports.set("id", lua.create_function(id)?)?; - exports.set("setup_tracing", lua.create_function(setup_tracing)?)?; + exports.set("get_logger", lua.create_function(get_logger)?)?; + exports.set("setup_logger", lua.create_function(setup_logger)?)?; Ok(exports) } -