mirror of
https://github.com/hexedtech/codemp.git
synced 2024-11-22 07:14:50 +01:00
Merge pull request #12 from hexedtech/fix-ci-python
New Ci for Windows and no-abi build option for python
This commit is contained in:
commit
d7c4ef3891
13 changed files with 152 additions and 84 deletions
11
.github/workflows/python.yml
vendored
11
.github/workflows/python.yml
vendored
|
@ -89,6 +89,11 @@ jobs:
|
||||||
runs-on: ${{ matrix.platform.runner }}
|
runs-on: ${{ matrix.platform.runner }}
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
versions:
|
||||||
|
- python: 3.8
|
||||||
|
features: py-noabi
|
||||||
|
- python: 3.x
|
||||||
|
features: py
|
||||||
platform:
|
platform:
|
||||||
- runner: windows-latest
|
- runner: windows-latest
|
||||||
target: x64
|
target: x64
|
||||||
|
@ -101,7 +106,7 @@ jobs:
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
- uses: actions/setup-python@v5
|
- uses: actions/setup-python@v5
|
||||||
with:
|
with:
|
||||||
python-version: 3.x
|
python-version: ${{ matrix.versions.python }}
|
||||||
architecture: ${{ matrix.platform.target }}
|
architecture: ${{ matrix.platform.target }}
|
||||||
- name: Build wheels
|
- name: Build wheels
|
||||||
uses: PyO3/maturin-action@v1
|
uses: PyO3/maturin-action@v1
|
||||||
|
@ -109,12 +114,12 @@ jobs:
|
||||||
working-directory: dist/py
|
working-directory: dist/py
|
||||||
target: ${{ matrix.platform.target }}
|
target: ${{ matrix.platform.target }}
|
||||||
container: 'off'
|
container: 'off'
|
||||||
args: --release --out ./build
|
args: --release --out ./build --features ${{ matrix.versions.features }}
|
||||||
sccache: 'true'
|
sccache: 'true'
|
||||||
- name: Upload wheels
|
- name: Upload wheels
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: codemp-py-windows-${{ matrix.platform.target }}
|
name: codemp-${{ matrix.versions.features }}-windows-${{ matrix.platform.target }}
|
||||||
path: dist/py/build
|
path: dist/py/build
|
||||||
|
|
||||||
macos:
|
macos:
|
||||||
|
|
|
@ -50,7 +50,7 @@ napi = { version = "2.16", features = ["full"], optional = true }
|
||||||
napi-derive = { version="2.16", optional = true}
|
napi-derive = { version="2.16", optional = true}
|
||||||
|
|
||||||
# glue (python)
|
# glue (python)
|
||||||
pyo3 = { version = "0.22", features = ["extension-module", "abi3-py38"], optional = true}
|
pyo3 = { version = "0.22", features = ["extension-module"], optional = true}
|
||||||
|
|
||||||
# extra
|
# extra
|
||||||
async-trait = { version = "0.1", optional = true }
|
async-trait = { version = "0.1", optional = true }
|
||||||
|
@ -71,7 +71,8 @@ serialize = ["dep:serde", "uuid/serde"]
|
||||||
rust = [] # used for ci matrix
|
rust = [] # used for ci matrix
|
||||||
java = ["lazy_static", "jni", "tracing-subscriber"]
|
java = ["lazy_static", "jni", "tracing-subscriber"]
|
||||||
js = ["napi-build", "tracing-subscriber", "napi", "napi-derive"]
|
js = ["napi-build", "tracing-subscriber", "napi", "napi-derive"]
|
||||||
py = ["pyo3", "tracing-subscriber", "pyo3-build-config"]
|
py-noabi = ["pyo3", "tracing-subscriber", "pyo3-build-config"]
|
||||||
|
py = ["py-noabi", "pyo3/abi3-py38"]
|
||||||
lua = ["mlua-codemp-patch", "tracing-subscriber", "lazy_static", "serialize"]
|
lua = ["mlua-codemp-patch", "tracing-subscriber", "lazy_static", "serialize"]
|
||||||
lua54 =["lua", "mlua-codemp-patch/lua54"]
|
lua54 =["lua", "mlua-codemp-patch/lua54"]
|
||||||
luajit = ["lua", "mlua-codemp-patch/luajit"]
|
luajit = ["lua", "mlua-codemp-patch/luajit"]
|
||||||
|
|
4
build.rs
4
build.rs
|
@ -1,7 +1,7 @@
|
||||||
#[cfg(feature = "js")]
|
#[cfg(feature = "js")]
|
||||||
extern crate napi_build;
|
extern crate napi_build;
|
||||||
|
|
||||||
#[cfg(feature = "py")]
|
#[cfg(any(feature = "py", feature = "py-noabi"))]
|
||||||
extern crate pyo3_build_config;
|
extern crate pyo3_build_config;
|
||||||
|
|
||||||
/// The main method of the buildscript, required by some glue modules.
|
/// The main method of the buildscript, required by some glue modules.
|
||||||
|
@ -11,7 +11,7 @@ fn main() {
|
||||||
napi_build::setup();
|
napi_build::setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "py")]
|
#[cfg(any(feature = "py", feature = "py-noabi"))]
|
||||||
{
|
{
|
||||||
pyo3_build_config::add_extension_module_link_args();
|
pyo3_build_config::add_extension_module_link_args();
|
||||||
}
|
}
|
||||||
|
|
6
dist/py/pyproject.toml
vendored
6
dist/py/pyproject.toml
vendored
|
@ -1,8 +1,8 @@
|
||||||
[project]
|
[project]
|
||||||
name = "codemp"
|
name = "codemp"
|
||||||
version = "0.7.0"
|
version = "0.7.1"
|
||||||
description = "code multiplexer"
|
description = "code multiplexer"
|
||||||
requires-python = ">= 3.8"
|
requires-python = ">=3.8"
|
||||||
license = "GPL-3.0-only"
|
license = "GPL-3.0-only"
|
||||||
keywords = ["codemp", "cooperative", "rust", "python"]
|
keywords = ["codemp", "cooperative", "rust", "python"]
|
||||||
authors = [
|
authors = [
|
||||||
|
@ -28,7 +28,7 @@ requires = ["maturin>=1.0,<2.0"]
|
||||||
build-backend = "maturin"
|
build-backend = "maturin"
|
||||||
|
|
||||||
[tool.maturin]
|
[tool.maturin]
|
||||||
features = ["py", "pyo3/extension-module"]
|
features = ["py"]
|
||||||
manifest-path = "../../Cargo.toml"
|
manifest-path = "../../Cargo.toml"
|
||||||
python-source = "src"
|
python-source = "src"
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
///
|
///
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
#[cfg_attr(feature = "js", napi_derive::napi(object))]
|
#[cfg_attr(feature = "js", napi_derive::napi(object))]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass(get_all))]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass(get_all))]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct TextChange {
|
pub struct TextChange {
|
||||||
/// Range start of text change, as char indexes in buffer previous state.
|
/// Range start of text change, as char indexes in buffer previous state.
|
||||||
|
@ -43,7 +43,7 @@ impl TextChange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "py", pyo3::pymethods)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pymethods)]
|
||||||
impl TextChange {
|
impl TextChange {
|
||||||
/// Returns true if this [`TextChange`] deletes existing text.
|
/// Returns true if this [`TextChange`] deletes existing text.
|
||||||
///
|
///
|
||||||
|
|
|
@ -10,7 +10,10 @@
|
||||||
/// http{tls?'s':''}://{host}:{port}
|
/// http{tls?'s':''}://{host}:{port}
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
#[cfg_attr(feature = "js", napi_derive::napi(object))]
|
#[cfg_attr(feature = "js", napi_derive::napi(object))]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass(get_all, set_all))]
|
#[cfg_attr(
|
||||||
|
any(feature = "py", feature = "py-noabi"),
|
||||||
|
pyo3::pyclass(get_all, set_all)
|
||||||
|
)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// user identifier used to register, possibly your email
|
/// user identifier used to register, possibly your email
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
//! ### Cursor
|
//! ### Cursor
|
||||||
//! Represents the position of a remote user's cursor.
|
//! Represents the position of a remote user's cursor.
|
||||||
|
|
||||||
#[cfg(feature = "py")]
|
#[cfg(any(feature = "py", feature = "py-noabi"))]
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
/// User cursor position in a buffer
|
/// User cursor position in a buffer
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
#[cfg_attr(feature = "py", pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyclass)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
// #[cfg_attr(feature = "py", pyo3(crate = "reexported::pyo3"))]
|
// #[cfg_attr(feature = "py", pyo3(crate = "reexported::pyo3"))]
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
|
|
|
@ -4,7 +4,7 @@ use codemp_proto::workspace::workspace_event::Event as WorkspaceEventInner;
|
||||||
|
|
||||||
/// Event in a [crate::Workspace].
|
/// Event in a [crate::Workspace].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
|
||||||
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
/// Fired when the file tree changes.
|
/// Fired when the file tree changes.
|
||||||
|
|
|
@ -18,7 +18,7 @@ use super::worker::DeltaRequest;
|
||||||
/// Each buffer controller internally tracks the last acknowledged state, remaining always in sync
|
/// Each buffer controller internally tracks the last acknowledged state, remaining always in sync
|
||||||
/// with the server while allowing to procedurally receive changes while still sending new ones.
|
/// with the server while allowing to procedurally receive changes while still sending new ones.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
|
||||||
#[cfg_attr(feature = "js", napi_derive::napi)]
|
#[cfg_attr(feature = "js", napi_derive::napi)]
|
||||||
pub struct BufferController(pub(crate) Arc<BufferControllerInner>);
|
pub struct BufferController(pub(crate) Arc<BufferControllerInner>);
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,25 @@
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use tonic::{service::interceptor::InterceptedService, transport::{Channel, Endpoint}};
|
use tonic::{
|
||||||
|
service::interceptor::InterceptedService,
|
||||||
use crate::{api::User, errors::{ConnectionResult, RemoteResult}, ext::InternallyMutable, network, workspace::Workspace};
|
transport::{Channel, Endpoint},
|
||||||
use codemp_proto::{
|
|
||||||
auth::{auth_client::AuthClient, LoginRequest},
|
|
||||||
common::{Empty, Token}, session::{session_client::SessionClient, InviteRequest, WorkspaceRequest},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "py")]
|
use crate::{
|
||||||
|
api::User,
|
||||||
|
errors::{ConnectionResult, RemoteResult},
|
||||||
|
ext::InternallyMutable,
|
||||||
|
network,
|
||||||
|
workspace::Workspace,
|
||||||
|
};
|
||||||
|
use codemp_proto::{
|
||||||
|
auth::{auth_client::AuthClient, LoginRequest},
|
||||||
|
common::{Empty, Token},
|
||||||
|
session::{session_client::SessionClient, InviteRequest, WorkspaceRequest},
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "py", feature = "py-noabi"))]
|
||||||
use pyo3::prelude::*;
|
use pyo3::prelude::*;
|
||||||
|
|
||||||
/// A `codemp` client handle.
|
/// A `codemp` client handle.
|
||||||
|
@ -22,7 +32,7 @@ use pyo3::prelude::*;
|
||||||
/// A new [`Client`] can be obtained with [`Client::connect`].
|
/// A new [`Client`] can be obtained with [`Client::connect`].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "js", napi_derive::napi)]
|
#[cfg_attr(feature = "js", napi_derive::napi)]
|
||||||
#[cfg_attr(feature = "py", pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyclass)]
|
||||||
pub struct Client(Arc<ClientInner>);
|
pub struct Client(Arc<ClientInner>);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -42,30 +52,37 @@ impl Client {
|
||||||
let channel = Endpoint::from_shared(config.endpoint())?.connect().await?;
|
let channel = Endpoint::from_shared(config.endpoint())?.connect().await?;
|
||||||
let mut auth = AuthClient::new(channel.clone());
|
let mut auth = AuthClient::new(channel.clone());
|
||||||
|
|
||||||
let resp = auth.login(LoginRequest {
|
let resp = auth
|
||||||
username: config.username.clone(),
|
.login(LoginRequest {
|
||||||
password: config.password.clone(),
|
username: config.username.clone(),
|
||||||
})
|
password: config.password.clone(),
|
||||||
|
})
|
||||||
.await?
|
.await?
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
let claims = InternallyMutable::new(resp.token);
|
let claims = InternallyMutable::new(resp.token);
|
||||||
|
|
||||||
// TODO move this one into network.rs
|
// TODO move this one into network.rs
|
||||||
let session = SessionClient::with_interceptor(
|
let session =
|
||||||
channel, network::SessionInterceptor(claims.channel())
|
SessionClient::with_interceptor(channel, network::SessionInterceptor(claims.channel()));
|
||||||
);
|
|
||||||
|
|
||||||
Ok(Client(Arc::new(ClientInner {
|
Ok(Client(Arc::new(ClientInner {
|
||||||
user: resp.user.into(),
|
user: resp.user.into(),
|
||||||
workspaces: DashMap::default(),
|
workspaces: DashMap::default(),
|
||||||
claims, auth, session, config
|
claims,
|
||||||
|
auth,
|
||||||
|
session,
|
||||||
|
config,
|
||||||
})))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Refresh session token.
|
/// Refresh session token.
|
||||||
pub async fn refresh(&self) -> RemoteResult<()> {
|
pub async fn refresh(&self) -> RemoteResult<()> {
|
||||||
let new_token = self.0.auth.clone().refresh(self.0.claims.get())
|
let new_token = self
|
||||||
|
.0
|
||||||
|
.auth
|
||||||
|
.clone()
|
||||||
|
.refresh(self.0.claims.get())
|
||||||
.await?
|
.await?
|
||||||
.into_inner();
|
.into_inner();
|
||||||
self.0.claims.set(new_token);
|
self.0.claims.set(new_token);
|
||||||
|
@ -74,25 +91,36 @@ impl Client {
|
||||||
|
|
||||||
/// Attempt to create a new workspace with given name.
|
/// Attempt to create a new workspace with given name.
|
||||||
pub async fn create_workspace(&self, name: impl AsRef<str>) -> RemoteResult<()> {
|
pub async fn create_workspace(&self, name: impl AsRef<str>) -> RemoteResult<()> {
|
||||||
self.0.session
|
self.0
|
||||||
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
.create_workspace(WorkspaceRequest { workspace: name.as_ref().to_string() })
|
.create_workspace(WorkspaceRequest {
|
||||||
|
workspace: name.as_ref().to_string(),
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Delete an existing workspace if possible.
|
/// Delete an existing workspace if possible.
|
||||||
pub async fn delete_workspace(&self, name: impl AsRef<str>) -> RemoteResult<()> {
|
pub async fn delete_workspace(&self, name: impl AsRef<str>) -> RemoteResult<()> {
|
||||||
self.0.session
|
self.0
|
||||||
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
.delete_workspace(WorkspaceRequest { workspace: name.as_ref().to_string() })
|
.delete_workspace(WorkspaceRequest {
|
||||||
|
workspace: name.as_ref().to_string(),
|
||||||
|
})
|
||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invite user with given username to the given workspace, if possible.
|
/// Invite user with given username to the given workspace, if possible.
|
||||||
pub async fn invite_to_workspace(&self, workspace_name: impl AsRef<str>, user_name: impl AsRef<str>) -> RemoteResult<()> {
|
pub async fn invite_to_workspace(
|
||||||
self.0.session
|
&self,
|
||||||
|
workspace_name: impl AsRef<str>,
|
||||||
|
user_name: impl AsRef<str>,
|
||||||
|
) -> RemoteResult<()> {
|
||||||
|
self.0
|
||||||
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
.invite_to_workspace(InviteRequest {
|
.invite_to_workspace(InviteRequest {
|
||||||
workspace: workspace_name.as_ref().to_string(),
|
workspace: workspace_name.as_ref().to_string(),
|
||||||
|
@ -104,7 +132,9 @@ impl Client {
|
||||||
|
|
||||||
/// List all available workspaces, also filtering between those owned and those invited to.
|
/// List all available workspaces, also filtering between those owned and those invited to.
|
||||||
pub async fn list_workspaces(&self, owned: bool, invited: bool) -> RemoteResult<Vec<String>> {
|
pub async fn list_workspaces(&self, owned: bool, invited: bool) -> RemoteResult<Vec<String>> {
|
||||||
let mut workspaces = self.0.session
|
let mut workspaces = self
|
||||||
|
.0
|
||||||
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
.list_workspaces(Empty {})
|
.list_workspaces(Empty {})
|
||||||
.await?
|
.await?
|
||||||
|
@ -112,17 +142,25 @@ impl Client {
|
||||||
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
|
|
||||||
if owned { out.append(&mut workspaces.owned) }
|
if owned {
|
||||||
if invited { out.append(&mut workspaces.invited) }
|
out.append(&mut workspaces.owned)
|
||||||
|
}
|
||||||
|
if invited {
|
||||||
|
out.append(&mut workspaces.invited)
|
||||||
|
}
|
||||||
|
|
||||||
Ok(out)
|
Ok(out)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Join and return a [`Workspace`].
|
/// Join and return a [`Workspace`].
|
||||||
pub async fn join_workspace(&self, workspace: impl AsRef<str>) -> ConnectionResult<Workspace> {
|
pub async fn join_workspace(&self, workspace: impl AsRef<str>) -> ConnectionResult<Workspace> {
|
||||||
let token = self.0.session
|
let token = self
|
||||||
|
.0
|
||||||
|
.session
|
||||||
.clone()
|
.clone()
|
||||||
.access_workspace(WorkspaceRequest { workspace: workspace.as_ref().to_string() })
|
.access_workspace(WorkspaceRequest {
|
||||||
|
workspace: workspace.as_ref().to_string(),
|
||||||
|
})
|
||||||
.await?
|
.await?
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,20 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use tokio::sync::{mpsc, oneshot, watch};
|
use tokio::sync::{mpsc, oneshot, watch};
|
||||||
|
|
||||||
use crate::{api::{controller::ControllerCallback, Controller, Cursor}, errors::ControllerResult};
|
use crate::{
|
||||||
use codemp_proto::{cursor::{CursorPosition, RowCol}, files::BufferNode};
|
api::{controller::ControllerCallback, Controller, Cursor},
|
||||||
|
errors::ControllerResult,
|
||||||
|
};
|
||||||
|
use codemp_proto::{
|
||||||
|
cursor::{CursorPosition, RowCol},
|
||||||
|
files::BufferNode,
|
||||||
|
};
|
||||||
|
|
||||||
/// A [Controller] for asynchronously sending and receiving [Cursor] event.
|
/// A [Controller] for asynchronously sending and receiving [Cursor] event.
|
||||||
///
|
///
|
||||||
/// An unique [CursorController] exists for each active [crate::Workspace].
|
/// An unique [CursorController] exists for each active [crate::Workspace].
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
|
||||||
#[cfg_attr(feature = "js", napi_derive::napi)]
|
#[cfg_attr(feature = "js", napi_derive::napi)]
|
||||||
pub struct CursorController(pub(crate) Arc<CursorControllerInner>);
|
pub struct CursorController(pub(crate) Arc<CursorControllerInner>);
|
||||||
|
|
||||||
|
@ -31,11 +37,23 @@ impl Controller<Cursor> for CursorController {
|
||||||
if cursor.start > cursor.end {
|
if cursor.start > cursor.end {
|
||||||
std::mem::swap(&mut cursor.start, &mut cursor.end);
|
std::mem::swap(&mut cursor.start, &mut cursor.end);
|
||||||
}
|
}
|
||||||
Ok(self.0.op.send(CursorPosition {
|
Ok(self
|
||||||
buffer: BufferNode { path: cursor.buffer },
|
.0
|
||||||
start: RowCol { row: cursor.start.0, col: cursor.start.1 },
|
.op
|
||||||
end: RowCol { row: cursor.end.0, col: cursor.end.1 },
|
.send(CursorPosition {
|
||||||
}).await?)
|
buffer: BufferNode {
|
||||||
|
path: cursor.buffer,
|
||||||
|
},
|
||||||
|
start: RowCol {
|
||||||
|
row: cursor.start.0,
|
||||||
|
col: cursor.start.1,
|
||||||
|
},
|
||||||
|
end: RowCol {
|
||||||
|
row: cursor.end.0,
|
||||||
|
col: cursor.end.1,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn try_recv(&self) -> ControllerResult<Option<Cursor>> {
|
async fn try_recv(&self) -> ControllerResult<Option<Cursor>> {
|
||||||
|
|
|
@ -56,5 +56,5 @@ pub mod lua;
|
||||||
pub mod js;
|
pub mod js;
|
||||||
|
|
||||||
/// python bindings, built with [pyo3]
|
/// python bindings, built with [pyo3]
|
||||||
#[cfg(feature = "py")]
|
#[cfg(any(feature = "py", feature = "py-noabi"))]
|
||||||
pub mod python;
|
pub mod python;
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
||||||
cursor::{self, worker::CursorWorker},
|
cursor::{self, worker::CursorWorker},
|
||||||
errors::{ConnectionResult, ControllerResult, RemoteResult},
|
errors::{ConnectionResult, ControllerResult, RemoteResult},
|
||||||
ext::InternallyMutable,
|
ext::InternallyMutable,
|
||||||
network::Services
|
network::Services,
|
||||||
};
|
};
|
||||||
|
|
||||||
use codemp_proto::{
|
use codemp_proto::{
|
||||||
|
@ -33,7 +33,7 @@ use uuid::Uuid;
|
||||||
use napi_derive::napi;
|
use napi_derive::napi;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass)]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass)]
|
||||||
#[cfg_attr(feature = "js", napi)]
|
#[cfg_attr(feature = "js", napi)]
|
||||||
pub struct Workspace(Arc<WorkspaceInner>);
|
pub struct Workspace(Arc<WorkspaceInner>);
|
||||||
|
|
||||||
|
@ -59,7 +59,8 @@ impl Workspace {
|
||||||
claims: tokio::sync::watch::Receiver<codemp_proto::common::Token>, // TODO ughh receiving this
|
claims: tokio::sync::watch::Receiver<codemp_proto::common::Token>, // TODO ughh receiving this
|
||||||
) -> ConnectionResult<Self> {
|
) -> ConnectionResult<Self> {
|
||||||
let workspace_claim = InternallyMutable::new(token);
|
let workspace_claim = InternallyMutable::new(token);
|
||||||
let services = Services::try_new(&config.endpoint(), claims, workspace_claim.channel()).await?;
|
let services =
|
||||||
|
Services::try_new(&config.endpoint(), claims, workspace_claim.channel()).await?;
|
||||||
let ws_stream = services.ws().attach(Empty {}).await?.into_inner();
|
let ws_stream = services.ws().attach(Empty {}).await?.into_inner();
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(128);
|
let (tx, rx) = mpsc::channel(128);
|
||||||
|
@ -126,12 +127,12 @@ impl Workspace {
|
||||||
|
|
||||||
let (tx, rx) = mpsc::channel(256);
|
let (tx, rx) = mpsc::channel(256);
|
||||||
let mut req = tonic::Request::new(tokio_stream::wrappers::ReceiverStream::new(rx));
|
let mut req = tonic::Request::new(tokio_stream::wrappers::ReceiverStream::new(rx));
|
||||||
req.metadata_mut()
|
req.metadata_mut().insert(
|
||||||
.insert(
|
"buffer",
|
||||||
"buffer",
|
tonic::metadata::MetadataValue::try_from(credentials.token).map_err(|e| {
|
||||||
tonic::metadata::MetadataValue::try_from(credentials.token)
|
tonic::Status::internal(format!("failed representing token to string: {e}"))
|
||||||
.map_err(|e| tonic::Status::internal(format!("failed representing token to string: {e}")))?,
|
})?,
|
||||||
);
|
);
|
||||||
let stream = self.0.services.buf().attach(req).await?.into_inner();
|
let stream = self.0.services.buf().attach(req).await?.into_inner();
|
||||||
|
|
||||||
let worker = BufferWorker::new(self.0.user.id, path);
|
let worker = BufferWorker::new(self.0.user.id, path);
|
||||||
|
@ -282,14 +283,18 @@ impl Workspace {
|
||||||
/// A filter may be applied, and it may be strict (equality check) or not (starts_with check).
|
/// A filter may be applied, and it may be strict (equality check) or not (starts_with check).
|
||||||
// #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120
|
// #[cfg_attr(feature = "js", napi)] // https://github.com/napi-rs/napi-rs/issues/1120
|
||||||
pub fn filetree(&self, filter: Option<&str>, strict: bool) -> Vec<String> {
|
pub fn filetree(&self, filter: Option<&str>, strict: bool) -> Vec<String> {
|
||||||
self.0.filetree.iter()
|
self.0
|
||||||
.filter(|f| filter.map_or(true, |flt| {
|
.filetree
|
||||||
if strict {
|
.iter()
|
||||||
f.as_str() == flt
|
.filter(|f| {
|
||||||
} else {
|
filter.map_or(true, |flt| {
|
||||||
f.starts_with(flt)
|
if strict {
|
||||||
}
|
f.as_str() == flt
|
||||||
}))
|
} else {
|
||||||
|
f.starts_with(flt)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
.map(|f| f.clone())
|
.map(|f| f.clone())
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
@ -315,9 +320,7 @@ impl Workspace {
|
||||||
match ev {
|
match ev {
|
||||||
// user
|
// user
|
||||||
WorkspaceEventInner::Join(UserJoin { user }) => {
|
WorkspaceEventInner::Join(UserJoin { user }) => {
|
||||||
inner
|
inner.users.insert(user.id.uuid(), user.into());
|
||||||
.users
|
|
||||||
.insert(user.id.uuid(), user.into());
|
|
||||||
}
|
}
|
||||||
WorkspaceEventInner::Leave(UserLeave { user }) => {
|
WorkspaceEventInner::Leave(UserLeave { user }) => {
|
||||||
inner.users.remove(&user.id.uuid());
|
inner.users.remove(&user.id.uuid());
|
||||||
|
@ -364,8 +367,8 @@ impl Drop for WorkspaceInner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg_attr(feature = "py", pyo3::pyclass(eq, eq_int))]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), pyo3::pyclass(eq, eq_int))]
|
||||||
#[cfg_attr(feature = "py", derive(PartialEq))]
|
#[cfg_attr(any(feature = "py", feature = "py-noabi"), derive(PartialEq))]
|
||||||
pub enum DetachResult {
|
pub enum DetachResult {
|
||||||
NotAttached,
|
NotAttached,
|
||||||
Detaching,
|
Detaching,
|
||||||
|
|
Loading…
Reference in a new issue