mirror of https://github.com/tauri-apps/tauri
Refactor(runner.rs) Clean up code to make it more composable and… (#259)
* update .gitignore * remove cargo.lock * add clone to config * create functions * finish merge and fix conflict. * cleanup * continue refactor cleanup * fix logic for embedded server * bringing back the polymorphisms! * cleaning it all up... * add imports * add basic documentation. * add a TauriResult type * cleanup spawn_updater func * cleanup imports and errors. * fix error and proliferate it * cleanup ?s
This commit is contained in:
parent
7ae7c9dfc2
commit
aa149370a4
|
@ -10,7 +10,7 @@ pub struct App {
|
|||
|
||||
impl App {
|
||||
pub fn run(mut self) {
|
||||
runner::run(&mut self);
|
||||
runner::run(&mut self).expect("Failed to build webview");
|
||||
}
|
||||
|
||||
pub(crate) fn run_invoke_handler(&mut self, webview: &mut WebView<'_, ()>, arg: &str) {
|
||||
|
|
|
@ -1,141 +1,202 @@
|
|||
pub(crate) fn run(application: &mut crate::App) {
|
||||
let debug = cfg!(debug_assertions);
|
||||
let config = crate::config::get();
|
||||
#[allow(unused_imports)]
|
||||
use std::{fs::read_to_string, path::Path, process::Stdio, thread::spawn};
|
||||
|
||||
let content;
|
||||
#[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
|
||||
{
|
||||
content = if config.build.dev_path.starts_with("http") {
|
||||
web_view::Content::Url(config.build.dev_path)
|
||||
} else {
|
||||
let dev_path = std::path::Path::new(&config.build.dev_path).join("index.tauri.html");
|
||||
web_view::Content::Html(
|
||||
std::fs::read_to_string(dev_path).expect("failed to read index.tauri.html"),
|
||||
)
|
||||
};
|
||||
}
|
||||
use web_view::{builder, Content, WebView};
|
||||
|
||||
#[cfg(feature = "embedded-server")]
|
||||
let server_url;
|
||||
use crate::config::{get, Config};
|
||||
#[cfg(feature = "embedded-server")]
|
||||
use crate::tcp::{get_available_port, port_is_available};
|
||||
use crate::App;
|
||||
use crate::TauriResult;
|
||||
|
||||
#[cfg(feature = "embedded-server")]
|
||||
{
|
||||
// define URL
|
||||
let port;
|
||||
let port_valid;
|
||||
if config.tauri.embedded_server.port == "random" {
|
||||
match crate::tcp::get_available_port() {
|
||||
Some(available_port) => {
|
||||
port = available_port.to_string();
|
||||
port_valid = true;
|
||||
}
|
||||
None => {
|
||||
port = "0".to_string();
|
||||
port_valid = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
port = config.tauri.embedded_server.port;
|
||||
port_valid = crate::tcp::port_is_available(
|
||||
port
|
||||
.parse::<u16>()
|
||||
.expect(&format!("Invalid port {}", port)),
|
||||
);
|
||||
}
|
||||
if port_valid {
|
||||
let mut url = format!("{}:{}", config.tauri.embedded_server.host, port);
|
||||
if !url.starts_with("http") {
|
||||
url = format!("http://{}", url);
|
||||
}
|
||||
server_url = url.clone();
|
||||
content = web_view::Content::Url(url.to_string());
|
||||
} else {
|
||||
panic!(format!("Port {} is not valid or not open", port));
|
||||
// JavaScript string literal
|
||||
const JS_STRING: &'static str = r#"
|
||||
if (window.onTauriInit !== void 0) {
|
||||
window.onTauriInit()
|
||||
window.onTauriInit = void 0
|
||||
}
|
||||
Object.defineProperty(window, 'onTauriInit', {
|
||||
set: function(val) {
|
||||
if (typeof(val) === 'function') {
|
||||
val()
|
||||
}
|
||||
}
|
||||
})
|
||||
"#;
|
||||
|
||||
#[cfg(feature = "no-server")]
|
||||
{
|
||||
let index_path = std::path::Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
|
||||
content =
|
||||
web_view::Content::Html(std::fs::read_to_string(index_path).expect("failed to read string"));
|
||||
}
|
||||
// Main entry point function for running the Webview
|
||||
pub(crate) fn run(application: &mut App) -> TauriResult<()> {
|
||||
// get the tauri config struct
|
||||
let config = get()?;
|
||||
|
||||
#[cfg(feature = "updater")]
|
||||
{
|
||||
std::thread::spawn(|| {
|
||||
crate::command::spawn_relative_command(
|
||||
"updater".to_string(),
|
||||
Vec::new(),
|
||||
std::process::Stdio::inherit(),
|
||||
)
|
||||
.expect("Failed to spawn updater thread");
|
||||
});
|
||||
}
|
||||
// setup the content using the config struct depending on the compile target
|
||||
let content = setup_content(config.clone())?;
|
||||
|
||||
let webview = web_view::builder()
|
||||
.title(&config.tauri.window.title)
|
||||
.size(config.tauri.window.width, config.tauri.window.height)
|
||||
.resizable(config.tauri.window.resizable)
|
||||
.debug(debug)
|
||||
.user_data(())
|
||||
.invoke_handler(|webview, arg| {
|
||||
if arg == r#"{"cmd":"__initialized"}"# {
|
||||
application.run_setup(webview);
|
||||
webview.eval("
|
||||
if (window.onTauriInit !== void 0) {
|
||||
window.onTauriInit()
|
||||
window.onTauriInit = void 0
|
||||
}
|
||||
Object.defineProperty(window, 'onTauriInit', {
|
||||
set: function(val) {
|
||||
if (typeof(val) === 'function') {
|
||||
val()
|
||||
}
|
||||
}
|
||||
})
|
||||
").expect("failed to evaluate window.onTauriInit");
|
||||
} else if !crate::endpoints::handle(webview, arg) {
|
||||
application.run_invoke_handler(webview, arg);
|
||||
}
|
||||
// setup the server url for the embedded-server
|
||||
#[cfg(feature = "embedded-server")]
|
||||
let server_url = {
|
||||
if let Content::Url(ref url) = &content {
|
||||
String::from(url)
|
||||
} else {
|
||||
String::from("")
|
||||
}
|
||||
};
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.content(content)
|
||||
.build()
|
||||
.expect("Failed to build webview builder");
|
||||
// build the webview
|
||||
let webview = build_webview(application, config, content)?;
|
||||
|
||||
// on dev-server grab a handler and execute the tauri.js API entry point.
|
||||
#[cfg(feature = "dev-server")]
|
||||
webview
|
||||
.handle()
|
||||
.dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))
|
||||
.expect("Failed to grab webview handle");
|
||||
.dispatch(|_webview| _webview.eval(include_str!(concat!(env!("TAURI_DIR"), "/tauri.js"))))?;
|
||||
|
||||
// spawn the embedded server on our server url
|
||||
#[cfg(feature = "embedded-server")]
|
||||
{
|
||||
std::thread::spawn(move || {
|
||||
let server = tiny_http::Server::http(
|
||||
server_url
|
||||
.clone()
|
||||
.replace("http://", "")
|
||||
.replace("https://", ""),
|
||||
)
|
||||
.expect(&format!(
|
||||
"Could not start embedded server with the specified url: {}",
|
||||
server_url
|
||||
));
|
||||
for request in server.incoming_requests() {
|
||||
let url = match request.url() {
|
||||
"/" => "/index.tauri.html",
|
||||
url => url,
|
||||
}
|
||||
.to_string();
|
||||
request
|
||||
.respond(crate::server::asset_response(&url))
|
||||
.expect("Failed to read asset type");
|
||||
}
|
||||
});
|
||||
}
|
||||
spawn_server(server_url.to_string())?;
|
||||
|
||||
webview.run().expect("Failed to run webview");
|
||||
// spin up the updater process
|
||||
#[cfg(feature = "updater")]
|
||||
spawn_updater()?;
|
||||
|
||||
// run the webview
|
||||
webview.run()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// setup content for dev-server
|
||||
#[cfg(not(any(feature = "embedded-server", feature = "no-server")))]
|
||||
fn setup_content(config: Config) -> TauriResult<Content<String>> {
|
||||
if config.build.dev_path.starts_with("http") {
|
||||
Ok(Content::Url(config.build.dev_path))
|
||||
} else {
|
||||
let dev_path = Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
|
||||
Ok(Content::Html(read_to_string(dev_path)?))
|
||||
}
|
||||
}
|
||||
|
||||
// setup content for embedded server
|
||||
#[cfg(feature = "embedded-server")]
|
||||
fn setup_content(config: Config) -> TauriResult<Content<String>> {
|
||||
let (port, valid) = setup_port(config.clone()).expect("Unable to setup Port");
|
||||
let url = setup_server_url(config.clone(), valid, port).expect("Unable to setup URL");
|
||||
|
||||
Ok(Content::Url(url.to_string()))
|
||||
}
|
||||
|
||||
// setup content for no-server
|
||||
#[cfg(feature = "no-server")]
|
||||
fn setup_content(_: Config) -> TauriResult<Content<String>> {
|
||||
let index_path = Path::new(env!("TAURI_DIST_DIR")).join("index.tauri.html");
|
||||
Ok(Content::Html(read_to_string(index_path)?))
|
||||
}
|
||||
|
||||
// get the port for the embedded server
|
||||
#[cfg(feature = "embedded-server")]
|
||||
fn setup_port(config: Config) -> Option<(String, bool)> {
|
||||
if config.tauri.embedded_server.port == "random" {
|
||||
match get_available_port() {
|
||||
Some(available_port) => Some((available_port.to_string(), true)),
|
||||
None => Some(("0".to_string(), false)),
|
||||
}
|
||||
} else {
|
||||
let port = config.tauri.embedded_server.port;
|
||||
let port_valid = port_is_available(
|
||||
port
|
||||
.parse::<u16>()
|
||||
.expect(&format!("Invalid port {}", port)),
|
||||
);
|
||||
Some((port, port_valid))
|
||||
}
|
||||
}
|
||||
|
||||
// setup the server url for embedded server
|
||||
#[cfg(feature = "embedded-server")]
|
||||
fn setup_server_url(config: Config, valid: bool, port: String) -> Option<String> {
|
||||
if valid {
|
||||
let mut url = format!("{}:{}", config.tauri.embedded_server.host, port);
|
||||
if !url.starts_with("http") {
|
||||
url = format!("http://{}", url);
|
||||
}
|
||||
Some(url)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
// spawn the embedded server
|
||||
#[cfg(feature = "embedded-server")]
|
||||
fn spawn_server(server_url: String) -> TauriResult<()> {
|
||||
spawn(move || {
|
||||
let server = tiny_http::Server::http(
|
||||
server_url
|
||||
.clone()
|
||||
.replace("http://", "")
|
||||
.replace("https://", ""),
|
||||
)
|
||||
.expect("Unable to spawn server");
|
||||
for request in server.incoming_requests() {
|
||||
let url = match request.url() {
|
||||
"/" => "/index.tauri.html",
|
||||
url => url,
|
||||
}
|
||||
.to_string();
|
||||
request
|
||||
.respond(crate::server::asset_response(&url))
|
||||
.expect("unable to setup response");
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// spawn an updater process.
|
||||
#[cfg(feature = "updater")]
|
||||
fn spawn_updater() -> TauriResult<()> {
|
||||
spawn(|| {
|
||||
tauri_api::command::spawn_relative_command(
|
||||
"updater".to_string(),
|
||||
Vec::new(),
|
||||
Stdio::inherit(),
|
||||
)?;
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// build the webview struct
|
||||
fn build_webview(
|
||||
application: &mut App,
|
||||
config: Config,
|
||||
content: Content<String>,
|
||||
) -> TauriResult<WebView<'_, ()>> {
|
||||
let debug = cfg!(debug_assertions);
|
||||
// get properties from config struct
|
||||
let width = config.tauri.window.width;
|
||||
let height = config.tauri.window.height;
|
||||
let resizable = config.tauri.window.resizable;
|
||||
let title = config.tauri.window.title.into_boxed_str();
|
||||
|
||||
Ok(
|
||||
builder()
|
||||
.title(Box::leak(title))
|
||||
.size(width, height)
|
||||
.resizable(resizable)
|
||||
.debug(debug)
|
||||
.user_data(())
|
||||
.invoke_handler(move |webview, arg| {
|
||||
if arg == r#"{"cmd":"__initialized"}"# {
|
||||
application.run_setup(webview);
|
||||
webview.eval(JS_STRING)?;
|
||||
} else if let Ok(b) = crate::endpoints::handle(webview, arg) {
|
||||
if !b {
|
||||
application.run_invoke_handler(webview, arg);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.content(content)
|
||||
.build()?,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
use std::env;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
use crate::TauriResult;
|
||||
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(tag = "window", rename_all = "camelCase")]
|
||||
pub struct WindowConfig {
|
||||
#[serde(default = "default_width")]
|
||||
|
@ -38,7 +40,7 @@ fn default_window() -> WindowConfig {
|
|||
};
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(tag = "embeddedServer", rename_all = "camelCase")]
|
||||
pub struct EmbeddedServerConfig {
|
||||
#[serde(default = "default_host")]
|
||||
|
@ -62,53 +64,54 @@ fn default_embedded_server() -> EmbeddedServerConfig {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(tag = "tauri", rename_all = "camelCase")]
|
||||
pub struct TauriConfig {
|
||||
#[serde(default = "default_window")]
|
||||
pub window: WindowConfig,
|
||||
#[serde(default = "default_embedded_server")]
|
||||
pub embedded_server: EmbeddedServerConfig
|
||||
pub embedded_server: EmbeddedServerConfig,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(tag = "build", rename_all = "camelCase")]
|
||||
pub struct BuildConfig {
|
||||
#[serde(default = "default_dev_path")]
|
||||
pub dev_path: String
|
||||
pub dev_path: String,
|
||||
}
|
||||
|
||||
fn default_dev_path() -> String {
|
||||
"".to_string()
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Deserialize, Clone)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct Config {
|
||||
#[serde(default = "default_tauri")]
|
||||
pub tauri: TauriConfig,
|
||||
#[serde(default = "default_build")]
|
||||
pub build: BuildConfig
|
||||
pub build: BuildConfig,
|
||||
}
|
||||
|
||||
fn default_tauri() -> TauriConfig {
|
||||
TauriConfig {
|
||||
window: default_window(),
|
||||
embedded_server: default_embedded_server()
|
||||
embedded_server: default_embedded_server(),
|
||||
}
|
||||
}
|
||||
|
||||
fn default_build() -> BuildConfig {
|
||||
BuildConfig {
|
||||
dev_path: default_dev_path()
|
||||
dev_path: default_dev_path(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get() -> Config {
|
||||
pub fn get() -> TauriResult<Config> {
|
||||
match option_env!("TAURI_CONFIG") {
|
||||
Some(config) => serde_json::from_str(config)
|
||||
.expect("failed to parse TAURI_CONFIG env"),
|
||||
None => serde_json::from_str(include_str!(concat!(env!("TAURI_DIR"), "/tauri.conf.json")))
|
||||
.expect("failed to read tauri.conf.json")
|
||||
Some(config) => Ok(serde_json::from_str(config).expect("failed to parse TAURI_CONFIG env")),
|
||||
None => Ok(
|
||||
serde_json::from_str(include_str!(concat!(env!("TAURI_DIR"), "/tauri.conf.json")))
|
||||
.expect("failed to read tauri.conf.json"),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,11 +2,13 @@ mod cmd;
|
|||
|
||||
use web_view::WebView;
|
||||
|
||||
use crate::TauriResult;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> bool {
|
||||
pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> TauriResult<bool> {
|
||||
use cmd::Cmd::*;
|
||||
match serde_json::from_str(arg) {
|
||||
Err(_) => false,
|
||||
Err(_) => Ok(false),
|
||||
Ok(command) => {
|
||||
match command {
|
||||
Init {} => {
|
||||
|
@ -44,13 +46,12 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
|
|||
listeners = crate::event::event_listeners_object_name(),
|
||||
queue = crate::event::event_queue_object_name()
|
||||
);
|
||||
webview
|
||||
.eval(&format!(
|
||||
r#"{event_init}
|
||||
webview.eval(&format!(
|
||||
r#"{event_init}
|
||||
window.external.invoke('{{"cmd":"__initialized"}}')
|
||||
"#,
|
||||
event_init = event_init
|
||||
)).expect("Failed to call webview.eval from init");
|
||||
event_init = event_init
|
||||
))?;
|
||||
}
|
||||
#[cfg(any(feature = "all-api", feature = "readTextFile"))]
|
||||
ReadTextFile {
|
||||
|
@ -95,7 +96,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
|
|||
}
|
||||
#[cfg(any(feature = "all-api", feature = "setTitle"))]
|
||||
SetTitle { title } => {
|
||||
webview.set_title(&title).expect("Failed to set title");
|
||||
webview.set_title(&title)?;
|
||||
}
|
||||
#[cfg(any(feature = "all-api", feature = "execute"))]
|
||||
Execute {
|
||||
|
@ -211,7 +212,7 @@ pub(crate) fn handle<T: 'static>(webview: &mut WebView<'_, T>, arg: &str) -> boo
|
|||
);
|
||||
}
|
||||
}
|
||||
true
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,9 @@ use web_view::*;
|
|||
|
||||
pub use tauri_api as api;
|
||||
|
||||
// Result alias
|
||||
type TauriResult<T> = Result<T, Box<dyn std::error::Error>>;
|
||||
|
||||
thread_local!(static POOL: ThreadPool = ThreadPool::new(4));
|
||||
|
||||
pub fn spawn<F: FnOnce() -> () + Send + 'static>(task: F) {
|
||||
|
|
Loading…
Reference in New Issue