Reformat the source code
This commit is contained in:
@@ -14,173 +14,217 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use std::{mem, ptr};
|
||||
use std::ffi::c_void;
|
||||
use std::sync::Arc;
|
||||
use std::{ffi::c_void, mem, ptr, sync::Arc};
|
||||
|
||||
use {Callback, parity_config_from_cli, parity_destroy, parity_rpc_worker, parity_start, parity_set_logger,
|
||||
parity_unsubscribe_ws, parity_ws_worker, ParityParams};
|
||||
use parity_config_from_cli;
|
||||
use parity_destroy;
|
||||
use parity_rpc_worker;
|
||||
use parity_set_logger;
|
||||
use parity_start;
|
||||
use parity_unsubscribe_ws;
|
||||
use parity_ws_worker;
|
||||
use Callback;
|
||||
use ParityParams;
|
||||
|
||||
use jni::{JavaVM, JNIEnv};
|
||||
use jni::objects::{JClass, JString, JObject, JValue, GlobalRef};
|
||||
use jni::sys::{jlong, jobjectArray, va_list};
|
||||
use jni::{
|
||||
objects::{GlobalRef, JClass, JObject, JString, JValue},
|
||||
sys::{jlong, jobjectArray, va_list},
|
||||
JNIEnv, JavaVM,
|
||||
};
|
||||
use parity_ethereum::RunningClient;
|
||||
|
||||
type CheckedQuery<'a> = (&'a RunningClient, String, JavaVM, GlobalRef);
|
||||
|
||||
// Creates a Java callback to a static method named `void callback(Object)`
|
||||
struct JavaCallback<'a> {
|
||||
jvm: JavaVM,
|
||||
callback: GlobalRef,
|
||||
method_name: &'a str,
|
||||
method_descriptor: &'a str,
|
||||
jvm: JavaVM,
|
||||
callback: GlobalRef,
|
||||
method_name: &'a str,
|
||||
method_descriptor: &'a str,
|
||||
}
|
||||
|
||||
impl<'a> JavaCallback<'a> {
|
||||
fn new(jvm: JavaVM, callback: GlobalRef) -> Self {
|
||||
Self {
|
||||
jvm,
|
||||
callback,
|
||||
method_name: "callback",
|
||||
method_descriptor: "(Ljava/lang/Object;)V",
|
||||
}
|
||||
}
|
||||
fn new(jvm: JavaVM, callback: GlobalRef) -> Self {
|
||||
Self {
|
||||
jvm,
|
||||
callback,
|
||||
method_name: "callback",
|
||||
method_descriptor: "(Ljava/lang/Object;)V",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Callback for JavaCallback<'a> {
|
||||
fn call(&self, msg: &str) {
|
||||
let env = self.jvm.attach_current_thread().expect("JavaVM should have an environment; qed");
|
||||
let java_str = env.new_string(msg.to_string()).expect("Rust String is valid JString; qed");
|
||||
let val = &[JValue::Object(JObject::from(java_str))];
|
||||
env.call_method(self.callback.as_obj(), self.method_name, self.method_descriptor, val).expect(
|
||||
"The callback must be an instance method and be named \"void callback(Object)\"; qed)");
|
||||
}
|
||||
fn call(&self, msg: &str) {
|
||||
let env = self
|
||||
.jvm
|
||||
.attach_current_thread()
|
||||
.expect("JavaVM should have an environment; qed");
|
||||
let java_str = env
|
||||
.new_string(msg.to_string())
|
||||
.expect("Rust String is valid JString; qed");
|
||||
let val = &[JValue::Object(JObject::from(java_str))];
|
||||
env.call_method(
|
||||
self.callback.as_obj(),
|
||||
self.method_name,
|
||||
self.method_descriptor,
|
||||
val,
|
||||
)
|
||||
.expect(
|
||||
"The callback must be an instance method and be named \"void callback(Object)\"; qed)",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_configFromCli(env: JNIEnv, _: JClass, cli: jobjectArray) -> jlong {
|
||||
let cli_len = env.get_array_length(cli).expect("invalid Java bindings") as usize;
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_configFromCli(
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
cli: jobjectArray,
|
||||
) -> jlong {
|
||||
let cli_len = env.get_array_length(cli).expect("invalid Java bindings") as usize;
|
||||
|
||||
let mut jni_strings = Vec::with_capacity(cli_len);
|
||||
let mut opts = Vec::with_capacity(cli_len);
|
||||
let mut opts_lens = Vec::with_capacity(cli_len);
|
||||
let mut jni_strings = Vec::with_capacity(cli_len);
|
||||
let mut opts = Vec::with_capacity(cli_len);
|
||||
let mut opts_lens = Vec::with_capacity(cli_len);
|
||||
|
||||
for n in 0..cli_len as i32 {
|
||||
let elem = env.get_object_array_element(cli, n).expect("invalid Java bindings");
|
||||
let elem_str: JString = elem.into();
|
||||
match env.get_string(elem_str) {
|
||||
Ok(s) => {
|
||||
opts.push(s.as_ptr());
|
||||
opts_lens.push(s.to_bytes().len());
|
||||
jni_strings.push(s);
|
||||
}
|
||||
Err(err) => {
|
||||
let _ = env.throw_new("java/lang/Exception", err.to_string());
|
||||
return 0
|
||||
}
|
||||
};
|
||||
}
|
||||
for n in 0..cli_len as i32 {
|
||||
let elem = env
|
||||
.get_object_array_element(cli, n)
|
||||
.expect("invalid Java bindings");
|
||||
let elem_str: JString = elem.into();
|
||||
match env.get_string(elem_str) {
|
||||
Ok(s) => {
|
||||
opts.push(s.as_ptr());
|
||||
opts_lens.push(s.to_bytes().len());
|
||||
jni_strings.push(s);
|
||||
}
|
||||
Err(err) => {
|
||||
let _ = env.throw_new("java/lang/Exception", err.to_string());
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
let mut out = ptr::null_mut();
|
||||
match parity_config_from_cli(opts.as_ptr(), opts_lens.as_ptr(), cli_len, &mut out) {
|
||||
0 => out as jlong,
|
||||
_ => {
|
||||
let _ = env.throw_new("java/lang/Exception", "failed to create config object");
|
||||
0
|
||||
},
|
||||
}
|
||||
let mut out = ptr::null_mut();
|
||||
match parity_config_from_cli(opts.as_ptr(), opts_lens.as_ptr(), cli_len, &mut out) {
|
||||
0 => out as jlong,
|
||||
_ => {
|
||||
let _ = env.throw_new("java/lang/Exception", "failed to create config object");
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_build(
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
config: va_list,
|
||||
logger_mode: JString,
|
||||
logger_file: JString
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
config: va_list,
|
||||
logger_mode: JString,
|
||||
logger_file: JString,
|
||||
) -> jlong {
|
||||
let mut params = ParityParams {
|
||||
configuration: config,
|
||||
.. mem::zeroed()
|
||||
};
|
||||
let mut params = ParityParams {
|
||||
configuration: config,
|
||||
..mem::zeroed()
|
||||
};
|
||||
|
||||
let logger_mode: String = env.get_string(logger_mode).expect("valid JString; qed").into();
|
||||
let logger_file: String = env.get_string(logger_file).expect("valid JString; qed").into();
|
||||
let logger_mode: String = env
|
||||
.get_string(logger_mode)
|
||||
.expect("valid JString; qed")
|
||||
.into();
|
||||
let logger_file: String = env
|
||||
.get_string(logger_file)
|
||||
.expect("valid JString; qed")
|
||||
.into();
|
||||
|
||||
parity_set_logger(logger_mode.as_ptr(), logger_mode.as_bytes().len(), logger_file.as_ptr(),
|
||||
logger_file.as_bytes().len(), &mut params.logger);
|
||||
parity_set_logger(
|
||||
logger_mode.as_ptr(),
|
||||
logger_mode.as_bytes().len(),
|
||||
logger_file.as_ptr(),
|
||||
logger_file.as_bytes().len(),
|
||||
&mut params.logger,
|
||||
);
|
||||
|
||||
let mut out = ptr::null_mut();
|
||||
match parity_start(¶ms, &mut out) {
|
||||
0 => out as jlong,
|
||||
_ => {
|
||||
let _ = env.throw_new("java/lang/Exception", "failed to start Parity");
|
||||
0
|
||||
}
|
||||
}
|
||||
let mut out = ptr::null_mut();
|
||||
match parity_start(¶ms, &mut out) {
|
||||
0 => out as jlong,
|
||||
_ => {
|
||||
let _ = env.throw_new("java/lang/Exception", "failed to start Parity");
|
||||
0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_destroy(_env: JNIEnv, _: JClass, parity: va_list) {
|
||||
parity_destroy(parity);
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_destroy(
|
||||
_env: JNIEnv,
|
||||
_: JClass,
|
||||
parity: va_list,
|
||||
) {
|
||||
parity_destroy(parity);
|
||||
}
|
||||
|
||||
unsafe fn java_query_checker<'a>(client: va_list, rpc: JString, callback: JObject, env: &JNIEnv<'a>)
|
||||
-> Result<CheckedQuery<'a>, String> {
|
||||
let query: String = env.get_string(rpc)
|
||||
.map(Into::into)
|
||||
.map_err(|e| e.to_string())?;
|
||||
unsafe fn java_query_checker<'a>(
|
||||
client: va_list,
|
||||
rpc: JString,
|
||||
callback: JObject,
|
||||
env: &JNIEnv<'a>,
|
||||
) -> Result<CheckedQuery<'a>, String> {
|
||||
let query: String = env
|
||||
.get_string(rpc)
|
||||
.map(Into::into)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let client: &RunningClient = &*(client as *const RunningClient);
|
||||
let jvm = env.get_java_vm().map_err(|e| e.to_string())?;
|
||||
let global_ref = env.new_global_ref(callback).map_err(|e| e.to_string())?;
|
||||
Ok((client, query, jvm, global_ref))
|
||||
let client: &RunningClient = &*(client as *const RunningClient);
|
||||
let jvm = env.get_java_vm().map_err(|e| e.to_string())?;
|
||||
let global_ref = env.new_global_ref(callback).map_err(|e| e.to_string())?;
|
||||
Ok((client, query, jvm, global_ref))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_rpcQueryNative(
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
parity: va_list,
|
||||
rpc: JString,
|
||||
timeout_ms: jlong,
|
||||
callback: JObject,
|
||||
)
|
||||
{
|
||||
let _ = java_query_checker(parity, rpc, callback, &env)
|
||||
.map(|(client, query, jvm, global_ref)| {
|
||||
let callback = Arc::new(JavaCallback::new(jvm, global_ref));
|
||||
parity_rpc_worker(client, &query, callback, timeout_ms as u64);
|
||||
})
|
||||
.map_err(|e| {
|
||||
let _ = env.throw_new("java/lang/Exception", e);
|
||||
});
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
parity: va_list,
|
||||
rpc: JString,
|
||||
timeout_ms: jlong,
|
||||
callback: JObject,
|
||||
) {
|
||||
let _ = java_query_checker(parity, rpc, callback, &env)
|
||||
.map(|(client, query, jvm, global_ref)| {
|
||||
let callback = Arc::new(JavaCallback::new(jvm, global_ref));
|
||||
parity_rpc_worker(client, &query, callback, timeout_ms as u64);
|
||||
})
|
||||
.map_err(|e| {
|
||||
let _ = env.throw_new("java/lang/Exception", e);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_subscribeWebSocketNative(
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
parity: va_list,
|
||||
rpc: JString,
|
||||
callback: JObject,
|
||||
) -> va_list {
|
||||
|
||||
java_query_checker(parity, rpc, callback, &env)
|
||||
.map(move |(client, query, jvm, global_ref)| {
|
||||
let callback = Arc::new(JavaCallback::new(jvm, global_ref));
|
||||
parity_ws_worker(client, &query, callback) as va_list
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
let _ = env.throw_new("java/lang/Exception", e);
|
||||
ptr::null_mut()
|
||||
})
|
||||
env: JNIEnv,
|
||||
_: JClass,
|
||||
parity: va_list,
|
||||
rpc: JString,
|
||||
callback: JObject,
|
||||
) -> va_list {
|
||||
java_query_checker(parity, rpc, callback, &env)
|
||||
.map(move |(client, query, jvm, global_ref)| {
|
||||
let callback = Arc::new(JavaCallback::new(jvm, global_ref));
|
||||
parity_ws_worker(client, &query, callback) as va_list
|
||||
})
|
||||
.unwrap_or_else(|e| {
|
||||
let _ = env.throw_new("java/lang/Exception", e);
|
||||
ptr::null_mut()
|
||||
})
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "system" fn Java_io_parity_ethereum_Parity_unsubscribeWebSocketNative(
|
||||
_: JNIEnv,
|
||||
_: JClass,
|
||||
session: va_list) {
|
||||
parity_unsubscribe_ws(session as *const c_void);
|
||||
_: JNIEnv,
|
||||
_: JClass,
|
||||
session: va_list,
|
||||
) {
|
||||
parity_unsubscribe_ws(session as *const c_void);
|
||||
}
|
||||
|
||||
@@ -29,14 +29,16 @@ extern crate jni;
|
||||
#[cfg(feature = "jni")]
|
||||
mod java;
|
||||
|
||||
use std::ffi::CString;
|
||||
use std::os::raw::{c_char, c_void, c_int};
|
||||
use std::{panic, ptr, slice, str, thread};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
ffi::CString,
|
||||
os::raw::{c_char, c_int, c_void},
|
||||
panic, ptr, slice, str,
|
||||
sync::Arc,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use futures::{Future, Stream};
|
||||
use futures::sync::mpsc;
|
||||
use futures::{sync::mpsc, Future, Stream};
|
||||
use parity_ethereum::{PubSubSession, RunningClient};
|
||||
use tokio_current_thread::CurrentThread;
|
||||
|
||||
@@ -44,261 +46,293 @@ type CCallback = Option<extern "C" fn(*mut c_void, *const c_char, usize)>;
|
||||
type CheckedQuery<'a> = (&'a RunningClient, &'static str);
|
||||
|
||||
pub mod error {
|
||||
pub const EMPTY: &str = r#"{"jsonrpc":"2.0","result":"null","id":1}"#;
|
||||
pub const TIMEOUT: &str = r#"{"jsonrpc":"2.0","result":"timeout","id":1}"#;
|
||||
pub const SUBSCRIBE: &str = r#"{"jsonrpc":"2.0","result":"subcribe_fail","id":1}"#;
|
||||
pub const EMPTY: &str = r#"{"jsonrpc":"2.0","result":"null","id":1}"#;
|
||||
pub const TIMEOUT: &str = r#"{"jsonrpc":"2.0","result":"timeout","id":1}"#;
|
||||
pub const SUBSCRIBE: &str = r#"{"jsonrpc":"2.0","result":"subcribe_fail","id":1}"#;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ParityParams {
|
||||
pub configuration: *mut c_void,
|
||||
pub on_client_restart_cb: CCallback,
|
||||
pub on_client_restart_cb_custom: *mut c_void,
|
||||
pub logger: *mut c_void
|
||||
pub configuration: *mut c_void,
|
||||
pub on_client_restart_cb: CCallback,
|
||||
pub on_client_restart_cb_custom: *mut c_void,
|
||||
pub logger: *mut c_void,
|
||||
}
|
||||
|
||||
/// Trait representing a callback that passes a string
|
||||
pub(crate) trait Callback: Send + Sync {
|
||||
fn call(&self, msg: &str);
|
||||
fn call(&self, msg: &str);
|
||||
}
|
||||
|
||||
// Internal structure for handling callbacks that get passed a string.
|
||||
struct CallbackStr {
|
||||
user_data: *mut c_void,
|
||||
function: CCallback,
|
||||
user_data: *mut c_void,
|
||||
function: CCallback,
|
||||
}
|
||||
|
||||
unsafe impl Send for CallbackStr {}
|
||||
unsafe impl Sync for CallbackStr {}
|
||||
impl Callback for CallbackStr {
|
||||
fn call(&self, msg: &str) {
|
||||
if let Some(ref cb) = self.function {
|
||||
let cstr = CString::new(msg).expect("valid string with no nul bytes in the middle; qed").into_raw();
|
||||
cb(self.user_data, cstr, msg.len())
|
||||
}
|
||||
}
|
||||
fn call(&self, msg: &str) {
|
||||
if let Some(ref cb) = self.function {
|
||||
let cstr = CString::new(msg)
|
||||
.expect("valid string with no nul bytes in the middle; qed")
|
||||
.into_raw();
|
||||
cb(self.user_data, cstr, msg.len())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_config_from_cli(
|
||||
args: *const *const c_char,
|
||||
args_lens: *const usize,
|
||||
len: usize,
|
||||
output: *mut *mut c_void
|
||||
pub unsafe extern "C" fn parity_config_from_cli(
|
||||
args: *const *const c_char,
|
||||
args_lens: *const usize,
|
||||
len: usize,
|
||||
output: *mut *mut c_void,
|
||||
) -> c_int {
|
||||
panic::catch_unwind(|| {
|
||||
*output = ptr::null_mut();
|
||||
panic::catch_unwind(|| {
|
||||
*output = ptr::null_mut();
|
||||
|
||||
let args = {
|
||||
let arg_ptrs = slice::from_raw_parts(args, len);
|
||||
let arg_lens = slice::from_raw_parts(args_lens, len);
|
||||
let args = {
|
||||
let arg_ptrs = slice::from_raw_parts(args, len);
|
||||
let arg_lens = slice::from_raw_parts(args_lens, len);
|
||||
|
||||
let mut args = Vec::with_capacity(len + 1);
|
||||
args.push("parity".to_owned());
|
||||
let mut args = Vec::with_capacity(len + 1);
|
||||
args.push("parity".to_owned());
|
||||
|
||||
for (&arg, &len) in arg_ptrs.iter().zip(arg_lens.iter()) {
|
||||
let string = slice::from_raw_parts(arg as *const u8, len);
|
||||
match String::from_utf8(string.to_owned()) {
|
||||
Ok(a) => args.push(a),
|
||||
Err(_) => return 1,
|
||||
};
|
||||
}
|
||||
args
|
||||
};
|
||||
for (&arg, &len) in arg_ptrs.iter().zip(arg_lens.iter()) {
|
||||
let string = slice::from_raw_parts(arg as *const u8, len);
|
||||
match String::from_utf8(string.to_owned()) {
|
||||
Ok(a) => args.push(a),
|
||||
Err(_) => return 1,
|
||||
};
|
||||
}
|
||||
args
|
||||
};
|
||||
|
||||
match parity_ethereum::Configuration::parse_cli(&args) {
|
||||
Ok(mut cfg) => {
|
||||
// Always disable the auto-updater when used as a library.
|
||||
cfg.args.arg_auto_update = "none".to_owned();
|
||||
match parity_ethereum::Configuration::parse_cli(&args) {
|
||||
Ok(mut cfg) => {
|
||||
// Always disable the auto-updater when used as a library.
|
||||
cfg.args.arg_auto_update = "none".to_owned();
|
||||
|
||||
let cfg = Box::into_raw(Box::new(cfg));
|
||||
*output = cfg as *mut _;
|
||||
0
|
||||
},
|
||||
Err(_) => {
|
||||
1
|
||||
},
|
||||
}
|
||||
}).unwrap_or(1)
|
||||
let cfg = Box::into_raw(Box::new(cfg));
|
||||
*output = cfg as *mut _;
|
||||
0
|
||||
}
|
||||
Err(_) => 1,
|
||||
}
|
||||
})
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_config_destroy(cfg: *mut c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let _cfg = Box::from_raw(cfg as *mut parity_ethereum::Configuration);
|
||||
});
|
||||
pub unsafe extern "C" fn parity_config_destroy(cfg: *mut c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let _cfg = Box::from_raw(cfg as *mut parity_ethereum::Configuration);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) -> c_int {
|
||||
panic::catch_unwind(|| {
|
||||
*output = ptr::null_mut();
|
||||
let cfg: &ParityParams = &*cfg;
|
||||
let logger = Arc::from_raw(cfg.logger as *mut parity_ethereum::RotatingLogger);
|
||||
let config = Box::from_raw(cfg.configuration as *mut parity_ethereum::Configuration);
|
||||
pub unsafe extern "C" fn parity_start(cfg: *const ParityParams, output: *mut *mut c_void) -> c_int {
|
||||
panic::catch_unwind(|| {
|
||||
*output = ptr::null_mut();
|
||||
let cfg: &ParityParams = &*cfg;
|
||||
let logger = Arc::from_raw(cfg.logger as *mut parity_ethereum::RotatingLogger);
|
||||
let config = Box::from_raw(cfg.configuration as *mut parity_ethereum::Configuration);
|
||||
|
||||
let on_client_restart_cb = {
|
||||
let cb = CallbackStr {
|
||||
user_data: cfg.on_client_restart_cb_custom,
|
||||
function: cfg.on_client_restart_cb,
|
||||
};
|
||||
move |new_chain: String| { cb.call(&new_chain); }
|
||||
};
|
||||
let on_client_restart_cb = {
|
||||
let cb = CallbackStr {
|
||||
user_data: cfg.on_client_restart_cb_custom,
|
||||
function: cfg.on_client_restart_cb,
|
||||
};
|
||||
move |new_chain: String| {
|
||||
cb.call(&new_chain);
|
||||
}
|
||||
};
|
||||
|
||||
let action = match parity_ethereum::start(*config, logger, on_client_restart_cb, || {}) {
|
||||
Ok(action) => action,
|
||||
Err(_) => return 1,
|
||||
};
|
||||
let action = match parity_ethereum::start(*config, logger, on_client_restart_cb, || {}) {
|
||||
Ok(action) => action,
|
||||
Err(_) => return 1,
|
||||
};
|
||||
|
||||
match action {
|
||||
parity_ethereum::ExecutionAction::Instant(Some(s)) => { println!("{}", s); 0 },
|
||||
parity_ethereum::ExecutionAction::Instant(None) => 0,
|
||||
parity_ethereum::ExecutionAction::Running(client) => {
|
||||
*output = Box::into_raw(Box::new(client)) as *mut c_void;
|
||||
0
|
||||
}
|
||||
}
|
||||
}).unwrap_or(1)
|
||||
match action {
|
||||
parity_ethereum::ExecutionAction::Instant(Some(s)) => {
|
||||
println!("{}", s);
|
||||
0
|
||||
}
|
||||
parity_ethereum::ExecutionAction::Instant(None) => 0,
|
||||
parity_ethereum::ExecutionAction::Running(client) => {
|
||||
*output = Box::into_raw(Box::new(client)) as *mut c_void;
|
||||
0
|
||||
}
|
||||
}
|
||||
})
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_destroy(client: *mut c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let client = Box::from_raw(client as *mut RunningClient);
|
||||
client.shutdown();
|
||||
});
|
||||
pub unsafe extern "C" fn parity_destroy(client: *mut c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let client = Box::from_raw(client as *mut RunningClient);
|
||||
client.shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_rpc(
|
||||
client: *const c_void,
|
||||
query: *const c_char,
|
||||
len: usize,
|
||||
timeout_ms: usize,
|
||||
callback: CCallback,
|
||||
user_data: *mut c_void,
|
||||
pub unsafe extern "C" fn parity_rpc(
|
||||
client: *const c_void,
|
||||
query: *const c_char,
|
||||
len: usize,
|
||||
timeout_ms: usize,
|
||||
callback: CCallback,
|
||||
user_data: *mut c_void,
|
||||
) -> c_int {
|
||||
panic::catch_unwind(|| {
|
||||
if let Some((client, query)) = parity_rpc_query_checker(client, query, len) {
|
||||
let callback = Arc::new(CallbackStr {user_data, function: callback} );
|
||||
parity_rpc_worker(client, query, callback, timeout_ms as u64);
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
}).unwrap_or(1)
|
||||
panic::catch_unwind(|| {
|
||||
if let Some((client, query)) = parity_rpc_query_checker(client, query, len) {
|
||||
let callback = Arc::new(CallbackStr {
|
||||
user_data,
|
||||
function: callback,
|
||||
});
|
||||
parity_rpc_worker(client, query, callback, timeout_ms as u64);
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
})
|
||||
.unwrap_or(1)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_subscribe_ws(
|
||||
client: *const c_void,
|
||||
query: *const c_char,
|
||||
len: usize,
|
||||
callback: CCallback,
|
||||
user_data: *mut c_void,
|
||||
pub unsafe extern "C" fn parity_subscribe_ws(
|
||||
client: *const c_void,
|
||||
query: *const c_char,
|
||||
len: usize,
|
||||
callback: CCallback,
|
||||
user_data: *mut c_void,
|
||||
) -> *const c_void {
|
||||
panic::catch_unwind(|| {
|
||||
if let Some((client, query)) = parity_rpc_query_checker(client, query, len) {
|
||||
let callback = Arc::new(CallbackStr { user_data, function: callback});
|
||||
parity_ws_worker(client, query, callback)
|
||||
} else {
|
||||
ptr::null()
|
||||
}
|
||||
})
|
||||
.unwrap_or(ptr::null())
|
||||
panic::catch_unwind(|| {
|
||||
if let Some((client, query)) = parity_rpc_query_checker(client, query, len) {
|
||||
let callback = Arc::new(CallbackStr {
|
||||
user_data,
|
||||
function: callback,
|
||||
});
|
||||
parity_ws_worker(client, query, callback)
|
||||
} else {
|
||||
ptr::null()
|
||||
}
|
||||
})
|
||||
.unwrap_or(ptr::null())
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_unsubscribe_ws(session: *const c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let _session = Arc::from_raw(session as *const PubSubSession);
|
||||
});
|
||||
pub unsafe extern "C" fn parity_unsubscribe_ws(session: *const c_void) {
|
||||
let _ = panic::catch_unwind(|| {
|
||||
let _session = Arc::from_raw(session as *const PubSubSession);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn parity_set_panic_hook(callback: CCallback, param: *mut c_void) {
|
||||
let cb = CallbackStr {user_data: param, function: callback};
|
||||
panic_hook::set_with(move |panic_msg| {
|
||||
cb.call(panic_msg);
|
||||
});
|
||||
pub extern "C" fn parity_set_panic_hook(callback: CCallback, param: *mut c_void) {
|
||||
let cb = CallbackStr {
|
||||
user_data: param,
|
||||
function: callback,
|
||||
};
|
||||
panic_hook::set_with(move |panic_msg| {
|
||||
cb.call(panic_msg);
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern fn parity_set_logger(
|
||||
logger_mode: *const u8,
|
||||
logger_mode_len: usize,
|
||||
log_file: *const u8,
|
||||
log_file_len: usize,
|
||||
logger: *mut *mut c_void) {
|
||||
pub unsafe extern "C" fn parity_set_logger(
|
||||
logger_mode: *const u8,
|
||||
logger_mode_len: usize,
|
||||
log_file: *const u8,
|
||||
log_file_len: usize,
|
||||
logger: *mut *mut c_void,
|
||||
) {
|
||||
let mut logger_cfg = parity_ethereum::LoggerConfig::default();
|
||||
logger_cfg.mode =
|
||||
String::from_utf8(slice::from_raw_parts(logger_mode, logger_mode_len).to_owned()).ok();
|
||||
|
||||
let mut logger_cfg = parity_ethereum::LoggerConfig::default();
|
||||
logger_cfg.mode = String::from_utf8(slice::from_raw_parts(logger_mode, logger_mode_len).to_owned()).ok();
|
||||
// Make sure an empty string is not constructed as file name (to prevent panic)
|
||||
if log_file_len != 0 && !log_file.is_null() {
|
||||
logger_cfg.file =
|
||||
String::from_utf8(slice::from_raw_parts(log_file, log_file_len).to_owned()).ok();
|
||||
}
|
||||
|
||||
// Make sure an empty string is not constructed as file name (to prevent panic)
|
||||
if log_file_len != 0 && !log_file.is_null() {
|
||||
logger_cfg.file = String::from_utf8(slice::from_raw_parts(log_file, log_file_len).to_owned()).ok();
|
||||
}
|
||||
|
||||
*logger = Arc::into_raw(parity_ethereum::setup_log(&logger_cfg).expect("Logger initialized only once; qed")) as *mut _;
|
||||
*logger = Arc::into_raw(
|
||||
parity_ethereum::setup_log(&logger_cfg).expect("Logger initialized only once; qed"),
|
||||
) as *mut _;
|
||||
}
|
||||
|
||||
// WebSocket event loop
|
||||
fn parity_ws_worker(client: &RunningClient, query: &str, callback: Arc<Callback>) -> *const c_void {
|
||||
let (tx, mut rx) = mpsc::channel(1);
|
||||
let session = Arc::new(PubSubSession::new(tx));
|
||||
let query_future = client.rpc_query(query, Some(session.clone()));
|
||||
let weak_session = Arc::downgrade(&session);
|
||||
let _handle = thread::Builder::new()
|
||||
.name("ws-subscriber".into())
|
||||
.spawn(move || {
|
||||
// Wait for subscription ID
|
||||
// Note this may block forever and be can't destroyed using the session object
|
||||
// However, this will likely timeout or be catched the RPC layer
|
||||
if let Ok(Some(response)) = query_future.wait() {
|
||||
callback.call(&response);
|
||||
} else {
|
||||
callback.call(error::SUBSCRIBE);
|
||||
return;
|
||||
}
|
||||
let (tx, mut rx) = mpsc::channel(1);
|
||||
let session = Arc::new(PubSubSession::new(tx));
|
||||
let query_future = client.rpc_query(query, Some(session.clone()));
|
||||
let weak_session = Arc::downgrade(&session);
|
||||
let _handle = thread::Builder::new()
|
||||
.name("ws-subscriber".into())
|
||||
.spawn(move || {
|
||||
// Wait for subscription ID
|
||||
// Note this may block forever and be can't destroyed using the session object
|
||||
// However, this will likely timeout or be catched the RPC layer
|
||||
if let Ok(Some(response)) = query_future.wait() {
|
||||
callback.call(&response);
|
||||
} else {
|
||||
callback.call(error::SUBSCRIBE);
|
||||
return;
|
||||
}
|
||||
|
||||
while weak_session.upgrade().map_or(0, |session| Arc::strong_count(&session)) > 1 {
|
||||
for response in rx.by_ref().wait() {
|
||||
if let Ok(r) = response {
|
||||
callback.call(&r);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.expect("rpc-subscriber thread shouldn't fail; qed");
|
||||
Arc::into_raw(session) as *const c_void
|
||||
while weak_session
|
||||
.upgrade()
|
||||
.map_or(0, |session| Arc::strong_count(&session))
|
||||
> 1
|
||||
{
|
||||
for response in rx.by_ref().wait() {
|
||||
if let Ok(r) = response {
|
||||
callback.call(&r);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.expect("rpc-subscriber thread shouldn't fail; qed");
|
||||
Arc::into_raw(session) as *const c_void
|
||||
}
|
||||
|
||||
// RPC event loop that runs for at most `timeout_ms`
|
||||
fn parity_rpc_worker(client: &RunningClient, query: &str, callback: Arc<Callback>, timeout_ms: u64) {
|
||||
let cb = callback.clone();
|
||||
let query = client.rpc_query(query, None).map(move |response| {
|
||||
let response = response.unwrap_or_else(|| error::EMPTY.to_string());
|
||||
callback.call(&response);
|
||||
});
|
||||
fn parity_rpc_worker(
|
||||
client: &RunningClient,
|
||||
query: &str,
|
||||
callback: Arc<Callback>,
|
||||
timeout_ms: u64,
|
||||
) {
|
||||
let cb = callback.clone();
|
||||
let query = client.rpc_query(query, None).map(move |response| {
|
||||
let response = response.unwrap_or_else(|| error::EMPTY.to_string());
|
||||
callback.call(&response);
|
||||
});
|
||||
|
||||
let _handle = thread::Builder::new()
|
||||
.name("rpc_query".to_string())
|
||||
.spawn(move || {
|
||||
let mut current_thread = CurrentThread::new();
|
||||
current_thread.spawn(query);
|
||||
let _ = current_thread
|
||||
.run_timeout(Duration::from_millis(timeout_ms))
|
||||
.map_err(|_e| {
|
||||
cb.call(error::TIMEOUT);
|
||||
});
|
||||
})
|
||||
.expect("rpc-query thread shouldn't fail; qed");
|
||||
let _handle = thread::Builder::new()
|
||||
.name("rpc_query".to_string())
|
||||
.spawn(move || {
|
||||
let mut current_thread = CurrentThread::new();
|
||||
current_thread.spawn(query);
|
||||
let _ = current_thread
|
||||
.run_timeout(Duration::from_millis(timeout_ms))
|
||||
.map_err(|_e| {
|
||||
cb.call(error::TIMEOUT);
|
||||
});
|
||||
})
|
||||
.expect("rpc-query thread shouldn't fail; qed");
|
||||
}
|
||||
|
||||
unsafe fn parity_rpc_query_checker<'a>(client: *const c_void, query: *const c_char, len: usize)
|
||||
-> Option<CheckedQuery<'a>>
|
||||
{
|
||||
let query_str = str::from_utf8(slice::from_raw_parts(query as *const u8, len)).ok()?;
|
||||
let client: &RunningClient = &*(client as *const RunningClient);
|
||||
Some((client, query_str))
|
||||
unsafe fn parity_rpc_query_checker<'a>(
|
||||
client: *const c_void,
|
||||
query: *const c_char,
|
||||
len: usize,
|
||||
) -> Option<CheckedQuery<'a>> {
|
||||
let query_str = str::from_utf8(slice::from_raw_parts(query as *const u8, len)).ok()?;
|
||||
let client: &RunningClient = &*(client as *const RunningClient);
|
||||
Some((client, query_str))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user