Graphite/desktop/src/cef/ipc.rs

113 lines
3.4 KiB
Rust

use cef::{CefString, Frame, ImplBinaryValue, ImplFrame, ImplListValue, ImplProcessMessage, ImplV8Context, ProcessId, V8Context, sys::cef_process_id_t};
pub(crate) enum MessageType {
Initialized,
SendToJS,
SendToNative,
}
impl From<MessageType> for MessageInfo {
fn from(val: MessageType) -> Self {
match val {
MessageType::Initialized => MessageInfo {
name: "initialized".to_string(),
target: cef_process_id_t::PID_BROWSER.into(),
},
MessageType::SendToJS => MessageInfo {
name: "send_to_js".to_string(),
target: cef_process_id_t::PID_RENDERER.into(),
},
MessageType::SendToNative => MessageInfo {
name: "send_to_native".to_string(),
target: cef_process_id_t::PID_BROWSER.into(),
},
}
}
}
impl TryFrom<String> for MessageType {
type Error = ();
fn try_from(value: String) -> Result<Self, Self::Error> {
match value.as_str() {
"initialized" => Ok(MessageType::Initialized),
"send_to_js" => Ok(MessageType::SendToJS),
"send_to_native" => Ok(MessageType::SendToNative),
_ => Err(()),
}
}
}
pub(crate) struct MessageInfo {
name: String,
target: ProcessId,
}
pub(crate) trait SendMessage {
fn send_message(&self, message_type: MessageType, message: &[u8]);
}
impl SendMessage for Option<V8Context> {
fn send_message(&self, message_type: MessageType, message: &[u8]) {
let Some(context) = self else {
tracing::error!("Current V8 context is not available, cannot send message");
return;
};
context.send_message(message_type, message);
}
}
impl SendMessage for V8Context {
fn send_message(&self, message_type: MessageType, message: &[u8]) {
let Some(frame) = self.frame() else {
tracing::error!("Current V8 context does not have a frame, cannot send message");
return;
};
frame.send_message(message_type, message);
}
}
impl SendMessage for Frame {
fn send_message(&self, message_type: MessageType, message: &[u8]) {
let MessageInfo { name, target } = message_type.into();
let Some(mut process_message) = cef::process_message_create(Some(&CefString::from(name.as_str()))) else {
tracing::error!("Failed to create process message: {}", name);
return;
};
let Some(arg_list) = process_message.argument_list() else { return };
let mut value = ::cef::binary_value_create(Some(message));
arg_list.set_binary(0, value.as_mut());
self.send_process_message(target, Some(&mut process_message));
}
}
pub(crate) struct UnpackedMessage<'a> {
pub(crate) message_type: MessageType,
pub(crate) data: &'a [u8],
}
trait Sealed {}
impl Sealed for cef::ProcessMessage {}
#[allow(private_bounds)]
pub(crate) trait UnpackMessage: Sealed {
/// # Safety
///
/// The caller must ensure that the message is valid.
/// Message should come from cef.
unsafe fn unpack(&self) -> Option<UnpackedMessage<'_>>;
}
impl UnpackMessage for cef::ProcessMessage {
unsafe fn unpack(&self) -> Option<UnpackedMessage<'_>> {
let pointer: *mut cef::sys::_cef_string_utf16_t = self.name().into();
let message = unsafe { super::utility::pointer_to_string(pointer) };
let Ok(message_type) = message.try_into() else {
tracing::error!("Failed to get message type from process message");
return None;
};
let arglist = self.argument_list()?;
let binary = arglist.binary(0)?;
let size = binary.size();
let ptr = binary.raw_data();
let buffer = unsafe { std::slice::from_raw_parts(ptr as *const u8, size) };
Some(UnpackedMessage { message_type, data: buffer })
}
}