add native/default file open
parent
4b7f0f66e2
commit
7a1d0a5024
|
@ -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",
|
||||
|
|
|
@ -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"]
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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."))
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue