Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite tauri_plugin_localhost to fix Linux resource loading issues #39

Merged
merged 5 commits into from
Dec 1, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bins/ayaka-gui/src-tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ flexi_logger = { version = "0.24", default-features = false, features = ["colors
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
tauri = { version = "1.2", features = ["cli", "protocol-all", "window-all"] }
tauri-plugin-localhost = "0.1"
tiny_http = "0.12"
url = "2.3"
minreq = "2.6"
mime_guess = "2.0"
portpicker = "0.1"
trylog = "0.2"

Expand Down
103 changes: 103 additions & 0 deletions bins/ayaka-gui/src-tauri/src/asset_resolver.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
use std::{path::PathBuf, sync::OnceLock};
use tauri::{
plugin::{Builder, TauriPlugin},
Runtime,
};
use tiny_http::{Header, Server};

pub(crate) static ROOT_PATH: OnceLock<PathBuf> = OnceLock::new();

pub fn init<R: Runtime>(dev_url: String, port: u16) -> TauriPlugin<R> {
Builder::new("asset_resolver")
.setup(move |app| {
let asset_resolver = app.asset_resolver();
std::thread::spawn(move || {
let server = Server::http(format!("127.0.0.1:{port}"))
.expect("Unable to start local server");
for req in server.incoming_requests() {
let url = req.url().to_string();
Tim-Paik marked this conversation as resolved.
Show resolved Hide resolved
if cfg!(debug_assertions) {
let _ = asset_resolver;
} else if url.starts_with("/assets/")
|| url == "/"
|| url == "/live2d.min.js"
|| url == "/live2dcubismcore.min.js"
{
let asset = asset_resolver.get(url).unwrap();
let mut resp = tiny_http::Response::from_data(asset.bytes);
resp.add_header(
Header::from_bytes("Content-Type", asset.mime_type)
.expect("Unable to convert mime_type to Content-Type"),
);
req.respond(resp).expect("Unable to setup response");
continue;
}
if url.starts_with("/fs/") {
let path = ROOT_PATH
.get()
.unwrap()
.clone()
.join(url.strip_prefix("/fs/").unwrap());
let file = if path.is_file() {
std::fs::File::open(&path).unwrap()
} else if path.is_dir() {
match std::fs::File::open(path.join("index.html")) {
Ok(file) => file,
Err(_) => {
req.respond(tiny_http::Response::empty(404))
.expect("Unable to setup response");
continue;
}
}
} else {
req.respond(tiny_http::Response::empty(404))
.expect("Unable to setup response");
continue;
};
let mut resp = tiny_http::Response::from_file(file);
if let Some(mime) = mime_guess::from_path(url).first() {
resp.add_header(
Header::from_bytes("Content-Type", mime.essence_str())
.expect("Unable to convert mime_type to Content-Type"),
);
}
req.respond(resp).expect("Unable to setup response");
} else if cfg!(debug_assertions) {
let req_url = url::Url::parse(&dev_url).unwrap().join(&url).unwrap();
let req_url = if req_url
.path_segments()
.unwrap()
.last()
.unwrap_or_default()
.is_empty()
{
req_url.join("index.html").unwrap()
} else {
req_url
};
let resp = minreq::get(req_url).send().expect("Unable to send request");
req.respond(tiny_http::Response::new(
resp.status_code.into(),
resp.headers
.iter()
.map(|(k, v)| {
Header::from_bytes(k.as_bytes(), v.as_bytes())
.expect("Unable to convert Header")
})
.collect(),
resp.as_bytes(),
None,
None,
))
.expect("Unable to setup response")
} else {
let _ = dev_url;
req.respond(tiny_http::Response::empty(404))
.expect("Unable to setup response")
}
}
});
Ok(())
})
.build()
}
38 changes: 23 additions & 15 deletions bins/ayaka-gui/src-tauri/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
#![feature(absolute_path)]
#![feature(once_cell)]

mod asset_resolver;

use ayaka_runtime::{
anyhow::{self, anyhow, Result},
Expand All @@ -14,9 +16,11 @@ use serde::{Deserialize, Serialize};
use std::{
collections::{HashMap, HashSet},
fmt::Display,
path::PathBuf,
path::Path,
};
use tauri::{
async_runtime::Mutex, command, utils::config::AppUrl, AppHandle, Manager, State, WindowUrl,
};
use tauri::{async_runtime::Mutex, command, AppHandle, Manager, State};
use trylog::TryLog;

type CommandResult<T> = std::result::Result<T, CommandError>;
Expand Down Expand Up @@ -70,7 +74,6 @@ impl OpenGameStatus {
struct Storage {
ident: String,
config: String,
root_path: PathBuf,
records: Mutex<Vec<ActionRecord>>,
context: Mutex<Option<Context>>,
current: Mutex<Option<RawContext>>,
Expand All @@ -81,15 +84,9 @@ struct Storage {
impl Storage {
pub fn new(ident: impl Into<String>, config: impl Into<String>) -> Self {
let config = config.into();
let root_path = std::path::absolute(&config)
.unwrap()
.parent()
.unwrap()
.to_path_buf();
Self {
ident: ident.into(),
config,
root_path,
..Default::default()
}
}
Expand All @@ -113,8 +110,8 @@ impl GameInfo {
}

#[command]
fn absolute_path(storage: State<'_, Storage>, path: String) -> CommandResult<String> {
Ok(storage.root_path.join(path).to_string_lossy().into_owned())
fn absolute_path(path: String) -> CommandResult<String> {
Ok(Path::new("/fs/").join(path).to_string_lossy().into_owned())
}

#[command]
Expand Down Expand Up @@ -426,9 +423,14 @@ fn main() -> Result<()> {
let port =
portpicker::pick_unused_port().ok_or_else(|| anyhow!("failed to find unused port"))?;
info!("Picked port {}", port);
let mut context = tauri::generate_context!();
let window_url = WindowUrl::External(format!("http://127.0.0.1:{port}").parse().unwrap());
let dev_url = context.config().build.dev_path.to_string();
context.config_mut().build.dist_dir = AppUrl::Url(window_url.clone());
context.config_mut().build.dev_path = AppUrl::Url(window_url);
tauri::Builder::default()
.plugin(tauri_plugin_localhost::Builder::new(port).build())
.setup(|app| {
.plugin(asset_resolver::init(dev_url, port))
.setup(move |app| {
let ident = app.config().tauri.bundle.identifier.clone();
let spec = LogSpecification::parse("warn,ayaka=debug")?;
let log_handle = if cfg!(debug_assertions) {
Expand Down Expand Up @@ -467,6 +469,12 @@ fn main() -> Result<()> {
.to_string_lossy()
.into_owned()
});
let root_path = std::fs::canonicalize(&config)
.expect("configuration file not found")
.parent()
.unwrap()
.to_path_buf();
asset_resolver::ROOT_PATH.set(root_path).unwrap();
app.manage(Storage::new(ident, config));
Ok(())
})
Expand All @@ -493,6 +501,6 @@ fn main() -> Result<()> {
switch,
history,
])
.run(tauri::generate_context!())?;
.run(context)?;
Ok(())
}
4 changes: 2 additions & 2 deletions bins/ayaka-gui/src/interop/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { convertFileSrc, invoke } from "@tauri-apps/api/tauri"
import { invoke } from "@tauri-apps/api/tauri"
import { Locale } from 'vue-i18n'

export async function conv_src(path?: string): Promise<string | undefined> {
if (path) {
return decodeURIComponent(convertFileSrc(await invoke("absolute_path", { path: path })))
return decodeURIComponent(await invoke("absolute_path", { path: path }))
}
return undefined
}
Expand Down