Merge pull request #4031 from Kingtous/feat/plugins
feat: add a rust example for writing a custom plugin
This commit is contained in:
		
						commit
						1280b7beb4
					
				
							
								
								
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -48,3 +48,5 @@ lib/generated_bridge.dart | ||||
| .vscode-server/ | ||||
| .ssh | ||||
| .devcontainer/.* | ||||
| # build cache in examples | ||||
| examples/**/target/ | ||||
| @ -136,7 +136,7 @@ flutter_rust_bridge = "1.61.1" | ||||
| 
 | ||||
| [workspace] | ||||
| members = ["libs/scrap", "libs/hbb_common", "libs/enigo", "libs/clipboard", "libs/virtual_display", "libs/virtual_display/dylib", "libs/simple_rc", "libs/portable"] | ||||
| exclude = ["vdi/host"] | ||||
| exclude = ["vdi/host", "examples/custom_plugin"] | ||||
| 
 | ||||
| [package.metadata.winres] | ||||
| LegalCopyright = "Copyright © 2022 Purslane, Inc." | ||||
|  | ||||
							
								
								
									
										23
									
								
								examples/custom_plugin/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								examples/custom_plugin/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,23 @@ | ||||
| [package] | ||||
| name = "custom_plugin" | ||||
| version = "0.1.0" | ||||
| edition = "2021" | ||||
| 
 | ||||
| # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html | ||||
| 
 | ||||
| [lib] | ||||
| name = "custom_plugin" | ||||
| path = "src/lib.rs" | ||||
| crate-type = ["cdylib"] | ||||
| 
 | ||||
| [dependencies] | ||||
| lazy_static = "1.4.0" | ||||
| rustdesk = { path = "../../", version = "1.2.0"} | ||||
| 
 | ||||
| [profile.release] | ||||
| lto = true | ||||
| codegen-units = 1 | ||||
| panic = 'abort' | ||||
| strip = true | ||||
| #opt-level = 'z' # only have smaller size after strip | ||||
| rpath = true | ||||
							
								
								
									
										30
									
								
								examples/custom_plugin/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/custom_plugin/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | ||||
| use librustdesk::{api::RustDeskApiTable}; | ||||
| /// This file demonstrates how to write a custom plugin for RustDesk.
 | ||||
| use std::ffi::{c_char, c_int, CString}; | ||||
| 
 | ||||
| lazy_static::lazy_static! { | ||||
|     pub static ref PLUGIN_NAME: CString = CString::new("A Template Rust Plugin").unwrap(); | ||||
|     pub static ref PLUGIN_ID: CString = CString::new("TemplatePlugin").unwrap(); | ||||
|     // Do your own logic based on the API provided by RustDesk.
 | ||||
|     pub static ref API: RustDeskApiTable = RustDeskApiTable::default(); | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| fn plugin_name() -> *const c_char { | ||||
|     return PLUGIN_NAME.as_ptr(); | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| fn plugin_id() -> *const c_char { | ||||
|     return PLUGIN_ID.as_ptr(); | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| fn plugin_init() -> c_int { | ||||
|     return 0 as _; | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| fn plugin_dispose() -> c_int { | ||||
|     return 0 as _; | ||||
| } | ||||
| @ -8,8 +8,8 @@ pub type UnloadPluginFunc = fn(*const c_char) -> i32; | ||||
| 
 | ||||
| #[repr(C)] | ||||
| pub struct RustDeskApiTable { | ||||
|     pub register_plugin: LoadPluginFunc, | ||||
|     pub unload_plugin: UnloadPluginFunc, | ||||
|     pub(crate) register_plugin: LoadPluginFunc, | ||||
|     pub(crate) unload_plugin: UnloadPluginFunc, | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| @ -22,11 +22,6 @@ fn unload_plugin(path: *const c_char) -> i32 { | ||||
|     PLUGIN_REGISTRAR.unload_plugin(path) | ||||
| } | ||||
| 
 | ||||
| #[no_mangle] | ||||
| fn get_api_table() -> RustDeskApiTable { | ||||
|     RustDeskApiTable::default() | ||||
| } | ||||
| 
 | ||||
| impl Default for RustDeskApiTable { | ||||
|     fn default() -> Self { | ||||
|         Self { | ||||
|  | ||||
							
								
								
									
										13
									
								
								src/lib.rs
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								src/lib.rs
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | ||||
| mod keyboard; | ||||
| #[cfg(not(any(target_os = "ios")))] | ||||
| /// cbindgen:ignore
 | ||||
| pub mod platform; | ||||
| mod keyboard; | ||||
| #[cfg(not(any(target_os = "android", target_os = "ios")))] | ||||
| pub use platform::{get_cursor, get_cursor_data, get_cursor_pos, start_os_service}; | ||||
| #[cfg(not(any(target_os = "ios")))] | ||||
| @ -20,7 +20,12 @@ pub use self::rendezvous_mediator::*; | ||||
| pub mod common; | ||||
| #[cfg(not(any(target_os = "ios")))] | ||||
| pub mod ipc; | ||||
| #[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli", feature = "flutter")))] | ||||
| #[cfg(not(any(
 | ||||
|     target_os = "android", | ||||
|     target_os = "ios", | ||||
|     feature = "cli", | ||||
|     feature = "flutter" | ||||
| )))] | ||||
| pub mod ui; | ||||
| mod version; | ||||
| pub use version::*; | ||||
| @ -44,9 +49,9 @@ mod license; | ||||
| mod port_forward; | ||||
| 
 | ||||
| #[cfg(not(any(target_os = "android", target_os = "ios")))] | ||||
| mod plugins; | ||||
| pub mod api; | ||||
| #[cfg(not(any(target_os = "android", target_os = "ios")))] | ||||
| mod api; | ||||
| pub mod plugins; | ||||
| 
 | ||||
| mod tray; | ||||
| 
 | ||||
|  | ||||
| @ -4,7 +4,10 @@ use std::{ | ||||
|     sync::{Arc, RwLock}, | ||||
| }; | ||||
| 
 | ||||
| use hbb_common::{anyhow::Error, log::debug}; | ||||
| use hbb_common::{ | ||||
|     anyhow::Error, | ||||
|     log::{debug, error}, | ||||
| }; | ||||
| use lazy_static::lazy_static; | ||||
| use libloading::{Library, Symbol}; | ||||
| 
 | ||||
| @ -82,6 +85,18 @@ impl<P: Plugin> PluginRegistar<P> { | ||||
|         match lib { | ||||
|             Ok(lib) => match lib.try_into() { | ||||
|                 Ok(plugin) => { | ||||
|                     let plugin: PluginImpl = plugin; | ||||
|                     // try to initialize this plugin
 | ||||
|                     if let Some(init) = plugin.plugin_vt().init { | ||||
|                         let init_ret = init(); | ||||
|                         if init_ret != 0 { | ||||
|                             error!( | ||||
|                                 "Error when initializing the plugin {} with error code {}.", | ||||
|                                 plugin.name, init_ret | ||||
|                             ); | ||||
|                             return init_ret; | ||||
|                         } | ||||
|                     } | ||||
|                     PLUGIN_REGISTRAR | ||||
|                         .plugins | ||||
|                         .write() | ||||
| @ -104,7 +119,12 @@ impl<P: Plugin> PluginRegistar<P> { | ||||
|         let p = unsafe { CStr::from_ptr(path) }; | ||||
|         let lib_path = p.to_str().unwrap_or("").to_owned(); | ||||
|         match PLUGIN_REGISTRAR.plugins.write().unwrap().remove(&lib_path) { | ||||
|             Some(_) => 0, | ||||
|             Some(plugin) => { | ||||
|                 if let Some(dispose) = plugin.plugin_vt().dispose { | ||||
|                     return dispose(); | ||||
|                 } | ||||
|                 0 | ||||
|             } | ||||
|             None => -1, | ||||
|         } | ||||
|     } | ||||
| @ -150,33 +170,28 @@ impl TryFrom<Library> for PluginImpl { | ||||
| #[cfg(target_os = "linux")] | ||||
| fn test_plugin() { | ||||
|     use std::io::Write; | ||||
| 
 | ||||
|     let code = " | ||||
|     const char* plugin_name(){return \"test_name\";};
 | ||||
|     const char* plugin_id(){return \"test_id\"; }
 | ||||
|     int plugin_init() {return 0;} | ||||
|     int plugin_dispose() {return 0;} | ||||
|     ";
 | ||||
|     let mut f = std::fs::File::create("test.c").unwrap(); | ||||
|     f.write_all(code.as_bytes()).unwrap(); | ||||
|     f.flush().unwrap(); | ||||
|     let mut cmd = std::process::Command::new("cc"); | ||||
|     cmd.arg("-fPIC") | ||||
|         .arg("-shared") | ||||
|         .arg("test.c") | ||||
|         .arg("-o") | ||||
|         .arg("libtest.so"); | ||||
|     let mut cmd = std::process::Command::new("cargo"); | ||||
|     cmd.current_dir("./examples/custom_plugin"); | ||||
|     // Strip this shared library.
 | ||||
|     cmd.env("RUSTFLAGS", "-C link-arg=-s"); | ||||
|     cmd.arg("build"); | ||||
|     // Spawn the compiler process.
 | ||||
|     let mut child = cmd.spawn().unwrap(); | ||||
|     // Wait for the compiler to finish.
 | ||||
|     let status = child.wait().unwrap(); | ||||
|     assert!(status.success()); | ||||
|     // Load the library.
 | ||||
|     let lib = unsafe { Library::new("./libtest.so").unwrap() }; | ||||
|     let lib = unsafe { | ||||
|         Library::new("./examples/custom_plugin/target/debug/libcustom_plugin.so").unwrap() | ||||
|     }; | ||||
|     let plugin: PluginImpl = lib.try_into().unwrap(); | ||||
|     assert!(plugin._inner.is_some()); | ||||
|     assert!(plugin.name == "test_name"); | ||||
|     assert!(plugin.id == "test_id"); | ||||
|     assert!(plugin.name == "A Template Rust Plugin"); | ||||
|     assert!(plugin.id == "TemplatePlugin"); | ||||
|     println!( | ||||
|         "plugin vt size: {}", | ||||
|         std::mem::size_of::<RustDeskPluginTable>() | ||||
|     ); | ||||
|     assert!(PLUGIN_REGISTRAR | ||||
|         .plugins | ||||
|         .write() | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user