[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
[package]
|
||||
name = "xcu-webview-bridge"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
authors = ["TSM.ID <tsm@tsm.id>"]
|
||||
description = "[TSM.ID].[11031972] xcu-webview-bridge"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1"
|
||||
@@ -0,0 +1,52 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! Bridge router for message routing between native and webview
|
||||
|
||||
use crate::{BridgeMessage, BridgeError, Result, Platform};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
pub type BridgeCallback = Box<dyn Fn(&BridgeMessage) -> Result<String> + Send + Sync>;
|
||||
|
||||
pub struct BridgeRouter {
|
||||
routes: Arc<Mutex<HashMap<String, Vec<BridgeCallback>>>>,
|
||||
platform: Platform,
|
||||
message_log: Arc<Mutex<Vec<BridgeMessage>>>,
|
||||
max_log_size: usize,
|
||||
}
|
||||
|
||||
impl BridgeRouter {
|
||||
pub fn new(platform: Platform, max_log_size: usize) -> Self {
|
||||
Self {
|
||||
routes: Arc::new(Mutex::new(HashMap::new())),
|
||||
platform,
|
||||
message_log: Arc::new(Mutex::new(Vec::new())),
|
||||
max_log_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(&self, target: &str, callback: BridgeCallback) -> Result<()> {
|
||||
let mut routes = self.routes.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
routes.entry(target.to_string()).or_default().push(callback);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn route(&self, msg: &BridgeMessage) -> Result<Vec<String>> {
|
||||
let routes = self.routes.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
let callbacks = routes.get(&msg.target).ok_or_else(|| BridgeError::InvalidTarget(msg.target.clone()))?;
|
||||
let mut results = Vec::new();
|
||||
for cb in callbacks {
|
||||
results.push(cb(msg)?);
|
||||
}
|
||||
let mut log = self.message_log.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
if log.len() < self.max_log_size {
|
||||
log.push(msg.clone());
|
||||
}
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn platform(&self) -> &Platform { &self.platform }
|
||||
|
||||
pub fn log_count(&self) -> usize {
|
||||
self.message_log.lock().map(|l| l.len()).unwrap_or(0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! xcu-webview-bridge — Native OS to WebView interface bridge
|
||||
#![deny(warnings)]
|
||||
|
||||
pub mod bridge;
|
||||
pub mod platform;
|
||||
|
||||
use serde::{Serialize, Deserialize};
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
pub enum Platform {
|
||||
Android,
|
||||
Ios,
|
||||
HarmonyOs,
|
||||
Desktop,
|
||||
WebAssembly,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct BridgeMessage {
|
||||
pub id: u64,
|
||||
pub source: Platform,
|
||||
pub target: String,
|
||||
pub payload: String,
|
||||
pub timestamp_ms: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum BridgeError {
|
||||
SerializationFailed(String),
|
||||
QueueFull,
|
||||
InvalidTarget(String),
|
||||
PlatformNotSupported(Platform),
|
||||
Timeout,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for BridgeError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::SerializationFailed(e) => write!(f, "Serialization failed: {e}"),
|
||||
Self::QueueFull => write!(f, "Message queue is full"),
|
||||
Self::InvalidTarget(t) => write!(f, "Invalid target: {t}"),
|
||||
Self::PlatformNotSupported(p) => write!(f, "Platform not supported: {p:?}"),
|
||||
Self::Timeout => write!(f, "Bridge operation timed out"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for BridgeError {}
|
||||
|
||||
pub type Result<T> = std::result::Result<T, BridgeError>;
|
||||
|
||||
pub struct MessageQueue {
|
||||
queue: Arc<Mutex<VecDeque<BridgeMessage>>>,
|
||||
capacity: usize,
|
||||
counter: Arc<Mutex<u64>>,
|
||||
}
|
||||
|
||||
impl MessageQueue {
|
||||
pub fn new(capacity: usize) -> Self {
|
||||
Self {
|
||||
queue: Arc::new(Mutex::new(VecDeque::with_capacity(capacity))),
|
||||
capacity,
|
||||
counter: Arc::new(Mutex::new(0)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enqueue(&self, mut msg: BridgeMessage) -> Result<u64> {
|
||||
let mut q = self.queue.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
if q.len() >= self.capacity {
|
||||
return Err(BridgeError::QueueFull);
|
||||
}
|
||||
let mut c = self.counter.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
*c += 1;
|
||||
msg.id = *c;
|
||||
let id = msg.id;
|
||||
q.push_back(msg);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
pub fn dequeue(&self) -> Result<Option<BridgeMessage>> {
|
||||
let mut q = self.queue.lock().map_err(|e| BridgeError::SerializationFailed(e.to_string()))?;
|
||||
Ok(q.pop_front())
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.queue.lock().map(|q| q.len()).unwrap_or(0)
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len() == 0
|
||||
}
|
||||
}
|
||||
|
||||
pub trait WebViewBridge {
|
||||
fn send(&self, msg: BridgeMessage) -> Result<u64>;
|
||||
fn receive(&self) -> Result<Option<BridgeMessage>>;
|
||||
fn eval_js(&self, script: &str) -> Result<String>;
|
||||
fn platform(&self) -> Platform;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_message_queue() {
|
||||
let q = MessageQueue::new(10);
|
||||
let msg = BridgeMessage {
|
||||
id: 0, source: Platform::Android,
|
||||
target: "ui".into(), payload: "hello".into(), timestamp_ms: 100,
|
||||
};
|
||||
let id = q.enqueue(msg).unwrap();
|
||||
assert_eq!(id, 1);
|
||||
assert!(!q.is_empty());
|
||||
let out = q.dequeue().unwrap().unwrap();
|
||||
assert_eq!(out.payload, "hello");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
//! [TSM.ID].[11031972] — Platform X Ecosystem
|
||||
//! Platform detection and capability matrix
|
||||
|
||||
use crate::{Platform, Result, BridgeError};
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct PlatformCapabilities {
|
||||
pub has_webview: bool,
|
||||
pub has_native_bridge: bool,
|
||||
pub supports_wasm: bool,
|
||||
pub max_message_size: usize,
|
||||
pub supports_binary: bool,
|
||||
pub supports_streaming: bool,
|
||||
}
|
||||
|
||||
pub struct PlatformDetector;
|
||||
|
||||
impl PlatformDetector {
|
||||
pub fn detect() -> Platform {
|
||||
#[cfg(target_os = "android")]
|
||||
return Platform::Android;
|
||||
#[cfg(target_os = "ios")]
|
||||
return Platform::Ios;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
return Platform::WebAssembly;
|
||||
#[cfg(not(any(target_os = "android", target_os = "ios", target_arch = "wasm32")))]
|
||||
Platform::Desktop
|
||||
}
|
||||
|
||||
pub fn capabilities(platform: &Platform) -> PlatformCapabilities {
|
||||
match platform {
|
||||
Platform::Android => PlatformCapabilities {
|
||||
has_webview: true, has_native_bridge: true, supports_wasm: true,
|
||||
max_message_size: 1_048_576, supports_binary: true, supports_streaming: true,
|
||||
},
|
||||
Platform::Ios => PlatformCapabilities {
|
||||
has_webview: true, has_native_bridge: true, supports_wasm: true,
|
||||
max_message_size: 1_048_576, supports_binary: true, supports_streaming: true,
|
||||
},
|
||||
Platform::HarmonyOs => PlatformCapabilities {
|
||||
has_webview: true, has_native_bridge: true, supports_wasm: true,
|
||||
max_message_size: 524_288, supports_binary: true, supports_streaming: false,
|
||||
},
|
||||
Platform::Desktop => PlatformCapabilities {
|
||||
has_webview: true, has_native_bridge: true, supports_wasm: true,
|
||||
max_message_size: 16_777_216, supports_binary: true, supports_streaming: true,
|
||||
},
|
||||
Platform::WebAssembly => PlatformCapabilities {
|
||||
has_webview: false, has_native_bridge: false, supports_wasm: true,
|
||||
max_message_size: 4_194_304, supports_binary: true, supports_streaming: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn validate_message_size(platform: &Platform, size: usize) -> Result<()> {
|
||||
let caps = Self::capabilities(platform);
|
||||
if size > caps.max_message_size {
|
||||
return Err(BridgeError::SerializationFailed(
|
||||
format!("Message size {size} exceeds platform limit {}", caps.max_message_size)
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user