mirror of
https://github.com/tauri-apps/tauri.git
synced 2026-04-03 10:11:15 +02:00
wip custom protocol
This commit is contained in:
committed by
Bill Avery
parent
8018cd2ecf
commit
afea11430b
@@ -8,17 +8,31 @@ use std::{
|
||||
},
|
||||
};
|
||||
use tauri_runtime::{
|
||||
webview::UriSchemeProtocol,
|
||||
window::{PendingWindow, WindowId},
|
||||
RunEvent, UserEvent,
|
||||
};
|
||||
|
||||
use crate::{AppWindow, CefRuntime, Message};
|
||||
|
||||
mod request_handler;
|
||||
mod utils;
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! cef_object {
|
||||
($struct: ident<T: UserEvent>, $inner: ty, $cef_obj: ident, $wrap_trait: ty) => {
|
||||
($struct: ident<T: UserEvent>, $context: ty, $cef_type: ty, $cef_obj: ident, $wrap_trait: ty) => {
|
||||
pub struct $struct<T: UserEvent> {
|
||||
object: *mut RcImpl<cef_dll_sys::$cef_obj, Self>,
|
||||
inner: $inner,
|
||||
context: $context,
|
||||
}
|
||||
|
||||
impl<T: UserEvent> $struct<T> {
|
||||
pub fn new(context: $context) -> $cef_type {
|
||||
<$cef_type>::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
context,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: UserEvent> Rc for $struct<T> {
|
||||
@@ -46,15 +60,24 @@ macro_rules! cef_object {
|
||||
|
||||
Self {
|
||||
object,
|
||||
inner: self.inner.clone(),
|
||||
context: self.context.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
($struct: ident, $inner: ty, $cef_obj: ident, $wrap_trait: ty) => {
|
||||
($struct: ident, $context: ty, $cef_type: ty, $cef_obj: ident, $wrap_trait: ty) => {
|
||||
pub struct $struct {
|
||||
object: *mut RcImpl<cef_dll_sys::$cef_obj, Self>,
|
||||
inner: $inner,
|
||||
context: $context,
|
||||
}
|
||||
|
||||
impl $struct {
|
||||
pub fn new(context: $context) -> $cef_type {
|
||||
<$cef_type>::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
context,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Rc for $struct {
|
||||
@@ -82,7 +105,7 @@ macro_rules! cef_object {
|
||||
|
||||
Self {
|
||||
object,
|
||||
inner: self.inner.clone(),
|
||||
context: self.context.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -117,16 +140,7 @@ impl<T: UserEvent> Context<T> {
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(TauriApp<T: UserEvent>, Context<T>, _cef_app_t, WrapApp);
|
||||
|
||||
impl<T: UserEvent> TauriApp<T> {
|
||||
pub fn new(context: Context<T>) -> App {
|
||||
App::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: context,
|
||||
})
|
||||
}
|
||||
}
|
||||
cef_object!(TauriApp<T: UserEvent>, Context<T>, App, _cef_app_t, WrapApp);
|
||||
|
||||
impl<T: UserEvent> ImplApp for TauriApp<T> {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_app_t {
|
||||
@@ -134,20 +148,11 @@ impl<T: UserEvent> ImplApp for TauriApp<T> {
|
||||
}
|
||||
|
||||
fn get_browser_process_handler(&self) -> Option<BrowserProcessHandler> {
|
||||
Some(AppBrowserProcessHandler::new(self.inner.clone()))
|
||||
Some(AppBrowserProcessHandler::new(self.context.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(AppBrowserProcessHandler<T: UserEvent>, Context<T>, cef_browser_process_handler_t, WrapBrowserProcessHandler);
|
||||
|
||||
impl<T: UserEvent> AppBrowserProcessHandler<T> {
|
||||
pub fn new(context: Context<T>) -> BrowserProcessHandler {
|
||||
BrowserProcessHandler::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: context,
|
||||
})
|
||||
}
|
||||
}
|
||||
cef_object!(AppBrowserProcessHandler<T: UserEvent>, Context<T>, BrowserProcessHandler, cef_browser_process_handler_t, WrapBrowserProcessHandler);
|
||||
|
||||
impl<T: UserEvent> ImplBrowserProcessHandler for AppBrowserProcessHandler<T> {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_browser_process_handler_t {
|
||||
@@ -157,117 +162,11 @@ impl<T: UserEvent> ImplBrowserProcessHandler for AppBrowserProcessHandler<T> {
|
||||
// The real lifespan of cef starts from `on_context_initialized`, so all the cef objects should be manipulated after that.
|
||||
fn on_context_initialized(&self) {
|
||||
println!("cef context initialized");
|
||||
(self.inner.callback.borrow_mut())(RunEvent::Ready);
|
||||
}
|
||||
|
||||
fn get_default_request_context_handler(&self) -> Option<RequestContextHandler> {
|
||||
Some(WebRequestContextHandler::new())
|
||||
}
|
||||
|
||||
fn get_default_client(&self) -> Option<Client> {
|
||||
None
|
||||
//Some(BrowserClient::new())
|
||||
(self.context.callback.borrow_mut())(RunEvent::Ready);
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
WebRequestContextHandler,
|
||||
(),
|
||||
_cef_request_context_handler_t,
|
||||
WrapRequestContextHandler
|
||||
);
|
||||
|
||||
impl WebRequestContextHandler {
|
||||
fn new() -> RequestContextHandler {
|
||||
RequestContextHandler::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplRequestContextHandler for WebRequestContextHandler {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_request_context_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
|
||||
fn get_resource_request_handler(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
is_navigation: ::std::os::raw::c_int,
|
||||
is_download: ::std::os::raw::c_int,
|
||||
request_initiator: Option<&CefStringUtf16>,
|
||||
disable_default_handling: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> Option<ResourceRequestHandler> {
|
||||
Some(WebResourceRequestHandler::new())
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
WebResourceRequestHandler,
|
||||
(),
|
||||
_cef_resource_request_handler_t,
|
||||
WrapResourceRequestHandler
|
||||
);
|
||||
|
||||
impl WebResourceRequestHandler {
|
||||
fn new() -> ResourceRequestHandler {
|
||||
ResourceRequestHandler::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplResourceRequestHandler for WebResourceRequestHandler {
|
||||
fn get_resource_handler(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
) -> Option<ResourceHandler> {
|
||||
println!(
|
||||
"get_resource_handler {:?}",
|
||||
request
|
||||
.as_ref()
|
||||
.map(|r| r.get_url().map(|s| CefStringUtf8::from(&s).to_string()))
|
||||
);
|
||||
None
|
||||
}
|
||||
|
||||
fn on_before_resource_load(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
callback: Option<&mut impl ImplCallback>,
|
||||
) -> ReturnValue {
|
||||
println!(
|
||||
"on_before_resource_load {:?}",
|
||||
request
|
||||
.as_ref()
|
||||
.map(|r| r.get_url().map(|s| CefStringUtf8::from(&s).to_string()))
|
||||
);
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_resource_request_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(BrowserClient, (), _cef_client_t, WrapClient);
|
||||
|
||||
impl BrowserClient {
|
||||
pub fn new() -> Client {
|
||||
Client::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
cef_object!(BrowserClient, (), Client, _cef_client_t, WrapClient);
|
||||
|
||||
impl ImplClient for BrowserClient {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_client_t {
|
||||
@@ -275,42 +174,7 @@ impl ImplClient for BrowserClient {
|
||||
}
|
||||
|
||||
fn get_request_handler(&self) -> Option<RequestHandler> {
|
||||
Some(WebRequestHandler::new())
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
WebRequestHandler,
|
||||
(),
|
||||
_cef_request_handler_t,
|
||||
WrapRequestHandler
|
||||
);
|
||||
|
||||
impl WebRequestHandler {
|
||||
fn new() -> RequestHandler {
|
||||
RequestHandler::new(Self {
|
||||
object: std::ptr::null_mut(),
|
||||
inner: (),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ImplRequestHandler for WebRequestHandler {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_request_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
|
||||
fn get_resource_request_handler(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
is_navigation: ::std::os::raw::c_int,
|
||||
is_download: ::std::os::raw::c_int,
|
||||
request_initiator: Option<&CefStringUtf16>,
|
||||
disable_default_handling: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> Option<ResourceRequestHandler> {
|
||||
Some(WebResourceRequestHandler::new())
|
||||
Some(request_handler::WebRequestHandler::new(()))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -487,19 +351,37 @@ fn create_window<T: UserEvent>(
|
||||
) {
|
||||
let label = pending.label.clone();
|
||||
|
||||
let mut client = BrowserClient::new();
|
||||
let url = pending
|
||||
.webview
|
||||
.as_ref()
|
||||
.map(|w| w.url.as_str())
|
||||
.map(|url| CefString::from(&CefStringUtf8::from(url)));
|
||||
let webview = pending.webview.unwrap();
|
||||
|
||||
let mut client = BrowserClient::new(());
|
||||
let url = CefString::from(&CefStringUtf8::from(webview.url.as_str()));
|
||||
|
||||
let mut request_context = request_context_create_context(
|
||||
Some(&RequestContextSettings::default()),
|
||||
Option::<&mut RequestContextHandler>::None,
|
||||
);
|
||||
if let Some(request_context) = &request_context {
|
||||
for (scheme, handler) in webview.uri_scheme_protocols {
|
||||
request_context.register_scheme_handler_factory(
|
||||
Some(&scheme.as_str().into()),
|
||||
None,
|
||||
Some(&mut request_handler::UriSchemeHandlerFactory::new(
|
||||
request_handler::UriSchemeContext {
|
||||
handler: Arc::new(handler) as Arc<UriSchemeProtocol>,
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
} else {
|
||||
eprintln!("failed to create context");
|
||||
}
|
||||
|
||||
let browser_view = browser_view_create(
|
||||
Some(&mut client),
|
||||
url.as_ref(),
|
||||
Some(&url),
|
||||
Some(&Default::default()),
|
||||
Option::<&mut DictionaryValue>::None,
|
||||
Option::<&mut RequestContext>::None,
|
||||
request_context.as_mut(),
|
||||
Option::<&mut BrowserViewDelegate>::None,
|
||||
)
|
||||
.expect("Failed to create browser view");
|
||||
|
||||
202
crates/tauri-runtime-cef/src/cef_impl/request_handler.rs
Normal file
202
crates/tauri-runtime-cef/src/cef_impl/request_handler.rs
Normal file
@@ -0,0 +1,202 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use cef::{rc::*, *};
|
||||
use tauri_runtime::webview::UriSchemeProtocol;
|
||||
use url::Url;
|
||||
|
||||
use crate::{cef_impl::utils::utf16_string_to_utf8, cef_object};
|
||||
|
||||
cef_object!(
|
||||
WebResourceRequestHandler,
|
||||
(),
|
||||
ResourceRequestHandler,
|
||||
_cef_resource_request_handler_t,
|
||||
WrapResourceRequestHandler
|
||||
);
|
||||
|
||||
impl ImplResourceRequestHandler for WebResourceRequestHandler {
|
||||
fn get_resource_handler(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
) -> Option<ResourceHandler> {
|
||||
None
|
||||
}
|
||||
|
||||
fn on_resource_response(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
response: Option<&mut impl ImplResponse>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn on_before_resource_load(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
callback: Option<&mut impl ImplCallback>,
|
||||
) -> ReturnValue {
|
||||
cef_dll_sys::cef_return_value_t::RV_CONTINUE.into()
|
||||
}
|
||||
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_resource_request_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
WebRequestHandler,
|
||||
(),
|
||||
RequestHandler,
|
||||
_cef_request_handler_t,
|
||||
WrapRequestHandler
|
||||
);
|
||||
|
||||
impl ImplRequestHandler for WebRequestHandler {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_request_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
|
||||
fn get_resource_request_handler(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
is_navigation: ::std::os::raw::c_int,
|
||||
is_download: ::std::os::raw::c_int,
|
||||
request_initiator: Option<&CefStringUtf16>,
|
||||
disable_default_handling: Option<&mut ::std::os::raw::c_int>,
|
||||
) -> Option<ResourceRequestHandler> {
|
||||
Some(WebResourceRequestHandler::new(self.context.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
WebResourceHandler,
|
||||
UriSchemeContext,
|
||||
ResourceHandler,
|
||||
_cef_resource_handler_t,
|
||||
WrapResourceHandler
|
||||
);
|
||||
|
||||
impl ImplResourceHandler for WebResourceHandler {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_resource_handler_t {
|
||||
self.object.cast()
|
||||
}
|
||||
|
||||
fn process_request(
|
||||
&self,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
callback: Option<&mut impl ImplCallback>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
let Some(request) = request else { return 0 };
|
||||
let Some(callback) = callback else { return 0 };
|
||||
|
||||
let url = request
|
||||
.get_url()
|
||||
.map(utf16_string_to_utf8)
|
||||
.map(|url| url.to_string())
|
||||
.and_then(|url| Url::parse(&url).ok());
|
||||
|
||||
println!("{:?}", url.as_ref().map(ToString::to_string));
|
||||
|
||||
//callback.cont();
|
||||
//return 1;
|
||||
|
||||
if let Some(url) = url {
|
||||
// keep the callback around
|
||||
unsafe {
|
||||
callback.add_ref();
|
||||
}
|
||||
|
||||
let callback = ThreadSafe(callback.get_raw());
|
||||
std::thread::spawn(move || {
|
||||
std::thread::sleep_ms(5);
|
||||
let cb = callback.into_owned();
|
||||
unsafe {
|
||||
(*cb).cont.inspect(|f| {
|
||||
f(cb);
|
||||
});
|
||||
// release after use
|
||||
(*cb).release();
|
||||
}
|
||||
});
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn read_response(
|
||||
&self,
|
||||
data_out: *mut u8,
|
||||
bytes_to_read: ::std::os::raw::c_int,
|
||||
bytes_read: Option<&mut ::std::os::raw::c_int>,
|
||||
callback: Option<&mut impl ImplCallback>,
|
||||
) -> ::std::os::raw::c_int {
|
||||
callback.inspect(|cb| cb.cont());
|
||||
bytes_read.map(|read| {
|
||||
*read = 5;
|
||||
});
|
||||
1
|
||||
}
|
||||
|
||||
fn get_response_headers(
|
||||
&self,
|
||||
response: Option<&mut impl ImplResponse>,
|
||||
response_length: Option<&mut i64>,
|
||||
redirect_url: Option<&mut CefStringUtf16>,
|
||||
) {
|
||||
let Some(response) = response else { return };
|
||||
response.set_status(200);
|
||||
response.set_header_by_name(Some(&"content-type".into()), Some(&"text/plain".into()), 1);
|
||||
response_length.map(|length| {
|
||||
*length = -1;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
cef_object!(
|
||||
UriSchemeHandlerFactory,
|
||||
UriSchemeContext,
|
||||
SchemeHandlerFactory,
|
||||
cef_scheme_handler_factory_t,
|
||||
WrapSchemeHandlerFactory
|
||||
);
|
||||
|
||||
impl ImplSchemeHandlerFactory for UriSchemeHandlerFactory {
|
||||
fn get_raw(&self) -> *mut cef_dll_sys::_cef_scheme_handler_factory_t {
|
||||
self.object.cast()
|
||||
}
|
||||
|
||||
fn create(
|
||||
&self,
|
||||
browser: Option<&mut impl ImplBrowser>,
|
||||
frame: Option<&mut impl ImplFrame>,
|
||||
scheme_name: Option<&CefStringUtf16>,
|
||||
request: Option<&mut impl ImplRequest>,
|
||||
) -> Option<ResourceHandler> {
|
||||
Some(WebResourceHandler::new(self.context.clone()))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct UriSchemeContext {
|
||||
pub handler: Arc<UriSchemeProtocol>,
|
||||
}
|
||||
|
||||
struct ThreadSafe<T>(T);
|
||||
|
||||
impl<T> ThreadSafe<T> {
|
||||
fn into_owned(self) -> T {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T> Send for ThreadSafe<T> {}
|
||||
unsafe impl<T> Sync for ThreadSafe<T> {}
|
||||
16
crates/tauri-runtime-cef/src/cef_impl/utils.rs
Normal file
16
crates/tauri-runtime-cef/src/cef_impl/utils.rs
Normal file
@@ -0,0 +1,16 @@
|
||||
use cef::{CefStringUtf16, CefStringUtf8};
|
||||
|
||||
pub fn utf16_string_to_utf8(s: CefStringUtf16) -> CefStringUtf8 {
|
||||
let value: *const cef_dll_sys::_cef_string_utf16_t = (&s).into();
|
||||
|
||||
unsafe {
|
||||
let mut cef_string = std::mem::zeroed();
|
||||
|
||||
if let Some((str_, length)) = value.as_ref().map(|value| (value.str_, value.length)) {
|
||||
cef_dll_sys::cef_string_utf16_to_utf8(str_, length, &mut cef_string);
|
||||
}
|
||||
|
||||
cef_string
|
||||
}
|
||||
.into()
|
||||
}
|
||||
@@ -23,23 +23,23 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
type UriSchemeProtocol = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
|
||||
pub type UriSchemeProtocol = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static;
|
||||
|
||||
type WebResourceRequestHandler =
|
||||
pub type WebResourceRequestHandler =
|
||||
dyn Fn(http::Request<Vec<u8>>, &mut http::Response<Cow<'static, [u8]>>) + Send + Sync;
|
||||
|
||||
type NavigationHandler = dyn Fn(&Url) -> bool + Send;
|
||||
pub type NavigationHandler = dyn Fn(&Url) -> bool + Send;
|
||||
|
||||
type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync;
|
||||
pub type NewWindowHandler = dyn Fn(Url, NewWindowFeatures) -> NewWindowResponse + Send + Sync;
|
||||
|
||||
type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
|
||||
pub type OnPageLoadHandler = dyn Fn(Url, PageLoadEvent) + Send;
|
||||
|
||||
type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static;
|
||||
pub type DocumentTitleChangedHandler = dyn Fn(String) + Send + 'static;
|
||||
|
||||
type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync;
|
||||
pub type DownloadHandler = dyn Fn(DownloadEvent) -> bool + Send + Sync;
|
||||
|
||||
#[cfg(target_os = "ios")]
|
||||
type InputAccessoryViewBuilderFn = dyn Fn(&objc2_ui_kit::UIView) -> Option<objc2::rc::Retained<objc2_ui_kit::UIView>>
|
||||
|
||||
Reference in New Issue
Block a user