feat: implemented exception handling (this time for real)

This commit is contained in:
zaaarf 2023-08-28 16:12:42 +02:00
parent c05947466d
commit 6c892e7e3a
No known key found for this signature in database
GPG key ID: 6445A5CD15E5B40C
5 changed files with 91 additions and 92 deletions

4
.gitignore vendored
View file

@ -44,8 +44,8 @@ bin/
### Rust ### ### Rust ###
Cargo.lock Cargo.lock
.cargo/* .cargo
target/* target
# Do not inclue generated code # Do not inclue generated code
src/main/java/com/codemp/intellij/jni src/main/java/com/codemp/intellij/jni

View file

@ -4,13 +4,18 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
codemp = { git = "ssh://git@github.com-irl/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.2" } codemp = { git = "ssh://git@github.com-irl/codewithotherpeopleandchangenamelater/codemp.git", tag = "v0.4.4", features = ["global"] }
jni = "0.21.1" jni = { version = "0.21.1", features = ["invocation"] }
rifgen = "0.1.61" rifgen = { path = "/home/zaaarf/dev/irl/rust/jni/rifgen" }
#rifgen = { git = "https://github.com/Kofituo/rifgen.git", rev = "d27d9785b2febcf5527f1deb6a846be5d583f7d7"}
#rifgen = "0.1.7"
[build-dependencies] [build-dependencies]
flapigen = "0.6.0" flapigen = "0.6.0"
rifgen = "0.1.61" rifgen = { path = "/home/zaaarf/dev/irl/rust/jni/rifgen" }
#rifgen = "0.1.7"
#rifgen = { git = "https://github.com/Kofituo/rifgen.git", rev = "d27d9785b2febcf5527f1deb6a846be5d583f7d7"}
[lib] [lib]
crate_type = ["cdylib"] crate_type = ["cdylib"]

View file

@ -1,43 +1,48 @@
use flapigen::{JavaConfig, LanguageConfig}; use flapigen::{JavaConfig, LanguageConfig};
use std::{env, path::Path}; use std::{env, path::Path};
use rifgen::{Generator, TypeCases, Language}; use rifgen::{Generator as RifgenGenerator, TypeCases, Language};
use flapigen::Generator as FlapigenGenerator;
fn main() { fn main() {
let out_dir_var = env::var("OUT_DIR") let out_dir_var = env::var("OUT_DIR")
.expect("no OUT_DIR, but cargo should provide it"); .expect("no OUT_DIR, but cargo should provide it");
let out_dir = Path::new(&out_dir_var); let out_dir = Path::new(&out_dir_var);
let source_folder = "src/main/rust/";
let glue_file = out_dir.join("glue.in"); let mut source_folders = Vec::new();
Generator::new(TypeCases::CamelCase,Language::Java,source_folder) source_folders.push(Path::new("src/main/rust/"));
.generate_interface(&glue_file);
let jni_path = Path::new("src") let glue_file = out_dir.join("glue.in");
.join("main") RifgenGenerator::new(TypeCases::CamelCase,
.join("java") Language::Java,
.join("com") source_folders)
.join("codemp") .generate_interface(&glue_file);
.join("intellij")
.join("jni");
//create folder if it doesn't exist let jni_path = Path::new("src")
std::fs::create_dir_all(&jni_path) .join("main")
.expect("An error occurred while creating the JNI folder!"); .join("java")
.join("com")
.join("codemp")
.join("intellij")
.join("jni");
let java_gen = flapigen::Generator::new(LanguageConfig::JavaConfig( //create folder if it doesn't exist
JavaConfig::new( std::fs::create_dir_all(&jni_path)
jni_path, .expect("An error occurred while creating the JNI folder!");
"com.codemp.intellij.jni".into()
))).rustfmt_bindings(true);
java_gen.expand( let java_gen = FlapigenGenerator::new(LanguageConfig::JavaConfig(
"codemp-intellij", JavaConfig::new(
&glue_file, jni_path,
out_dir.join("glue.rs"), "com.codemp.intellij.jni".into()
); ))).rustfmt_bindings(true);
println!( java_gen.expand(
"cargo:rerun-if-changed={}", "codemp-intellij",
Path::new("src/main").join(&glue_file).display() &glue_file,
); out_dir.join("glue.rs"),
);
println!(
"cargo:rerun-if-changed={}",
Path::new("src/main").join(&glue_file).display()
);
} }

View file

@ -1,6 +1,4 @@
use codemp::prelude::CodempError; use codemp::prelude::CodempError;
use jni::JNIEnv;
use crate::JAVA_FOLDER;
pub struct ErrorWrapper(CodempError); pub struct ErrorWrapper(CodempError);
@ -11,24 +9,19 @@ impl From::<CodempError> for ErrorWrapper {
} }
impl ErrorWrapper { impl ErrorWrapper {
pub fn throw(&self, mut env: JNIEnv) { pub fn get_error_message(&self) -> String {
let exception_package: String = format!("{}/exceptions", JAVA_FOLDER); match &self.0 {
let res = match &self.0 { CodempError::Transport { status, message } =>
CodempError::Transport { status, message } => env.throw_new(format!("{}/TransportException", exception_package), format!("Error {}: {}", status, message)), format!("Error {}: {}", status, message),
CodempError::InvalidState { msg } => env.throw_new(format!("{}/InvalidStateException", exception_package), msg), CodempError::InvalidState { msg } => msg.to_string(),
CodempError::Filler { message } => env.throw_new(format!("{}/CodeMPException", exception_package), message), CodempError::Filler { message } => message.to_string(),
CodempError::Channel { send } => { CodempError::Channel { send } => {
let class_name:String = if *send { if *send {
format!("{}/ChannelException/Send", exception_package) "Error while sending message on channel: the channel was closed!".to_string()
} else { } else {
format!("{}/ChannelException/Read", exception_package) "Error while reading message from channel: the channel was closed!".to_string()
}; }
env.throw_new(class_name, "The requested channel was closed!")
} }
};
if let Err(e) = res {
panic!("An error occurred while converting a Rust error to a Java Exception: {}", e);
} }
} }
} }

View file

@ -1,88 +1,84 @@
mod error; mod error;
use std::ffi::c_char;
use std::sync::Arc; use std::sync::Arc;
use codemp::prelude::*; use codemp::prelude::*;
use rifgen::rifgen_attr::generate_interface; use rifgen::rifgen_attr::generate_interface;
use crate::error::ErrorWrapper; use crate::error::ErrorWrapper;
pub const JAVA_PACKAGE: &str = "com.codemp.intellij";
pub const JAVA_FOLDER: &str = "com/codemp/intellij";
// #[generate_interface_doc] //TODO // #[generate_interface_doc] //TODO
struct CodeMPHandler {} struct CodeMPHandler {}
impl CodeMPHandler { impl CodeMPHandler {
#[generate_interface(constructor)] #[generate_interface(constructor)]
fn new() -> CodeMPHandler { async fn new() -> CodeMPHandler {
CodeMPHandler {} CodeMPHandler {}
} }
#[generate_interface] #[generate_interface]
async fn connect(addr: String) { async fn connect(addr: String) -> Result<(), String> {
CODEMP_INSTANCE.connect(&addr).await; convert(CODEMP_INSTANCE.connect(&addr).await)
/*match CODEMP_INSTANCE.connect(&addr) {
Ok(()) => (),
Err(err) => ErrorWrapper(err) //.throw(env)
}*/
} }
#[generate_interface] #[generate_interface]
async fn join(session: String) -> CursorHandler { async fn join(session: String) -> Result<CursorHandler, String> {
let controller = CODEMP_INSTANCE.join(&session).await.unwrap(); convert_cursor(CODEMP_INSTANCE.join(&session).await)
CursorHandler { cursor: Some(controller) } //TODO error handling
/*match CODEMP_INSTANCE.join(&session) {
Ok(cursor) => CursorHandler { cursor },
//Err(err) => ErrorWrapper(err)
}*/
} }
#[generate_interface] #[generate_interface]
async fn create(path: String) { async fn create(path: String) -> Result<(), String> {
CODEMP_INSTANCE.create(&path, None).await; convert(CODEMP_INSTANCE.create(&path, None).await)
} }
#[generate_interface] #[generate_interface]
async fn create_with_content(path: String, content: String) { async fn create_with_content(path: String, content: String) -> Result<(), String> {
CODEMP_INSTANCE.create(&path, Some(&content)).await; convert(CODEMP_INSTANCE.create(&path, Some(&content)).await)
} }
#[generate_interface] #[generate_interface]
async fn attach(path: String) -> BufferHandler { async fn attach(path: String) -> Result<BufferHandler, String> {
let controller = CODEMP_INSTANCE.attach(&path).await.unwrap(); convert_buffer(CODEMP_INSTANCE.attach(&path).await)
BufferHandler { buffer: Some(controller) }
} }
#[generate_interface] #[generate_interface]
async fn get_cursor() -> CursorHandler { async fn get_cursor() -> Result<CursorHandler, String> {
let controller = CODEMP_INSTANCE.get_cursor().await.unwrap(); convert_cursor(CODEMP_INSTANCE.get_cursor().await)
CursorHandler { cursor: Some(controller) }
} }
#[generate_interface] #[generate_interface]
async fn get_buffer(path: String) -> BufferHandler { async fn get_buffer(path: String) -> Result<BufferHandler, String> {
let controller = CODEMP_INSTANCE.get_buffer(&path).await.unwrap(); convert_buffer(CODEMP_INSTANCE.get_buffer(&path).await)
BufferHandler { buffer: Some(controller) }
} }
#[generate_interface] #[generate_interface]
async fn leave_workspace() { async fn leave_workspace() -> Result<(), String> {
CODEMP_INSTANCE.leave_workspace().await.unwrap() convert(CODEMP_INSTANCE.leave_workspace().await)
} }
#[generate_interface] #[generate_interface]
async fn disconnect_buffer(path: String) -> bool { async fn disconnect_buffer(path: String) -> Result<bool, String> {
CODEMP_INSTANCE.disconnect_buffer(&path).await.unwrap() convert(CODEMP_INSTANCE.disconnect_buffer(&path).await)
} }
} }
fn convert_buffer(result: Result<Arc<CodempBufferController>, CodempError>) -> Result<BufferHandler, String> {
convert(result).map(|val| BufferHandler { buffer: Some(val) })
}
fn convert_cursor(result: Result<Arc<CodempCursorController>, CodempError>) -> Result<CursorHandler, String> {
convert(result).map(|val| CursorHandler { cursor: Some(val) })
}
fn convert<T>(result: Result<T, CodempError>) -> Result<T, String> {
result.map_err(|err| ErrorWrapper::from(err).get_error_message())
}
struct CursorHandler { struct CursorHandler {
cursor: Option<Arc<CodempCursorController>> cursor: Option<Arc<CodempCursorController>>
} }
impl CursorHandler { impl CursorHandler {
#[generate_interface(constructor)] #[generate_interface(constructor)]
fn new() -> CursorHandler { //TODO this sucks but whatever async fn new() -> CursorHandler { //TODO: this sucks but whatever
CursorHandler { cursor: None } CursorHandler { cursor: None }
} }
} }
@ -94,7 +90,7 @@ struct BufferHandler {
impl BufferHandler { impl BufferHandler {
#[generate_interface(constructor)] #[generate_interface(constructor)]
fn new() -> BufferHandler { //TODO this sucks but whatever async fn new() -> BufferHandler { //TODO: this sucks but whatever
BufferHandler { buffer: None } BufferHandler { buffer: None }
} }
} }