mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-07-14 19:10:28 +03:00
refactor(core): add setup() to the Assets trait (#9147)
* feat(core): allow swapping the assets implemenetation * refactor(core): add setup() to the Assets trait * code review
This commit is contained in:
parent
85de230f31
commit
490a6b424e
5
.changes/assets-setup.md
Normal file
5
.changes/assets-setup.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:feat
|
||||
---
|
||||
|
||||
The `Assets` trait now include a `setup` method that lets you run initialization code for your custom asset provider.
|
5
.changes/context-assets-runtime-generic.md
Normal file
5
.changes/context-assets-runtime-generic.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:breaking
|
||||
---
|
||||
|
||||
The `Context` struct and the `Assets` trait now takes a `R: Runtime` generic.
|
5
.changes/context-remove-assets-mut.md
Normal file
5
.changes/context-remove-assets-mut.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:breaking
|
||||
---
|
||||
|
||||
Removed `Context::assets_mut` and added `Context::set_assets`.
|
5
.changes/utils-remove-asset-trait.md
Normal file
5
.changes/utils-remove-asset-trait.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri-utils": patch:breaking
|
||||
---
|
||||
|
||||
Removed the `assets::Assets` trait which is now part of the `tauri` crate.
|
@ -345,10 +345,10 @@ pub fn context_codegen(data: ContextData) -> Result<TokenStream, EmbeddedAssetsE
|
||||
let info_plist = quote!(());
|
||||
|
||||
let pattern = match &options.pattern {
|
||||
PatternKind::Brownfield => quote!(#root::Pattern::Brownfield(std::marker::PhantomData)),
|
||||
PatternKind::Brownfield => quote!(#root::Pattern::Brownfield),
|
||||
#[cfg(not(feature = "isolation"))]
|
||||
PatternKind::Isolation { dir: _ } => {
|
||||
quote!(#root::Pattern::Brownfield(std::marker::PhantomData))
|
||||
quote!(#root::Pattern::Brownfield)
|
||||
}
|
||||
#[cfg(feature = "isolation")]
|
||||
PatternKind::Isolation { dir } => {
|
||||
|
@ -30,7 +30,7 @@ runtime = [ ]
|
||||
[dependencies]
|
||||
anyhow = { version = "1", optional = true }
|
||||
serde = { version = "1", optional = true }
|
||||
tauri-utils = { version = "2.0.0-beta.8", default-features = false, path = "../tauri-utils" }
|
||||
tauri-utils = { version = "2.0.0-beta.8", default-features = false, features = [ "build" ], path = "../tauri-utils" }
|
||||
serde_json = { version = "1", optional = true }
|
||||
glob = { version = "0.3", optional = true }
|
||||
toml = { version = "0.8", optional = true }
|
||||
|
@ -104,18 +104,6 @@ impl CspHash<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Represents a container of file assets that are retrievable during runtime.
|
||||
pub trait Assets: Send + Sync + 'static {
|
||||
/// Get the content of the passed [`AssetKey`].
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>>;
|
||||
|
||||
/// Iterator for the assets.
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&&str, &&[u8])> + '_>;
|
||||
|
||||
/// Gets the hashes for the CSP tag of the HTML on the given path.
|
||||
fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_>;
|
||||
}
|
||||
|
||||
/// [`Assets`] implementation that only contains compile-time compressed and embedded assets.
|
||||
#[derive(Debug)]
|
||||
pub struct EmbeddedAssets {
|
||||
@ -139,11 +127,10 @@ impl EmbeddedAssets {
|
||||
html_hashes,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Assets for EmbeddedAssets {
|
||||
/// Get an asset by key.
|
||||
#[cfg(feature = "compression")]
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
pub fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
self
|
||||
.assets
|
||||
.get(key.as_ref())
|
||||
@ -157,8 +144,9 @@ impl Assets for EmbeddedAssets {
|
||||
.map(Cow::Owned)
|
||||
}
|
||||
|
||||
/// Get an asset by key.
|
||||
#[cfg(not(feature = "compression"))]
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
pub fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
self
|
||||
.assets
|
||||
.get(key.as_ref())
|
||||
@ -166,11 +154,13 @@ impl Assets for EmbeddedAssets {
|
||||
.map(|a| Cow::Owned(a.to_vec()))
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&&str, &&[u8])> + '_> {
|
||||
Box::new(self.assets.into_iter())
|
||||
/// Iterate on the assets.
|
||||
pub fn iter(&self) -> Box<dyn Iterator<Item = (&str, &[u8])> + '_> {
|
||||
Box::new(self.assets.into_iter().map(|(k, b)| (*k, *b)))
|
||||
}
|
||||
|
||||
fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_> {
|
||||
/// CSP hashes for the given asset.
|
||||
pub fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_> {
|
||||
Box::new(
|
||||
self
|
||||
.global_hashes
|
||||
|
@ -266,7 +266,7 @@ impl<R: Runtime> AssetResolver<R> {
|
||||
}
|
||||
|
||||
/// Iterate on all assets.
|
||||
pub fn iter(&self) -> Box<dyn Iterator<Item = (&&str, &&[u8])> + '_> {
|
||||
pub fn iter(&self) -> Box<dyn Iterator<Item = (&str, &[u8])> + '_> {
|
||||
self.manager.assets.iter()
|
||||
}
|
||||
}
|
||||
@ -1581,7 +1581,7 @@ tauri::Builder::default()
|
||||
feature = "tracing",
|
||||
tracing::instrument(name = "app::build", skip_all)
|
||||
)]
|
||||
pub fn build(mut self, context: Context) -> crate::Result<App<R>> {
|
||||
pub fn build(mut self, context: Context<R>) -> crate::Result<App<R>> {
|
||||
#[cfg(target_os = "macos")]
|
||||
if self.menu.is_none() && self.enable_macos_default_menu {
|
||||
self.menu = Some(Box::new(|app_handle| {
|
||||
@ -1749,7 +1749,7 @@ tauri::Builder::default()
|
||||
}
|
||||
|
||||
/// Runs the configured Tauri application.
|
||||
pub fn run(self, context: Context) -> crate::Result<()> {
|
||||
pub fn run(self, context: Context<R>) -> crate::Result<()> {
|
||||
self.build(context)?.run(|_, _| {});
|
||||
Ok(())
|
||||
}
|
||||
@ -1824,6 +1824,8 @@ fn setup<R: Runtime>(app: &mut App<R>) -> crate::Result<()> {
|
||||
.build_internal(&window_labels, &webview_labels)?;
|
||||
}
|
||||
|
||||
app.manager.assets.setup(app);
|
||||
|
||||
if let Some(setup) = app.setup.take() {
|
||||
(setup)(app).map_err(|e| crate::Error::Setup(e.into()))?;
|
||||
}
|
||||
|
@ -192,10 +192,12 @@ pub type SyncTask = Box<dyn FnOnce() + Send>;
|
||||
|
||||
use serde::Serialize;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::HashMap,
|
||||
fmt::{self, Debug},
|
||||
sync::MutexGuard,
|
||||
};
|
||||
use utils::assets::{AssetKey, CspHash, EmbeddedAssets};
|
||||
|
||||
#[cfg(feature = "wry")]
|
||||
#[cfg_attr(docsrs, doc(cfg(feature = "wry")))]
|
||||
@ -224,7 +226,6 @@ pub use {
|
||||
},
|
||||
self::state::{State, StateManager},
|
||||
self::utils::{
|
||||
assets::Assets,
|
||||
config::{Config, WebviewUrl},
|
||||
Env, PackageInfo, Theme,
|
||||
},
|
||||
@ -338,14 +339,47 @@ pub fn dev() -> bool {
|
||||
!cfg!(feature = "custom-protocol")
|
||||
}
|
||||
|
||||
/// Represents a container of file assets that are retrievable during runtime.
|
||||
pub trait Assets<R: Runtime>: Send + Sync + 'static {
|
||||
/// Initialize the asset provider.
|
||||
fn setup(&self, app: &App<R>) {
|
||||
let _ = app;
|
||||
}
|
||||
|
||||
/// Get the content of the passed [`AssetKey`].
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>>;
|
||||
|
||||
/// Iterator for the assets.
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&str, &[u8])> + '_>;
|
||||
|
||||
/// Gets the hashes for the CSP tag of the HTML on the given path.
|
||||
fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_>;
|
||||
}
|
||||
|
||||
impl<R: Runtime> Assets<R> for EmbeddedAssets {
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
EmbeddedAssets::get(self, key)
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&str, &[u8])> + '_> {
|
||||
EmbeddedAssets::iter(self)
|
||||
}
|
||||
|
||||
fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_> {
|
||||
EmbeddedAssets::csp_hashes(self, html_path)
|
||||
}
|
||||
}
|
||||
|
||||
/// User supplied data required inside of a Tauri application.
|
||||
///
|
||||
/// # Stability
|
||||
/// This is the output of the [`generate_context`] macro, and is not considered part of the stable API.
|
||||
/// Unless you know what you are doing and are prepared for this type to have breaking changes, do not create it yourself.
|
||||
pub struct Context {
|
||||
#[tauri_macros::default_runtime(Wry, wry)]
|
||||
pub struct Context<R: Runtime> {
|
||||
pub(crate) config: Config,
|
||||
pub(crate) assets: Box<dyn Assets>,
|
||||
/// Asset provider.
|
||||
pub assets: Box<dyn Assets<R>>,
|
||||
pub(crate) default_window_icon: Option<image::Image<'static>>,
|
||||
pub(crate) app_icon: Option<Vec<u8>>,
|
||||
#[cfg(all(desktop, feature = "tray-icon"))]
|
||||
@ -356,7 +390,7 @@ pub struct Context {
|
||||
pub(crate) runtime_authority: RuntimeAuthority,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Context {
|
||||
impl<R: Runtime> fmt::Debug for Context<R> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let mut d = f.debug_struct("Context");
|
||||
d.field("config", &self.config)
|
||||
@ -372,7 +406,7 @@ impl fmt::Debug for Context {
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
impl<R: Runtime> Context<R> {
|
||||
/// The config the application was prepared with.
|
||||
#[inline(always)]
|
||||
pub fn config(&self) -> &Config {
|
||||
@ -387,14 +421,14 @@ impl Context {
|
||||
|
||||
/// The assets to be served directly by Tauri.
|
||||
#[inline(always)]
|
||||
pub fn assets(&self) -> &dyn Assets {
|
||||
pub fn assets(&self) -> &dyn Assets<R> {
|
||||
self.assets.as_ref()
|
||||
}
|
||||
|
||||
/// A mutable reference to the assets to be served directly by Tauri.
|
||||
/// Replace the [`Assets`] implementation and returns the previous value so you can use it as a fallback if desired.
|
||||
#[inline(always)]
|
||||
pub fn assets_mut(&mut self) -> &mut Box<dyn Assets> {
|
||||
&mut self.assets
|
||||
pub fn set_assets(&mut self, assets: Box<dyn Assets<R>>) -> Box<dyn Assets<R>> {
|
||||
std::mem::replace(&mut self.assets, assets)
|
||||
}
|
||||
|
||||
/// The default window icon Tauri should use when creating windows.
|
||||
@ -459,7 +493,7 @@ impl Context {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
config: Config,
|
||||
assets: Box<dyn Assets>,
|
||||
assets: Box<dyn Assets<R>>,
|
||||
default_window_icon: Option<image::Image<'static>>,
|
||||
app_icon: Option<Vec<u8>>,
|
||||
package_info: PackageInfo,
|
||||
|
@ -24,8 +24,8 @@ use crate::{
|
||||
event::{assert_event_name_is_valid, Event, EventId, EventTarget, Listeners},
|
||||
ipc::{Invoke, InvokeHandler, InvokeResponder, RuntimeAuthority},
|
||||
plugin::PluginStore,
|
||||
utils::{assets::Assets, config::Config, PackageInfo},
|
||||
Context, Pattern, Runtime, StateManager, Window,
|
||||
utils::{config::Config, PackageInfo},
|
||||
Assets, Context, Pattern, Runtime, StateManager, Window,
|
||||
};
|
||||
use crate::{event::EmitArgs, resources::ResourceTable, Webview};
|
||||
|
||||
@ -48,7 +48,7 @@ struct CspHashStrings {
|
||||
#[allow(clippy::borrowed_box)]
|
||||
pub(crate) fn set_csp<R: Runtime>(
|
||||
asset: &mut String,
|
||||
assets: &impl std::borrow::Borrow<dyn Assets>,
|
||||
assets: &impl std::borrow::Borrow<dyn Assets<R>>,
|
||||
asset_path: &AssetKey,
|
||||
manager: &AppManager<R>,
|
||||
csp: Csp,
|
||||
@ -179,7 +179,7 @@ pub struct AppManager<R: Runtime> {
|
||||
pub listeners: Listeners,
|
||||
pub state: Arc<StateManager>,
|
||||
pub config: Config,
|
||||
pub assets: Box<dyn Assets>,
|
||||
pub assets: Box<dyn Assets<R>>,
|
||||
|
||||
pub app_icon: Option<Vec<u8>>,
|
||||
|
||||
@ -216,7 +216,7 @@ impl<R: Runtime> fmt::Debug for AppManager<R> {
|
||||
impl<R: Runtime> AppManager<R> {
|
||||
#[allow(clippy::too_many_arguments, clippy::type_complexity)]
|
||||
pub(crate) fn with_handlers(
|
||||
#[allow(unused_mut)] mut context: Context,
|
||||
#[allow(unused_mut)] mut context: Context<R>,
|
||||
plugins: PluginStore<R>,
|
||||
invoke_handler: Box<InvokeHandler<R>>,
|
||||
on_page_load: Option<Arc<OnPageLoad<R>>>,
|
||||
|
@ -2,28 +2,25 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use std::marker::PhantomData;
|
||||
#[cfg(feature = "isolation")]
|
||||
use std::sync::Arc;
|
||||
|
||||
use serde::Serialize;
|
||||
use serialize_to_javascript::{default_template, Template};
|
||||
|
||||
use tauri_utils::assets::{Assets, EmbeddedAssets};
|
||||
|
||||
/// The domain of the isolation iframe source.
|
||||
pub const ISOLATION_IFRAME_SRC_DOMAIN: &str = "localhost";
|
||||
|
||||
/// An application pattern.
|
||||
#[derive(Debug)]
|
||||
pub enum Pattern<A: Assets = EmbeddedAssets> {
|
||||
pub enum Pattern {
|
||||
/// The brownfield pattern.
|
||||
Brownfield(PhantomData<A>),
|
||||
Brownfield,
|
||||
/// Isolation pattern. Recommended for security purposes.
|
||||
#[cfg(feature = "isolation")]
|
||||
Isolation {
|
||||
/// The HTML served on `isolation://index.html`.
|
||||
assets: Arc<A>,
|
||||
assets: Arc<tauri_utils::assets::EmbeddedAssets>,
|
||||
|
||||
/// The schema used for the isolation frames.
|
||||
schema: String,
|
||||
@ -55,7 +52,7 @@ pub(crate) enum PatternObject {
|
||||
impl From<&Pattern> for PatternObject {
|
||||
fn from(pattern: &Pattern) -> Self {
|
||||
match pattern {
|
||||
Pattern::Brownfield(_) => Self::Brownfield,
|
||||
Pattern::Brownfield => Self::Brownfield,
|
||||
#[cfg(feature = "isolation")]
|
||||
Pattern::Isolation { .. } => Self::Isolation {
|
||||
side: IsolationSide::default(),
|
||||
|
@ -2,12 +2,10 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
use crate::Assets;
|
||||
use http::header::CONTENT_TYPE;
|
||||
use serialize_to_javascript::Template;
|
||||
use tauri_utils::{
|
||||
assets::{Assets, EmbeddedAssets},
|
||||
config::Csp,
|
||||
};
|
||||
use tauri_utils::{assets::EmbeddedAssets, config::Csp};
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
@ -29,7 +27,7 @@ pub fn get<R: Runtime>(
|
||||
format!("{schema}:")
|
||||
};
|
||||
|
||||
let assets = assets as Arc<dyn Assets>;
|
||||
let assets = assets as Arc<dyn Assets<R>>;
|
||||
|
||||
Box::new(move |request, responder| {
|
||||
let response = match request_to_path(&request).as_str() {
|
||||
|
@ -57,27 +57,27 @@ use std::{borrow::Cow, collections::HashMap, fmt::Debug};
|
||||
use crate::{
|
||||
ipc::{InvokeBody, InvokeError, InvokeResponse, RuntimeAuthority},
|
||||
webview::InvokeRequest,
|
||||
App, Builder, Context, Pattern, Webview,
|
||||
App, Assets, Builder, Context, Pattern, Runtime, Webview,
|
||||
};
|
||||
use tauri_utils::{
|
||||
acl::resolved::Resolved,
|
||||
assets::{AssetKey, Assets, CspHash},
|
||||
assets::{AssetKey, CspHash},
|
||||
config::{AppConfig, Config},
|
||||
};
|
||||
|
||||
/// An empty [`Assets`] implementation.
|
||||
pub struct NoopAsset {
|
||||
assets: HashMap<&'static str, &'static [u8]>,
|
||||
assets: HashMap<String, Vec<u8>>,
|
||||
csp_hashes: Vec<CspHash<'static>>,
|
||||
}
|
||||
|
||||
impl Assets for NoopAsset {
|
||||
impl<R: Runtime> Assets<R> for NoopAsset {
|
||||
fn get(&self, key: &AssetKey) -> Option<Cow<'_, [u8]>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&&str, &&[u8])> + '_> {
|
||||
Box::new(self.assets.iter())
|
||||
fn iter(&self) -> Box<dyn Iterator<Item = (&str, &[u8])> + '_> {
|
||||
Box::new(self.assets.iter().map(|(k, b)| (k.as_str(), b.as_slice())))
|
||||
}
|
||||
|
||||
fn csp_hashes(&self, html_path: &AssetKey) -> Box<dyn Iterator<Item = CspHash<'_>> + '_> {
|
||||
@ -94,7 +94,7 @@ pub fn noop_assets() -> NoopAsset {
|
||||
}
|
||||
|
||||
/// Creates a new [`crate::Context`] for testing.
|
||||
pub fn mock_context<A: Assets>(assets: A) -> crate::Context {
|
||||
pub fn mock_context<R: Runtime, A: Assets<R>>(assets: A) -> crate::Context<R> {
|
||||
Context {
|
||||
config: Config {
|
||||
schema: None,
|
||||
@ -125,7 +125,7 @@ pub fn mock_context<A: Assets>(assets: A) -> crate::Context {
|
||||
crate_name: "test",
|
||||
},
|
||||
_info_plist: (),
|
||||
pattern: Pattern::Brownfield(std::marker::PhantomData),
|
||||
pattern: Pattern::Brownfield,
|
||||
runtime_authority: RuntimeAuthority::new(Default::default(), Resolved::default()),
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user