feat: added new methods to java, js and py glues

This commit is contained in:
əlemi 2024-08-27 23:04:56 +02:00
parent e1da62f0c8
commit 6b7324d37f
Signed by: alemi
GPG key ID: A4895B84D311642C
5 changed files with 207 additions and 7 deletions

View file

@ -24,6 +24,26 @@ public class Client {
return join_workspace(this.ptr, id);
}
private static native void create_workspace(long self, String id) throws CodeMPException;
public void createWorkspace(String id) throws CodeMPException {
return create_workspace(this.ptr, id);
}
private static native void delete_workspace(long self, String id) throws CodeMPException;
public void deleteWorkspace(String id) throws CodeMPException {
return delete_workspace(this.ptr, id);
}
private static native void invite_to_workspace(long self, String ws, String usr) throws CodeMPException;
public void inviteToWorkspace(String ws, String usr) throws CodeMPException {
return invite_to_workspace(this.ptr, id);
}
private static native String[] list_workspaces(long self, boolean owned, boolean invited) throws CodeMPException;
public String[] listWorkspaces(boolean owned, boolean invited) throws CodeMPException {
return list_workspaces(this.ptr, owned, invited);
}
private static native boolean leave_workspace(long self, String id);
public boolean leaveWorkspace(String id) {
return leave_workspace(this.ptr, id);
@ -33,6 +53,11 @@ public class Client {
public Optional<Workspace> getWorkspace() {
return Optional.ofNullable(get_workspace(this.ptr));
}
private static native void refresh_native(long self);
public void refresh() {
return refresh_native(this.ptr);
}
private static native void free(long self);
@Override

6
dist/py/codemp.pyi vendored
View file

@ -114,7 +114,13 @@ class Client:
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]: ...

View file

@ -1,4 +1,4 @@
use jni::{objects::{JClass, JString, JValueGen}, sys::{jboolean, jlong, jobject}, JNIEnv};
use jni::{objects::{JClass, JObject, JString, JValueGen}, sys::{jboolean, jlong, jobject, jobjectArray}, JNIEnv};
use crate::{client::Client, Workspace};
use super::{JExceptable, RT};
@ -21,7 +21,7 @@ pub extern "system" fn Java_mp_code_Client_connect<'local>(
let pwd: String = env.get_string(&pwd)
.map(|s| s.into())
.jexcept(&mut env);
RT.block_on(crate::Client::new(&url, &user, &pwd))
RT.block_on(crate::Client::connect(&url, &user, &pwd))
.map(|client| Box::into_raw(Box::new(client)) as jlong)
.map(|ptr| {
env.find_class("mp/code/Client")
@ -52,6 +52,87 @@ pub extern "system" fn Java_mp_code_Client_join_1workspace<'local>(
}).jexcept(&mut env).as_raw()
}
/// Creates a workspace on server, if allowed to
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_create_1workspace<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
self_ptr: jlong,
input: JString<'local>
) {
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
let workspace_id = unsafe { env.get_string_unchecked(&input) }
.map(|wid| wid.to_string_lossy().to_string())
.jexcept(&mut env);
RT
.block_on(client.create_workspace(workspace_id))
.jexcept(&mut env);
}
/// Deletes a workspace on server, if allowed to
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_delete_1workspace<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
self_ptr: jlong,
input: JString<'local>
) {
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
let workspace_id = unsafe { env.get_string_unchecked(&input) }
.map(|wid| wid.to_string_lossy().to_string())
.jexcept(&mut env);
RT
.block_on(client.delete_workspace(workspace_id))
.jexcept(&mut env);
}
/// Invites another user to an owned workspace
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_invite_1to_1workspace<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
self_ptr: jlong,
ws: JString<'local>,
usr: JString<'local>
) {
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
let workspace_id = unsafe { env.get_string_unchecked(&ws) }
.map(|wid| wid.to_string_lossy().to_string())
.jexcept(&mut env);
let user_name = unsafe { env.get_string_unchecked(&usr) }
.map(|wid| wid.to_string_lossy().to_string())
.jexcept(&mut env);
RT
.block_on(client.invite_to_workspace(workspace_id, user_name))
.jexcept(&mut env);
}
/// List available workspaces
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_list_1workspaces<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
self_ptr: jlong,
owned: jboolean,
invited: jboolean
) -> jobjectArray {
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
let list = RT
.block_on(client.list_workspaces(owned != 0, invited != 0))
.jexcept(&mut env);
env.find_class("java/lang/String")
.and_then(|class| env.new_object_array(list.len() as i32, class, JObject::null()))
.map(|arr| {
for (idx, path) in list.iter().enumerate() {
env.new_string(path)
.and_then(|path| env.set_object_array_element(&arr, idx as i32, path))
.jexcept(&mut env)
}
arr
}).jexcept(&mut env).as_raw()
}
// TODO: this stays until we get rid of the arc then i'll have to find a better way
fn spawn_updater(workspace: Workspace) -> Workspace {
let w = workspace.clone();
@ -79,6 +160,7 @@ pub extern "system" fn Java_mp_code_Client_leave_1workspace<'local>(
.map(|wid| client.leave_workspace(&wid) as jboolean)
.jexcept(&mut env)
}
/// Gets a [Workspace] by name and returns a pointer to it.
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_get_1workspace<'local>(
@ -100,6 +182,17 @@ pub extern "system" fn Java_mp_code_Client_get_1workspace<'local>(
}).unwrap_or_default().as_raw()
}
/// Refresh client's session token
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_refresh<'local>(
mut env: JNIEnv<'local>,
_class: JClass<'local>,
self_ptr: jlong,
) {
let client = unsafe { Box::leak(Box::from_raw(self_ptr as *mut Client)) };
RT.block_on(client.refresh()).jexcept(&mut env);
}
/// Sets up the tracing subscriber.
#[no_mangle]
pub extern "system" fn Java_mp_code_Client_setup_1tracing<'local>(

View file

@ -4,7 +4,7 @@ use crate::{Client, Workspace};
#[napi]
/// connect to codemp servers and return a client session
pub async fn connect(addr: Option<String>, username: String, password: String) -> napi::Result<crate::Client>{
let client = crate::Client::new(addr.as_deref().unwrap_or("http://codemp.alemi.dev:50053"), username, password)
let client = crate::Client::connect(addr.as_deref().unwrap_or("http://codemp.alemi.dev:50053"), username, password)
.await?;
Ok(client)
@ -12,12 +12,42 @@ pub async fn connect(addr: Option<String>, username: String, password: String) -
#[napi]
impl Client {
#[napi(js_name = "create_workspace")]
/// create workspace with given id, if able to
pub async fn js_create_workspace(&self, workspace: String) -> napi::Result<()> {
Ok(self.create_workspace(workspace).await?)
}
#[napi(js_name = "delete_workspace")]
/// delete workspace with given id, if able to
pub async fn js_delete_workspace(&self, workspace: String) -> napi::Result<()> {
Ok(self.delete_workspace(workspace).await?)
}
#[napi(js_name = "list_workspaces")]
/// list available workspaces
pub async fn js_list_workspaces(&self, owned: bool, invited: bool) -> napi::Result<Vec<String>> {
Ok(self.list_workspaces(owned, invited).await?)
}
#[napi(js_name = "invite_to_workspace")]
/// invite user to given workspace, if able to
pub async fn js_invite_to_workspace(&self, workspace: String, user: String) -> napi::Result<()> {
Ok(self.invite_to_workspace(workspace, user).await?)
}
#[napi(js_name = "join_workspace")]
/// join workspace with given id (will start its cursor controller)
pub async fn js_join_workspace(&self, workspace: String) -> napi::Result<Workspace> {
Ok(self.join_workspace(workspace).await?)
}
#[napi(js_name = "leave_workspace")]
/// leave workspace and disconnect, returns true if workspace was active
pub async fn js_leave_workspace(&self, workspace: String) -> napi::Result<bool> {
Ok(self.leave_workspace(&workspace))
}
#[napi(js_name = "get_workspace")]
/// get workspace with given id, if it exists
pub fn js_get_workspace(&self, workspace: String) -> Option<Workspace> {
@ -27,7 +57,7 @@ impl Client {
#[napi(js_name = "user_id")]
/// return current sessions's user id
pub fn js_user_id(&self) -> String {
self.user_id().to_string()
self.user().id.to_string()
}
#[napi(js_name = "active_workspaces")]
@ -35,4 +65,10 @@ impl Client {
pub fn js_active_workspaces(&self) -> Vec<String> {
self.active_workspaces()
}
}
#[napi(js_name = "refresh")]
/// refresh client session token
pub async fn js_refresh(&self) -> napi::Result<()> {
Ok(self.refresh().await?)
}
}

View file

@ -8,7 +8,7 @@ use super::tokio;
impl Client {
#[new]
fn __new__(host: String, username: String, password: String) -> crate::Result<Self> {
tokio().block_on(Client::new(host, username, password))
tokio().block_on(Client::connect(host, username, password))
}
// #[pyo3(name = "join_workspace")]
@ -37,6 +37,34 @@ impl Client {
// }))))
}
#[pyo3(name = "create_workspace")]
fn pycreate_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> {
tracing::info!("attempting to create workspace {}", workspace);
let this = self.clone();
crate::a_sync_allow_threads!(py, this.create_workspace(workspace).await)
}
#[pyo3(name = "delete_workspace")]
fn pydelete_workspace(&self, py: Python<'_>, workspace: String) -> PyResult<super::Promise> {
tracing::info!("attempting to delete workspace {}", workspace);
let this = self.clone();
crate::a_sync_allow_threads!(py, this.delete_workspace(workspace).await)
}
#[pyo3(name = "invite_to_workspace")]
fn pyinvite_to_workspace(&self, py: Python<'_>, workspace: String, user: String) -> PyResult<super::Promise> {
tracing::info!("attempting to invite {user} to workspace {workspace}");
let this = self.clone();
crate::a_sync_allow_threads!(py, this.invite_to_workspace(workspace, user).await)
}
#[pyo3(name = "list_workspaces")]
fn pylist_workspaces(&self, py: Python<'_>, owned: bool, invited: bool) -> PyResult<super::Promise> {
tracing::info!("attempting to list workspaces");
let this = self.clone();
crate::a_sync_allow_threads!(py, this.list_workspaces(owned, invited).await)
}
#[pyo3(name = "leave_workspace")]
fn pyleave_workspace(&self, id: String) -> bool {
self.leave_workspace(id.as_str())
@ -55,6 +83,18 @@ impl Client {
#[pyo3(name = "user_id")]
fn pyuser_id(&self) -> String {
self.user_id().to_string()
self.user().id.to_string()
}
#[pyo3(name = "user_name")]
fn pyuser_name(&self) -> String {
self.user().name.clone()
}
#[pyo3(name = "refresh")]
fn pyrefresh(&self, py: Python<'_>) -> PyResult<super::Promise> {
tracing::info!("attempting to refresh token");
let this = self.clone();
crate::a_sync_allow_threads!(py, this.refresh().await)
}
}