#[macro_use] extern crate tracing; #[macro_use] extern crate futures; mod webbluetooth; use js_sys; use tokio_stream::StreamExt; use crate::webbluetooth::{WebBluetoothCommunicationManagerBuilder}; use buttplug_core::{ message::{ButtplugServerMessageCurrent, BUTTPLUG_CURRENT_API_MAJOR_VERSION, serializer::{ButtplugSerializedMessage, ButtplugMessageSerializer}}, util::async_manager, }; use buttplug_server::{ ButtplugServerBuilder, ButtplugServer, device::ServerDeviceManagerBuilder, message::{ButtplugServerMessageVariant, serializer::ButtplugServerJSONSerializer}, }; use buttplug_server_device_config::{DeviceConfigurationManager, load_protocol_configs}; type FFICallback = js_sys::Function; type FFICallbackContext = u32; #[derive(Clone, Copy)] pub struct FFICallbackContextWrapper(FFICallbackContext); unsafe impl Send for FFICallbackContextWrapper { } unsafe impl Sync for FFICallbackContextWrapper { } use console_error_panic_hook; use tracing_subscriber::{layer::SubscriberExt, Registry}; use tracing_wasm::{WASMLayer, WASMLayerConfig}; use wasm_bindgen::prelude::*; use std::sync::Arc; use js_sys::Uint8Array; pub type ButtplugWASMServer = Arc; pub fn send_server_message( message: &ButtplugServerMessageCurrent, callback: &FFICallback, ) { let serializer = ButtplugServerJSONSerializer::default(); serializer.force_message_version(&BUTTPLUG_CURRENT_API_MAJOR_VERSION); let json_msg = serializer.serialize(&[ButtplugServerMessageVariant::V4(message.clone())]); if let ButtplugSerializedMessage::Text(json) = json_msg { let buf = json.as_bytes(); let this = JsValue::null(); let uint8buf = unsafe { Uint8Array::new(&Uint8Array::view(buf)) }; callback.call1(&this, &JsValue::from(uint8buf)); } } #[no_mangle] pub fn create_test_dcm(_allow_raw_messages: bool) -> DeviceConfigurationManager { load_protocol_configs(&None, &None, false) .expect("If this fails, the whole library goes with it.") .finish() .expect("If this fails, the whole library goes with it.") } #[no_mangle] #[wasm_bindgen] pub fn buttplug_create_embedded_wasm_server( callback: &FFICallback, ) -> *mut ButtplugWASMServer { console_error_panic_hook::set_once(); let dcm = create_test_dcm(false); let mut sdm = ServerDeviceManagerBuilder::new(dcm); sdm.comm_manager(WebBluetoothCommunicationManagerBuilder::default()); let builder = ButtplugServerBuilder::new(sdm.finish().unwrap()); let server = Arc::new(builder.finish().unwrap()); let event_stream = server.server_version_event_stream(); let callback = callback.clone(); async_manager::spawn(async move { pin_mut!(event_stream); while let Some(message) = event_stream.next().await { send_server_message(&message, &callback); } }); Box::into_raw(Box::new(server)) } #[no_mangle] #[wasm_bindgen] pub fn buttplug_free_embedded_wasm_server(ptr: *mut ButtplugWASMServer) { if !ptr.is_null() { unsafe { let _ = Box::from_raw(ptr); } } } #[no_mangle] #[wasm_bindgen] pub fn buttplug_client_send_json_message( server_ptr: *mut ButtplugWASMServer, buf: &[u8], callback: &FFICallback, ) { let server = unsafe { assert!(!server_ptr.is_null()); &mut *server_ptr }; let callback = callback.clone(); let serializer = ButtplugServerJSONSerializer::default(); serializer.force_message_version(&BUTTPLUG_CURRENT_API_MAJOR_VERSION); let input_msg = serializer.deserialize(&ButtplugSerializedMessage::Text(std::str::from_utf8(buf).unwrap().to_owned())).unwrap(); async_manager::spawn(async move { let msg = input_msg[0].clone(); let response = server.parse_message(msg).await.unwrap(); let json_msg = serializer.serialize(&[response]); if let ButtplugSerializedMessage::Text(json) = json_msg { let buf = json.as_bytes(); let this = JsValue::null(); let uint8buf = unsafe { Uint8Array::new(&Uint8Array::view(buf)) }; callback.call1(&this, &JsValue::from(uint8buf)); } }); } #[no_mangle] #[wasm_bindgen] pub fn buttplug_activate_env_logger(_max_level: &str) { tracing::subscriber::set_global_default( Registry::default() //.with(EnvFilter::new(max_level)) .with(WASMLayer::new(WASMLayerConfig::default())), ) .expect("default global"); }