I want to implement an addon using Rust to expose an addListener API. When I modify the system’s time zone, I can receive a callback.
using core_foundation_sys and neon
The code is as follows:
extern "C" fn notification_callback(
_center: notification_center::CFNotificationCenterRef,
_observer: *mut c_void,
_name: notification_center::CFNotificationName,
_object: *const c_void,
_user_info: CFDictionaryRef,
) {
println!("timezone_change");
}
fn init_notification {
unsafe {
let center = notification_center::CFNotificationCenterGetLocalCenter();
let observer = &Observer as *const _ as *mut c_void;
let name = CFStringCreateWithCString(
kCFAllocatorDefault,
b"kCFTimeZoneSystemTimeZoneDidChangeNotification".as_ptr() as *const i8,
kCFStringEncodingUTF8,
);
let object = ptr::null();
let suspension_behavior: isize =
CFNotificationSuspensionBehaviorDeliverImmediately as isize;
notification_center::CFNotificationCenterAddObserver(
center,
observer,
notification_callback,
name,
object,
suspension_behavior,
);
// Run the main loop to keep the application alive and responsive to notifications
CFRunLoopRun();
}
}
fn add_date_listener(mut cx: FunctionContext) -> JsResult<JsUndefined> {
let cb_name_js = &cx.argument::<JsString>(0)?;
let cb_name = cb_name_js.value(&mut cx);
if cb_name == "timezone_change" {
init_notification();
TimeZoneChangeEvent::new(cx)
} else {
Ok(cx.undefined())
}
}
fn create_date_module(cx: &mut ModuleContext) -> NeonResult<()> {
let date = cx.empty_object();
let get_timezone_fn = JsFunction::new(cx, get_timezone)?;
let add_date_listener_fn = JsFunction::new(cx, add_date_listener)?;
date.set(cx, "getTimeZone", get_timezone_fn)?;
date.set(cx, "addListener", add_date_listener_fn)?;
cx.export_value("date", date)?;
Ok(())
}
#[neon::main]
fn main(mut cx: ModuleContext) -> NeonResult<()> {
create_date_module(&mut cx)?;
Ok(())
}
nodejs usage:
const addon = require('dist/x.node');
addon.date.addListener('timezone_change', () => {
console.log(timezone_change);
})
print: timezone_change
But I can’t do anything else because the main thread of Node.js is blocked.
I have tried the following:
Modify init_notification to the following code:
fn init_notification() {
thread::spawn(move || {
unsafe {
let center = notification_center::CFNotificationCenterGetLocalCenter();
let observer = &Observer as *const _ as *mut c_void;
let name = CFStringCreateWithCString(
kCFAllocatorDefault,
b"kCFTimeZoneSystemTimeZoneDidChangeNotification".as_ptr() as *const i8,
kCFStringEncodingUTF8,
);
let object = ptr::null();
let suspension_behavior: isize =
CFNotificationSuspensionBehaviorDeliverImmediately as isize;
notification_center::CFNotificationCenterAddObserver(
center,
observer,
notification_callback,
name,
object,
suspension_behavior,
);
// Run the main loop to keep the application alive and responsive to notifications
CFRunLoopRun();
}
});
}
The result is that no notification was received,How to achieve receiving notifications without blocking the main process of Node.js?
刘北京 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.