Merge pull request #4200 from fufesou/feat/plugin_framework
Feat/plugin framework
This commit is contained in:
commit
e6ac69abfe
@ -1608,12 +1608,16 @@ class FFI {
|
|||||||
if (message.field0 == "close") {
|
if (message.field0 == "close") {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Map<String, dynamic>? event;
|
||||||
try {
|
try {
|
||||||
Map<String, dynamic> event = json.decode(message.field0);
|
event = json.decode(message.field0);
|
||||||
await cb(event);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('json.decode fail1(): $e, ${message.field0}');
|
debugPrint('json.decode fail1(): $e, ${message.field0}');
|
||||||
}
|
}
|
||||||
|
if (event != null) {
|
||||||
|
await cb(event);
|
||||||
|
}
|
||||||
} else if (message is EventToUI_Rgba) {
|
} else if (message is EventToUI_Rgba) {
|
||||||
if (useTextureRender) {
|
if (useTextureRender) {
|
||||||
if (_waitForImage[id]!) {
|
if (_waitForImage[id]!) {
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
void handlePluginEvent(
|
void handlePluginEvent(
|
||||||
Map<String, dynamic> evt,
|
Map<String, dynamic> evt,
|
||||||
String peer,
|
String peer,
|
||||||
Function(Map<String, dynamic> e) handleMsgBox,
|
Function(Map<String, dynamic> e) handleMsgBox,
|
||||||
) {
|
) {
|
||||||
if (evt['content']?['c'] == null) return;
|
Map<String, dynamic>? content;
|
||||||
final t = evt['content']?['t'];
|
try {
|
||||||
if (t == 'MsgBox') {
|
content = json.decode(evt['content']);
|
||||||
handleMsgBox(evt['content']?['c']);
|
} catch (e) {
|
||||||
|
debugPrint(
|
||||||
|
'Json decode plugin event content failed: $e, ${evt['content']}');
|
||||||
|
}
|
||||||
|
if (content?['t'] == 'MsgBox') {
|
||||||
|
handleMsgBox(content?['c']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -605,7 +605,7 @@ message PluginRequest {
|
|||||||
bytes content = 2;
|
bytes content = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
message PluginResponse {
|
message PluginFailure {
|
||||||
string id = 1;
|
string id = 1;
|
||||||
string name = 2;
|
string name = 2;
|
||||||
string msg = 3;
|
string msg = 3;
|
||||||
@ -633,7 +633,7 @@ message Misc {
|
|||||||
SwitchBack switch_back = 22;
|
SwitchBack switch_back = 22;
|
||||||
Resolution change_resolution = 24;
|
Resolution change_resolution = 24;
|
||||||
PluginRequest plugin_request = 25;
|
PluginRequest plugin_request = 25;
|
||||||
PluginResponse plugin_response = 26;
|
PluginFailure plugin_failure = 26;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,12 +1301,16 @@ impl<T: InvokeUiSession> Remote<T> {
|
|||||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
Some(misc::Union::PluginRequest(p)) => {
|
Some(misc::Union::PluginRequest(p)) => {
|
||||||
allow_err!(crate::plugin::handle_server_event(&p.id, &self.handler.id, &p.content));
|
allow_err!(crate::plugin::handle_server_event(
|
||||||
|
&p.id,
|
||||||
|
&self.handler.id,
|
||||||
|
&p.content
|
||||||
|
));
|
||||||
// to-do: show message box on UI when error occurs?
|
// to-do: show message box on UI when error occurs?
|
||||||
}
|
}
|
||||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
Some(misc::Union::PluginResponse(p)) => {
|
Some(misc::Union::PluginFailure(p)) => {
|
||||||
let name = if p.name.is_empty() {
|
let name = if p.name.is_empty() {
|
||||||
"plugin".to_string()
|
"plugin".to_string()
|
||||||
} else {
|
} else {
|
||||||
|
@ -36,13 +36,13 @@ lazy_static::lazy_static! {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ConfigToUi {
|
struct ConfigToUi {
|
||||||
channel: u16,
|
channel: u16,
|
||||||
location: String,
|
location: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct MsgToConfig {
|
struct MsgToConfig {
|
||||||
id: String,
|
id: String,
|
||||||
r#type: String,
|
r#type: String,
|
||||||
@ -99,7 +99,7 @@ pub(super) extern "C" fn cb_msg(
|
|||||||
}
|
}
|
||||||
MSG_TO_UI_TARGET => {
|
MSG_TO_UI_TARGET => {
|
||||||
let content_slice = unsafe { std::slice::from_raw_parts(content as *const u8, len) };
|
let content_slice = unsafe { std::slice::from_raw_parts(content as *const u8, len) };
|
||||||
let channel = u16::from_be_bytes([content_slice[0], content_slice[1]]);
|
let channel = u16::from_le_bytes([content_slice[0], content_slice[1]]);
|
||||||
let content = std::string::String::from_utf8(content_slice[2..].to_vec())
|
let content = std::string::String::from_utf8(content_slice[2..].to_vec())
|
||||||
.unwrap_or("".to_string());
|
.unwrap_or("".to_string());
|
||||||
push_event_to_ui(channel, &peer, &content);
|
push_event_to_ui(channel, &peer, &content);
|
||||||
@ -165,7 +165,7 @@ fn push_event_to_ui(channel: u16, peer: &str, content: &str) {
|
|||||||
let _res = flutter::push_global_event(v as _, event.to_string());
|
let _res = flutter::push_global_event(v as _, event.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if is_peer_channel(channel) {
|
if !peer.is_empty() && is_peer_channel(channel) {
|
||||||
let _res = flutter::push_session_event(
|
let _res = flutter::push_session_event(
|
||||||
&peer,
|
&peer,
|
||||||
MSG_TO_UI_TYPE_PLUGIN_EVENT,
|
MSG_TO_UI_TYPE_PLUGIN_EVENT,
|
||||||
@ -176,21 +176,26 @@ fn push_event_to_ui(channel: u16, peer: &str, content: &str) {
|
|||||||
|
|
||||||
fn push_option_to_ui(channel: u16, peer: &str, msg: &MsgToConfig, ui: &ConfigToUi) {
|
fn push_option_to_ui(channel: u16, peer: &str, msg: &MsgToConfig, ui: &ConfigToUi) {
|
||||||
let v = [
|
let v = [
|
||||||
("name", MSG_TO_UI_TYPE_PLUGIN_OPTION),
|
("id", &msg.id as &str),
|
||||||
("id", &msg.id),
|
|
||||||
("location", &ui.location),
|
("location", &ui.location),
|
||||||
("key", &msg.key),
|
("key", &msg.key),
|
||||||
("value", &msg.value),
|
("value", &msg.value),
|
||||||
];
|
];
|
||||||
let event = serde_json::to_string(&HashMap::from(v)).unwrap_or("".to_string());
|
|
||||||
|
// Send main and cm
|
||||||
|
let mut m = HashMap::from(v);
|
||||||
|
m.insert("name", MSG_TO_UI_TYPE_PLUGIN_OPTION);
|
||||||
|
let event = serde_json::to_string(&m).unwrap_or("".to_string());
|
||||||
for (k, v) in MSG_TO_UI_FLUTTER_CHANNELS.iter() {
|
for (k, v) in MSG_TO_UI_FLUTTER_CHANNELS.iter() {
|
||||||
if channel & k != 0 {
|
if channel & k != 0 {
|
||||||
let _res = flutter::push_global_event(v as _, event.to_string());
|
let _res = flutter::push_global_event(v as _, event.to_string());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut v = v.to_vec();
|
|
||||||
v.push(("peer", &peer));
|
// Send remote, transfer and forward
|
||||||
if is_peer_channel(channel) {
|
if !peer.is_empty() && is_peer_channel(channel) {
|
||||||
let _res = flutter::push_session_event(&peer, MSG_TO_UI_TYPE_PLUGIN_OPTION, v.to_vec());
|
let mut v = v.to_vec();
|
||||||
|
v.push(("peer", &peer));
|
||||||
|
let _res = flutter::push_session_event(&peer, MSG_TO_UI_TYPE_PLUGIN_OPTION, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ use hbb_common::{
|
|||||||
allow_err, bail,
|
allow_err, bail,
|
||||||
dlopen::symbor::Library,
|
dlopen::symbor::Library,
|
||||||
lazy_static, log,
|
lazy_static, log,
|
||||||
message_proto::{Message, Misc, PluginResponse},
|
message_proto::{Message, Misc, PluginFailure, PluginRequest},
|
||||||
ResultType,
|
ResultType,
|
||||||
};
|
};
|
||||||
use std::{
|
use std::{
|
||||||
@ -89,20 +89,43 @@ type CallbackGetId = extern "C" fn() -> *const c_char;
|
|||||||
/// level: "error", "warn", "info", "debug", "trace".
|
/// level: "error", "warn", "info", "debug", "trace".
|
||||||
/// msg: The message.
|
/// msg: The message.
|
||||||
type CallbackLog = extern "C" fn(level: *const c_char, msg: *const c_char);
|
type CallbackLog = extern "C" fn(level: *const c_char, msg: *const c_char);
|
||||||
/// The main function of the plugin.
|
/// The main function of the plugin on the client(self) side.
|
||||||
|
///
|
||||||
/// method: The method. "handle_ui" or "handle_peer"
|
/// method: The method. "handle_ui" or "handle_peer"
|
||||||
/// peer: The peer id.
|
/// peer: The peer id.
|
||||||
/// args: The arguments.
|
/// args: The arguments.
|
||||||
|
/// len: The length of the arguments.
|
||||||
///
|
///
|
||||||
/// Return null ptr if success.
|
/// Return null ptr if success.
|
||||||
/// Return the error message if failed. `i32-String` without dash, i32 is a signed little-endian number, the String is utf8 string.
|
/// Return the error message if failed. `i32-String` without dash, i32 is a signed little-endian number, the String is utf8 string.
|
||||||
/// The plugin allocate memory with `libc::malloc` and return the pointer.
|
/// The plugin allocate memory with `libc::malloc` and return the pointer.
|
||||||
type PluginFuncCall = extern "C" fn(
|
type PluginFuncClientCall = extern "C" fn(
|
||||||
method: *const c_char,
|
method: *const c_char,
|
||||||
peer: *const c_char,
|
peer: *const c_char,
|
||||||
args: *const c_void,
|
args: *const c_void,
|
||||||
len: usize,
|
len: usize,
|
||||||
) -> *const c_void;
|
) -> *const c_void;
|
||||||
|
/// The main function of the plugin on the server(remote) side.
|
||||||
|
///
|
||||||
|
/// method: The method. "handle_ui" or "handle_peer"
|
||||||
|
/// peer: The peer id.
|
||||||
|
/// args: The arguments.
|
||||||
|
/// len: The length of the arguments.
|
||||||
|
/// out: The output.
|
||||||
|
/// The plugin allocate memory with `libc::malloc` and return the pointer.
|
||||||
|
/// out_len: The length of the output.
|
||||||
|
///
|
||||||
|
/// Return null ptr if success.
|
||||||
|
/// Return the error message if failed. `i32-String` without dash, i32 is a signed little-endian number, the String is utf8 string.
|
||||||
|
/// The plugin allocate memory with `libc::malloc` and return the pointer.
|
||||||
|
type PluginFuncServerCall = extern "C" fn(
|
||||||
|
method: *const c_char,
|
||||||
|
peer: *const c_char,
|
||||||
|
args: *const c_void,
|
||||||
|
len: usize,
|
||||||
|
out: *mut *mut c_void,
|
||||||
|
out_len: *mut usize,
|
||||||
|
) -> *const c_void;
|
||||||
|
|
||||||
/// The plugin callbacks.
|
/// The plugin callbacks.
|
||||||
/// msg: The callback to send message to peer or ui.
|
/// msg: The callback to send message to peer or ui.
|
||||||
@ -222,7 +245,8 @@ make_plugin!(
|
|||||||
reset: PluginFuncReset,
|
reset: PluginFuncReset,
|
||||||
clear: PluginFuncClear,
|
clear: PluginFuncClear,
|
||||||
desc: PluginFuncDesc,
|
desc: PluginFuncDesc,
|
||||||
call: PluginFuncCall
|
client_call: PluginFuncClientCall,
|
||||||
|
server_call: PluginFuncServerCall
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@ -357,7 +381,7 @@ fn handle_event(method: &[u8], id: &str, peer: &str, event: &[u8]) -> ResultType
|
|||||||
peer.push('\0');
|
peer.push('\0');
|
||||||
match PLUGINS.read().unwrap().get(id) {
|
match PLUGINS.read().unwrap().get(id) {
|
||||||
Some(plugin) => {
|
Some(plugin) => {
|
||||||
let ret = (plugin.call)(
|
let ret = (plugin.client_call)(
|
||||||
method.as_ptr() as _,
|
method.as_ptr() as _,
|
||||||
peer.as_ptr() as _,
|
peer.as_ptr() as _,
|
||||||
event.as_ptr() as _,
|
event.as_ptr() as _,
|
||||||
@ -392,19 +416,25 @@ pub fn handle_server_event(id: &str, peer: &str, event: &[u8]) -> ResultType<()>
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn handle_client_event(id: &str, peer: &str, event: &[u8]) -> Option<Message> {
|
pub fn handle_client_event(id: &str, peer: &str, event: &[u8]) -> Message {
|
||||||
let mut peer: String = peer.to_owned();
|
let mut peer: String = peer.to_owned();
|
||||||
peer.push('\0');
|
peer.push('\0');
|
||||||
match PLUGINS.read().unwrap().get(id) {
|
match PLUGINS.read().unwrap().get(id) {
|
||||||
Some(plugin) => {
|
Some(plugin) => {
|
||||||
let ret = (plugin.call)(
|
let mut out = std::ptr::null_mut();
|
||||||
|
let mut out_len: usize = 0;
|
||||||
|
let ret = (plugin.server_call)(
|
||||||
METHOD_HANDLE_PEER.as_ptr() as _,
|
METHOD_HANDLE_PEER.as_ptr() as _,
|
||||||
peer.as_ptr() as _,
|
peer.as_ptr() as _,
|
||||||
event.as_ptr() as _,
|
event.as_ptr() as _,
|
||||||
event.len(),
|
event.len(),
|
||||||
|
&mut out as _,
|
||||||
|
&mut out_len as _,
|
||||||
);
|
);
|
||||||
if ret.is_null() {
|
if ret.is_null() {
|
||||||
None
|
let msg = make_plugin_request(id, out, out_len);
|
||||||
|
free_c_ptr(out as _);
|
||||||
|
msg
|
||||||
} else {
|
} else {
|
||||||
let (code, msg) = get_code_msg_from_ret(ret);
|
let (code, msg) = get_code_msg_from_ret(ret);
|
||||||
free_c_ptr(ret as _);
|
free_c_ptr(ret as _);
|
||||||
@ -421,17 +451,13 @@ pub fn handle_client_event(id: &str, peer: &str, event: &[u8]) -> Option<Message
|
|||||||
}
|
}
|
||||||
.to_owned();
|
.to_owned();
|
||||||
match code {
|
match code {
|
||||||
ERR_CALL_NOT_SUPPORTED_METHOD => Some(make_plugin_response(
|
ERR_CALL_NOT_SUPPORTED_METHOD => {
|
||||||
id,
|
make_plugin_failure(id, &name, "Plugin method is not supported")
|
||||||
&name,
|
}
|
||||||
"plugin method is not supported",
|
ERR_CALL_INVALID_ARGS => {
|
||||||
)),
|
make_plugin_failure(id, &name, "Plugin arguments is invalid")
|
||||||
ERR_CALL_INVALID_ARGS => Some(make_plugin_response(
|
}
|
||||||
id,
|
_ => make_plugin_failure(id, &name, &msg),
|
||||||
&name,
|
|
||||||
"plugin arguments is invalid",
|
|
||||||
)),
|
|
||||||
_ => Some(make_plugin_response(id, &name, &msg)),
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log::error!(
|
log::error!(
|
||||||
@ -440,17 +466,33 @@ pub fn handle_client_event(id: &str, peer: &str, event: &[u8]) -> Option<Message
|
|||||||
code,
|
code,
|
||||||
msg
|
msg
|
||||||
);
|
);
|
||||||
None
|
let msg = make_plugin_request(id, out, out_len);
|
||||||
|
free_c_ptr(out as _);
|
||||||
|
msg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => Some(make_plugin_response(id, "", "plugin not found")),
|
None => make_plugin_failure(id, "", "Plugin not found"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_plugin_response(id: &str, name: &str, msg: &str) -> Message {
|
fn make_plugin_request(id: &str, content: *const c_void, len: usize) -> Message {
|
||||||
let mut misc = Misc::new();
|
let mut misc = Misc::new();
|
||||||
misc.set_plugin_response(PluginResponse {
|
misc.set_plugin_request(PluginRequest {
|
||||||
|
id: id.to_owned(),
|
||||||
|
content: unsafe { std::slice::from_raw_parts(content as *const u8, len) }
|
||||||
|
.clone()
|
||||||
|
.into(),
|
||||||
|
..Default::default()
|
||||||
|
});
|
||||||
|
let mut msg_out = Message::new();
|
||||||
|
msg_out.set_misc(misc);
|
||||||
|
msg_out
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_plugin_failure(id: &str, name: &str, msg: &str) -> Message {
|
||||||
|
let mut misc = Misc::new();
|
||||||
|
misc.set_plugin_failure(PluginFailure {
|
||||||
id: id.to_owned(),
|
id: id.to_owned(),
|
||||||
name: name.to_owned(),
|
name: name.to_owned(),
|
||||||
msg: msg.to_owned(),
|
msg: msg.to_owned(),
|
||||||
|
@ -1813,11 +1813,9 @@ impl Connection {
|
|||||||
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
#[cfg(all(feature = "flutter", feature = "plugin_framework"))]
|
||||||
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
#[cfg(not(any(target_os = "android", target_os = "ios")))]
|
||||||
Some(misc::Union::PluginRequest(p)) => {
|
Some(misc::Union::PluginRequest(p)) => {
|
||||||
if let Some(msg) =
|
let msg =
|
||||||
crate::plugin::handle_client_event(&p.id, &self.lr.my_id, &p.content)
|
crate::plugin::handle_client_event(&p.id, &self.lr.my_id, &p.content);
|
||||||
{
|
self.send(msg).await;
|
||||||
self.send(msg).await;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user