mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 07:14:50 +01:00
fix(python): changed entry point. separated logger from driver.
This commit is contained in:
parent
7fc25cd332
commit
487a490887
5 changed files with 92 additions and 89 deletions
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -228,7 +228,7 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codemp"
|
name = "codemp"
|
||||||
version = "0.6.2"
|
version = "0.7.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"codemp-proto",
|
"codemp-proto",
|
||||||
|
@ -254,7 +254,8 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codemp-proto"
|
name = "codemp-proto"
|
||||||
version = "0.6.1"
|
version = "0.7.0"
|
||||||
|
source = "git+ssh://git@github.com/hexedtech/codemp-proto.git?tag=v0.7.0#11cc52e837a2e568c14ef3bc3a70e8124564f5aa"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"prost",
|
"prost",
|
||||||
"tonic",
|
"tonic",
|
||||||
|
|
78
dist/py/codemp.pyi
vendored
78
dist/py/codemp.pyi
vendored
|
@ -8,7 +8,9 @@ class Driver:
|
||||||
def stop(self) -> None: ...
|
def stop(self) -> None: ...
|
||||||
|
|
||||||
|
|
||||||
def init(logger_cb: Callable[[str], None], debug: bool) -> Driver: ...
|
def init() -> Driver: ...
|
||||||
|
def set_logger(logger_cb: Callable[[str], None], debug: bool) -> bool: ...
|
||||||
|
def connect(host: str, username: str, password: str) -> Promise[Client]: ...
|
||||||
|
|
||||||
class Promise[T]:
|
class Promise[T]:
|
||||||
"""
|
"""
|
||||||
|
@ -22,6 +24,41 @@ class Promise[T]:
|
||||||
def wait(self) -> T: ...
|
def wait(self) -> T: ...
|
||||||
def is_done(self) -> bool: ...
|
def is_done(self) -> bool: ...
|
||||||
|
|
||||||
|
class Client:
|
||||||
|
"""
|
||||||
|
Handle to the actual client that manages the session. It manages the connection
|
||||||
|
to a server and joining/creating new workspaces
|
||||||
|
"""
|
||||||
|
def join_workspace(self, workspace: str) -> Promise[Workspace]: ...
|
||||||
|
def create_workspace(self, workspace: str) -> Promise[None]: ...
|
||||||
|
def delete_workspace(self, workspace: str) -> Promise[None]: ...
|
||||||
|
def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ...
|
||||||
|
def list_workspaces(self, owned: bool, invited: bool) -> Promise[list[str]]: ...
|
||||||
|
def leave_workspace(self, workspace: str) -> bool: ...
|
||||||
|
def get_workspace(self, id: str) -> Workspace: ...
|
||||||
|
def active_workspaces(self) -> list[str]: ...
|
||||||
|
def user_id(self) -> str: ...
|
||||||
|
def user_name(self) -> str: ...
|
||||||
|
def refresh(self) -> Promise[None]: ...
|
||||||
|
|
||||||
|
class Workspace:
|
||||||
|
"""
|
||||||
|
Handle to a workspace inside codemp. It manages buffers.
|
||||||
|
A cursor is tied to the single workspace.
|
||||||
|
"""
|
||||||
|
def create(self, path: str) -> Promise[None]: ...
|
||||||
|
def attach(self, path: str) -> Promise[BufferController]: ...
|
||||||
|
def detach(self, path: str) -> bool: ...
|
||||||
|
def fetch_buffers(self) -> Promise[None]: ...
|
||||||
|
def fetch_users(self) -> Promise[None]: ...
|
||||||
|
def list_buffer_users(self, path: str) -> Promise[list[str]]: ...
|
||||||
|
def delete(self, path: str) -> Promise[None]: ...
|
||||||
|
def id(self) -> str: ...
|
||||||
|
def cursor(self) -> CursorController: ...
|
||||||
|
def buffer_by_name(self, path: str) -> Optional[BufferController]: ...
|
||||||
|
def buffer_list(self) -> list[str]: ...
|
||||||
|
def filetree(self, filter: Optional[str]) -> list[str]: ...
|
||||||
|
|
||||||
class TextChange:
|
class TextChange:
|
||||||
"""
|
"""
|
||||||
Editor agnostic representation of a text change, it translate between internal
|
Editor agnostic representation of a text change, it translate between internal
|
||||||
|
@ -85,42 +122,3 @@ class CursorController:
|
||||||
def clear_callback(self) -> None: ...
|
def clear_callback(self) -> None: ...
|
||||||
def stop(self) -> bool: ...
|
def stop(self) -> bool: ...
|
||||||
|
|
||||||
|
|
||||||
class Workspace:
|
|
||||||
"""
|
|
||||||
Handle to a workspace inside codemp. It manages buffers.
|
|
||||||
A cursor is tied to the single workspace.
|
|
||||||
"""
|
|
||||||
def create(self, path: str) -> Promise[None]: ...
|
|
||||||
def attach(self, path: str) -> Promise[BufferController]: ...
|
|
||||||
def detach(self, path: str) -> bool: ...
|
|
||||||
def fetch_buffers(self) -> Promise[None]: ...
|
|
||||||
def fetch_users(self) -> Promise[None]: ...
|
|
||||||
def list_buffer_users(self, path: str) -> Promise[list[str]]: ...
|
|
||||||
def delete(self, path: str) -> Promise[None]: ...
|
|
||||||
def id(self) -> str: ...
|
|
||||||
def cursor(self) -> CursorController: ...
|
|
||||||
def buffer_by_name(self, path: str) -> Optional[BufferController]: ...
|
|
||||||
def buffer_list(self) -> list[str]: ...
|
|
||||||
def filetree(self, filter: Optional[str]) -> list[str]: ...
|
|
||||||
|
|
||||||
|
|
||||||
class Client:
|
|
||||||
"""
|
|
||||||
Handle to the actual client that manages the session. It manages the connection
|
|
||||||
to a server and joining/creating new workspaces
|
|
||||||
"""
|
|
||||||
def __new__(cls,
|
|
||||||
host: str,
|
|
||||||
username: str, password: str) -> Client: ...
|
|
||||||
def join_workspace(self, workspace: str) -> Promise[Workspace]: ...
|
|
||||||
def create_workspace(self, workspace: str) -> Promise[None]: ...
|
|
||||||
def delete_workspace(self, workspace: str) -> Promise[None]: ...
|
|
||||||
def invite_to_workspace(self, workspace: str, username: str) -> Promise[None]: ...
|
|
||||||
def list_workspaces(self, owned: bool, invited: bool) -> Promise[list[str]]: ...
|
|
||||||
def leave_workspace(self, workspace: str) -> bool: ...
|
|
||||||
def get_workspace(self, id: str) -> Workspace: ...
|
|
||||||
def active_workspaces(self) -> list[str]: ...
|
|
||||||
def user_id(self) -> str: ...
|
|
||||||
def user_name(self) -> str: ...
|
|
||||||
def refresh(self) -> Promise[None]: ...
|
|
||||||
|
|
2
dist/py/pyproject.toml
vendored
2
dist/py/pyproject.toml
vendored
|
@ -1,6 +1,6 @@
|
||||||
[project]
|
[project]
|
||||||
name = "codemp"
|
name = "codemp"
|
||||||
version = "0.6.2"
|
version = "0.7.0"
|
||||||
description = "Cooperative multi-player coding"
|
description = "Cooperative multi-player coding"
|
||||||
requires-python = ">=3.8"
|
requires-python = ">=3.8"
|
||||||
license = {file = "../../LICENSE"}
|
license = {file = "../../LICENSE"}
|
||||||
|
|
|
@ -2,25 +2,11 @@ use crate::workspace::Workspace;
|
||||||
use crate::Client;
|
use crate::Client;
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
use super::tokio;
|
|
||||||
|
|
||||||
#[pymethods]
|
#[pymethods]
|
||||||
impl Client {
|
impl Client {
|
||||||
#[new]
|
// #[new]
|
||||||
fn __new__(host: String, username: String, password: String) -> crate::Result<Self> {
|
// fn __new__(host: String, username: String, password: String) -> crate::Result<Self> {
|
||||||
tokio().block_on(Client::connect(host, username, password))
|
// tokio().block_on(Client::connect(host, username, password))
|
||||||
}
|
|
||||||
|
|
||||||
// #[pyo3(name = "join_workspace")]
|
|
||||||
// async fn pyjoin_workspace(&self, workspace: String) -> JoinHandle<crate::Result<Workspace>> {
|
|
||||||
// tracing::info!("attempting to join the workspace {}", workspace);
|
|
||||||
|
|
||||||
// let this = self.clone();
|
|
||||||
// async {
|
|
||||||
// tokio()
|
|
||||||
// .spawn(async move { this.join_workspace(workspace).await })
|
|
||||||
// .await
|
|
||||||
// }
|
|
||||||
// }
|
// }
|
||||||
|
|
||||||
#[pyo3(name = "join_workspace")]
|
#[pyo3(name = "join_workspace")]
|
||||||
|
@ -52,14 +38,24 @@ impl Client {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyo3(name = "invite_to_workspace")]
|
#[pyo3(name = "invite_to_workspace")]
|
||||||
fn pyinvite_to_workspace(&self, py: Python<'_>, workspace: String, user: String) -> PyResult<super::Promise> {
|
fn pyinvite_to_workspace(
|
||||||
|
&self,
|
||||||
|
py: Python<'_>,
|
||||||
|
workspace: String,
|
||||||
|
user: String,
|
||||||
|
) -> PyResult<super::Promise> {
|
||||||
tracing::info!("attempting to invite {user} to workspace {workspace}");
|
tracing::info!("attempting to invite {user} to workspace {workspace}");
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
crate::a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await)
|
crate::a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyo3(name = "list_workspaces")]
|
#[pyo3(name = "list_workspaces")]
|
||||||
fn pylist_workspaces(&self, py: Python<'_>, owned: bool, invited: bool) -> PyResult<super::Promise> {
|
fn pylist_workspaces(
|
||||||
|
&self,
|
||||||
|
py: Python<'_>,
|
||||||
|
owned: bool,
|
||||||
|
invited: bool,
|
||||||
|
) -> PyResult<super::Promise> {
|
||||||
tracing::info!("attempting to list workspaces");
|
tracing::info!("attempting to list workspaces");
|
||||||
let this = self.clone();
|
let this = self.clone();
|
||||||
crate::a_sync_allow_threads!(py, this.list_workspaces(owned, invited).await)
|
crate::a_sync_allow_threads!(py, this.list_workspaces(owned, invited).await)
|
||||||
|
|
|
@ -131,8 +131,30 @@ impl Driver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn init(py: Python, logging_cb: Py<PyFunction>, debug: bool) -> PyResult<Driver> {
|
fn init() -> PyResult<Driver> {
|
||||||
|
let (rt_stop_tx, mut rt_stop_rx) = oneshot::channel::<()>();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
tokio().block_on(async move {
|
||||||
|
tracing::info!("started runtime driver...");
|
||||||
|
tokio::select! {
|
||||||
|
() = std::future::pending::<()>() => {},
|
||||||
|
_ = &mut rt_stop_rx => {}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Driver(Some(rt_stop_tx)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn connect(host: String, username: String, password: String) -> PyResult<Promise> {
|
||||||
|
a_sync!(Client::connect(host, username, password).await)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[pyfunction]
|
||||||
|
fn set_logger(logging_cb: Py<PyFunction>, debug: bool) -> bool {
|
||||||
let (tx, mut rx) = mpsc::unbounded_channel();
|
let (tx, mut rx) = mpsc::unbounded_channel();
|
||||||
let level = if debug {
|
let level = if debug {
|
||||||
tracing::Level::DEBUG
|
tracing::Level::DEBUG
|
||||||
|
@ -151,38 +173,22 @@ fn init(py: Python, logging_cb: Py<PyFunction>, debug: bool) -> PyResult<Driver>
|
||||||
.with_source_location(false)
|
.with_source_location(false)
|
||||||
.compact();
|
.compact();
|
||||||
|
|
||||||
let log_subscribing = tracing_subscriber::fmt()
|
let log_subscribed = tracing_subscriber::fmt()
|
||||||
.with_ansi(false)
|
.with_ansi(false)
|
||||||
.event_format(format)
|
.event_format(format)
|
||||||
.with_max_level(level)
|
.with_max_level(level)
|
||||||
.with_writer(std::sync::Mutex::new(LoggerProducer(tx)))
|
.with_writer(std::sync::Mutex::new(LoggerProducer(tx)))
|
||||||
.try_init();
|
.try_init()
|
||||||
|
.is_ok();
|
||||||
|
|
||||||
let (rt_stop_tx, mut rt_stop_rx) = oneshot::channel::<()>();
|
if log_subscribed {
|
||||||
|
tokio().spawn(async move {
|
||||||
match log_subscribing {
|
while let Some(msg) = rx.recv().await {
|
||||||
Ok(_) => {
|
let _ = Python::with_gil(|py| logging_cb.call1(py, (msg,)));
|
||||||
// the runtime is driven by the logger awaiting messages from codemp and echoing them back to
|
}
|
||||||
// a provided logger.
|
});
|
||||||
py.allow_threads(move || {
|
|
||||||
std::thread::spawn(move || {
|
|
||||||
tokio().block_on(async move {
|
|
||||||
loop {
|
|
||||||
tokio::select! {
|
|
||||||
biased;
|
|
||||||
Some(msg) = rx.recv() => {
|
|
||||||
let _ = Python::with_gil(|py| logging_cb.call1(py, (msg,)));
|
|
||||||
},
|
|
||||||
_ = &mut rt_stop_rx => { break }, // a bit brutal but will do for now.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
});
|
|
||||||
Ok(Driver(Some(rt_stop_tx)))
|
|
||||||
}
|
|
||||||
Err(_) => Err(PyRuntimeError::new_err("codemp was already initialised.")),
|
|
||||||
}
|
}
|
||||||
|
log_subscribed
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<crate::Error> for PyErr {
|
impl From<crate::Error> for PyErr {
|
||||||
|
@ -211,6 +217,8 @@ impl IntoPy<PyObject> for crate::api::User {
|
||||||
#[pymodule]
|
#[pymodule]
|
||||||
fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
fn codemp(m: &Bound<'_, PyModule>) -> PyResult<()> {
|
||||||
m.add_function(wrap_pyfunction!(init, m)?)?;
|
m.add_function(wrap_pyfunction!(init, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(connect, m)?)?;
|
||||||
|
m.add_function(wrap_pyfunction!(set_logger, m)?)?;
|
||||||
m.add_class::<Driver>()?;
|
m.add_class::<Driver>()?;
|
||||||
|
|
||||||
m.add_class::<TextChange>()?;
|
m.add_class::<TextChange>()?;
|
||||||
|
|
Loading…
Reference in a new issue