add native/default file open

feat/vaults
Tomáš Mládek 2021-12-19 22:38:41 +01:00
parent 4b7f0f66e2
commit 7a1d0a5024
5 changed files with 91 additions and 13 deletions

38
Cargo.lock generated
View File

@ -486,6 +486,17 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
[[package]]
name = "bstr"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
dependencies = [
"lazy_static",
"memchr 2.4.1",
"regex-automata",
]
[[package]]
name = "buf-min"
version = "0.4.0"
@ -1147,6 +1158,15 @@ dependencies = [
"winreg",
]
[[package]]
name = "is_executable"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa9acdc6d67b75e626ad644734e8bc6df893d9cd2a834129065d3dd6158ea9c8"
dependencies = [
"winapi 0.3.9",
]
[[package]]
name = "itoa"
version = "0.4.8"
@ -1514,6 +1534,16 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "opener"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ea3ebcd72a54701f56345f16785a6d3ac2df7e986d273eb4395c0b01db17952"
dependencies = [
"bstr",
"winapi 0.3.9",
]
[[package]]
name = "parking_lot"
version = "0.10.2"
@ -1829,6 +1859,12 @@ dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
[[package]]
name = "regex-syntax"
version = "0.6.25"
@ -2429,6 +2465,7 @@ dependencies = [
"env_logger",
"filebuffer",
"futures-util",
"is_executable",
"lazy_static",
"lexpr",
"libsqlite3-sys",
@ -2436,6 +2473,7 @@ dependencies = [
"lru",
"nonempty",
"once_cell",
"opener",
"rayon",
"serde",
"serde_json",

View File

@ -50,6 +50,8 @@ tree_magic = "0.2.3"
dotenv = "0.15.0"
xdg = "^2.1"
opener = { version = "^0.5.0", optional = true }
is_executable = { version = "1.0.1", optional = true }
webbrowser = { version = "^0.5.5", optional = true }
nonempty = "0.6.0"
@ -59,4 +61,4 @@ tempdir = "0.3.7"
[features]
default = ["desktop"]
desktop = ["webbrowser"]
desktop = ["webbrowser", "opener", "is_executable"]

View File

@ -49,6 +49,11 @@ fn main() -> Result<()> {
.long("no-browser")
.help("Do not open web browser with the UI."),
)
.arg(
Arg::with_name("NO_DESKTOP")
.long("no-desktop")
.help("Disable desktop features (webbrowser, native file opening)"),
)
.arg(
Arg::with_name("NO_UI")
.long("no-ui")

View File

@ -9,10 +9,10 @@ use crate::util::hash::{decode, encode};
use crate::util::jobs::JobContainer;
use actix_files::NamedFile;
use actix_web::error::{ErrorBadRequest, ErrorInternalServerError, ErrorNotFound};
use actix_web::{delete, error, get, post, put, web, Error, HttpResponse};
use actix_web::{delete, error, get, post, put, web, Either, Error, HttpResponse};
use anyhow::Result;
use futures_util::StreamExt;
use log::{debug, trace};
use log::{debug, info, trace};
use serde::Deserialize;
use serde_json::json;
use std::collections::HashMap;
@ -20,6 +20,9 @@ use std::convert::TryFrom;
use std::path::PathBuf;
use std::sync::{Arc, RwLock};
#[cfg(feature = "desktop")]
use is_executable::IsExecutable;
const VERSION: &str = env!("CARGO_PKG_VERSION");
#[derive(Clone)]
@ -30,22 +33,44 @@ pub struct State {
pub job_container: Arc<RwLock<JobContainer>>,
}
#[derive(Deserialize)]
pub struct RawRequest {
native: Option<String>,
}
#[get("/api/raw/{hash}")]
pub async fn get_raw(state: web::Data<State>, hash: web::Path<String>) -> Result<NamedFile, Error> {
pub async fn get_raw(
state: web::Data<State>,
web::Query(query): web::Query<RawRequest>,
hash: web::Path<String>,
) -> Result<Either<NamedFile, HttpResponse>, Error> {
let address = Address::decode(&decode(hash.into_inner()).map_err(ErrorInternalServerError)?)
.map_err(ErrorInternalServerError)?;
if let Address::Hash(hash) = address {
let connection = state.db_pool.get().map_err(ErrorInternalServerError)?;
let response = retrieve_file(&connection, hash);
let files = retrieve_file(&connection, hash).map_err(ErrorInternalServerError)?;
if let Some(file) = files.get(0) {
let file_path = state.directory.join(&file.path);
debug!("{:?}", response);
match response {
Ok(result) => match result.get(0) {
Some(file) => Ok(NamedFile::open(state.directory.join(&file.path))?),
None => Err(error::ErrorNotFound("NOT FOUND")),
},
Err(e) => Err(error::ErrorInternalServerError(e)),
if !query.native.is_some() {
Ok(Either::A(NamedFile::open(file_path)?))
} else {
if cfg!(feature = "desktop") {
#[cfg(feature = "desktop")]
{
info!("Opening {:?}...", file_path);
if !file_path.is_executable() {
opener::open(file_path).map_err(error::ErrorServiceUnavailable)?;
return Ok(Either::B(HttpResponse::NoContent().finish()));
}
}
Err(error::ErrorForbidden(""))
} else {
Err(error::ErrorBadRequest("Desktop features not enabled."))
}
}
} else {
Err(error::ErrorNotFound("NOT FOUND"))
}
} else {
Err(ErrorBadRequest("Address does not refer to a file."))

View File

@ -35,6 +35,11 @@
Array.from(new Set(inferredIds.concat(labels))).join(" | ") || address;
$: dispatch("resolved", inferredIds);
// Native open
function nativeOpen() {
fetch(`/api/raw/${address}?native=1`);
}
</script>
<div class="address" class:identified={Boolean(inferredIds)} class:banner>
@ -53,6 +58,9 @@
<Ellipsis value={displayLabel} />
{/if}
</div>
{#if banner && isFile}
<sl-icon-button name="arrow-up-right-circle" on:click="{nativeOpen}" title="Open in default application..." />
{/if}
</div>
<style scoped lang="scss">