mirror of
https://git.asonix.dog/asonix/pict-rs
synced 2024-12-22 19:31:35 +00:00
Add ability to set 404 image
Fix imagemagick blur arguments
This commit is contained in:
parent
e7e4876908
commit
3487cb0e30
4 changed files with 85 additions and 13 deletions
15
README.md
15
README.md
|
@ -430,6 +430,21 @@ A secure API key can be generated by any password generator.
|
||||||
"identifier": "/path/to/object"
|
"identifier": "/path/to/object"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
- `POST /internal/set_not_found` Set the 404 image that is served from the original and process
|
||||||
|
endpoints. The image used must already be uploaded and have an alias. The request should look
|
||||||
|
like this:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"alias": "asdf.png"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
On success, the returned json should look like this:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "ok"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Additionally, all endpoints support setting deadlines, after which the request will cease
|
Additionally, all endpoints support setting deadlines, after which the request will cease
|
||||||
processing. To enable deadlines for your requests, you can set the `X-Request-Deadline` header to an
|
processing. To enable deadlines for your requests, you can set the `X-Request-Deadline` header to an
|
||||||
|
|
2
dev.toml
2
dev.toml
|
@ -1,6 +1,8 @@
|
||||||
[server]
|
[server]
|
||||||
address = '0.0.0.0:8080'
|
address = '0.0.0.0:8080'
|
||||||
worker_id = 'pict-rs-1'
|
worker_id = 'pict-rs-1'
|
||||||
|
api_key = 'api-key'
|
||||||
|
|
||||||
[tracing.logging]
|
[tracing.logging]
|
||||||
format = 'normal'
|
format = 'normal'
|
||||||
targets = 'warn,tracing_actix_web=info,actix_server=info,actix_web=info'
|
targets = 'warn,tracing_actix_web=info,actix_server=info,actix_web=info'
|
||||||
|
|
73
src/lib.rs
73
src/lib.rs
|
@ -80,6 +80,8 @@ const MINUTES: u32 = 60;
|
||||||
const HOURS: u32 = 60 * MINUTES;
|
const HOURS: u32 = 60 * MINUTES;
|
||||||
const DAYS: u32 = 24 * HOURS;
|
const DAYS: u32 = 24 * HOURS;
|
||||||
|
|
||||||
|
const NOT_FOUND_KEY: &str = "404-alias";
|
||||||
|
|
||||||
static DO_CONFIG: OnceCell<(Configuration, Operation)> = OnceCell::new();
|
static DO_CONFIG: OnceCell<(Configuration, Operation)> = OnceCell::new();
|
||||||
static CONFIG: Lazy<Configuration> = Lazy::new(|| {
|
static CONFIG: Lazy<Configuration> = Lazy::new(|| {
|
||||||
DO_CONFIG
|
DO_CONFIG
|
||||||
|
@ -595,6 +597,21 @@ async fn process_details<R: FullRepo, S: Store>(
|
||||||
Ok(HttpResponse::Ok().json(&details))
|
Ok(HttpResponse::Ok().json(&details))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn not_found_hash<R: FullRepo>(repo: &R) -> Result<Option<(Alias, R::Bytes)>, Error> {
|
||||||
|
let Some(not_found) = repo.get(NOT_FOUND_KEY).await? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
|
let alias = String::from_utf8_lossy(not_found.as_ref())
|
||||||
|
.parse::<Alias>()
|
||||||
|
.expect("Infallible");
|
||||||
|
|
||||||
|
repo.hash(&alias)
|
||||||
|
.await
|
||||||
|
.map(|opt| opt.map(|hash| (alias, hash)))
|
||||||
|
.map_err(Error::from)
|
||||||
|
}
|
||||||
|
|
||||||
/// Process files
|
/// Process files
|
||||||
#[tracing::instrument(name = "Serving processed image", skip(repo, store))]
|
#[tracing::instrument(name = "Serving processed image", skip(repo, store))]
|
||||||
async fn process<R: FullRepo, S: Store + 'static>(
|
async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
|
@ -607,12 +624,17 @@ async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
let (format, alias, thumbnail_path, thumbnail_args) = prepare_process(query, ext.as_str())?;
|
let (format, alias, thumbnail_path, thumbnail_args) = prepare_process(query, ext.as_str())?;
|
||||||
|
|
||||||
let path_string = thumbnail_path.to_string_lossy().to_string();
|
let path_string = thumbnail_path.to_string_lossy().to_string();
|
||||||
let Some(hash) = repo.hash(&alias).await? else {
|
|
||||||
// Invalid alias
|
let (hash, alias, not_found) = if let Some(hash) = repo.hash(&alias).await? {
|
||||||
// TODO: placeholder 404 image
|
(hash, alias, false)
|
||||||
|
} else {
|
||||||
|
let Some((alias, hash)) = not_found_hash(&repo).await? else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(hash, alias, true)
|
||||||
|
};
|
||||||
|
|
||||||
let identifier_opt = repo
|
let identifier_opt = repo
|
||||||
.variant_identifier::<S::Identifier>(hash.clone(), path_string)
|
.variant_identifier::<S::Identifier>(hash.clone(), path_string)
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -637,7 +659,7 @@ async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
new_details
|
new_details
|
||||||
};
|
};
|
||||||
|
|
||||||
return ranged_file_resp(&store, identifier, range, details).await;
|
return ranged_file_resp(&store, identifier, range, details, not_found).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let original_details = ensure_details(&repo, &store, &alias).await?;
|
let original_details = ensure_details(&repo, &store, &alias).await?;
|
||||||
|
@ -674,6 +696,11 @@ async fn process<R: FullRepo, S: Store + 'static>(
|
||||||
} else {
|
} else {
|
||||||
return Err(UploadError::Range.into());
|
return Err(UploadError::Range.into());
|
||||||
}
|
}
|
||||||
|
} else if not_found {
|
||||||
|
(
|
||||||
|
HttpResponse::NotFound(),
|
||||||
|
Either::right(once(ready(Ok(bytes)))),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
(HttpResponse::Ok(), Either::right(once(ready(Ok(bytes)))))
|
(HttpResponse::Ok(), Either::right(once(ready(Ok(bytes)))))
|
||||||
};
|
};
|
||||||
|
@ -785,15 +812,21 @@ async fn serve<R: FullRepo, S: Store + 'static>(
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let alias = alias.into_inner();
|
let alias = alias.into_inner();
|
||||||
|
|
||||||
let Some(identifier) = repo.identifier_from_alias::<S::Identifier>(&alias).await? else {
|
let (hash, alias, not_found) = if let Some(hash) = repo.hash(&alias).await? {
|
||||||
// Invalid alias
|
(hash, Serde::into_inner(alias), false)
|
||||||
// TODO: placeholder 404 image
|
} else {
|
||||||
|
let Some((alias, hash)) = not_found_hash(&repo).await? else {
|
||||||
return Ok(HttpResponse::NotFound().finish());
|
return Ok(HttpResponse::NotFound().finish());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(hash, alias, true)
|
||||||
|
};
|
||||||
|
|
||||||
|
let identifier = repo.identifier(hash).await?;
|
||||||
|
|
||||||
let details = ensure_details(&repo, &store, &alias).await?;
|
let details = ensure_details(&repo, &store, &alias).await?;
|
||||||
|
|
||||||
ranged_file_resp(&store, identifier, range, details).await
|
ranged_file_resp(&store, identifier, range, details, not_found).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Serving file headers", skip(repo, store))]
|
#[tracing::instrument(name = "Serving file headers", skip(repo, store))]
|
||||||
|
@ -855,6 +888,7 @@ async fn ranged_file_resp<S: Store + 'static>(
|
||||||
identifier: S::Identifier,
|
identifier: S::Identifier,
|
||||||
range: Option<web::Header<Range>>,
|
range: Option<web::Header<Range>>,
|
||||||
details: Details,
|
details: Details,
|
||||||
|
not_found: bool,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let (builder, stream) = if let Some(web::Header(range_header)) = range {
|
let (builder, stream) = if let Some(web::Header(range_header)) = range {
|
||||||
//Range header exists - return as ranged
|
//Range header exists - return as ranged
|
||||||
|
@ -887,7 +921,12 @@ async fn ranged_file_resp<S: Store + 'static>(
|
||||||
.to_stream(&identifier, None, None)
|
.to_stream(&identifier, None, None)
|
||||||
.await?
|
.await?
|
||||||
.map_err(Error::from);
|
.map_err(Error::from);
|
||||||
|
|
||||||
|
if not_found {
|
||||||
|
(HttpResponse::NotFound(), Either::right(stream))
|
||||||
|
} else {
|
||||||
(HttpResponse::Ok(), Either::right(stream))
|
(HttpResponse::Ok(), Either::right(stream))
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(srv_response(
|
Ok(srv_response(
|
||||||
|
@ -952,6 +991,21 @@ struct AliasQuery {
|
||||||
alias: Serde<Alias>,
|
alias: Serde<Alias>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(name = "Setting 404 Image", skip(repo))]
|
||||||
|
async fn set_not_found<R: FullRepo>(
|
||||||
|
json: web::Json<AliasQuery>,
|
||||||
|
repo: web::Data<R>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
let alias = json.into_inner().alias;
|
||||||
|
|
||||||
|
repo.set(NOT_FOUND_KEY, Vec::from(alias.to_string()).into())
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
Ok(HttpResponse::Created().json(serde_json::json!({
|
||||||
|
"msg": "ok",
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(name = "Purging file", skip(repo))]
|
#[tracing::instrument(name = "Purging file", skip(repo))]
|
||||||
async fn purge<R: FullRepo>(
|
async fn purge<R: FullRepo>(
|
||||||
query: web::Query<AliasQuery>,
|
query: web::Query<AliasQuery>,
|
||||||
|
@ -1110,7 +1164,8 @@ fn configure_endpoints<R: FullRepo + 'static, S: Store + 'static>(
|
||||||
.service(web::resource("/variants").route(web::delete().to(clean_variants::<R>)))
|
.service(web::resource("/variants").route(web::delete().to(clean_variants::<R>)))
|
||||||
.service(web::resource("/purge").route(web::post().to(purge::<R>)))
|
.service(web::resource("/purge").route(web::post().to(purge::<R>)))
|
||||||
.service(web::resource("/aliases").route(web::get().to(aliases::<R>)))
|
.service(web::resource("/aliases").route(web::get().to(aliases::<R>)))
|
||||||
.service(web::resource("/identifier").route(web::get().to(identifier::<R, S>))),
|
.service(web::resource("/identifier").route(web::get().to(identifier::<R, S>)))
|
||||||
|
.service(web::resource("/set_not_found").route(web::post().to(set_not_found::<R>))),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -295,7 +295,7 @@ impl Processor for Blur {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command(&self, mut args: Vec<String>) -> Vec<String> {
|
fn command(&self, mut args: Vec<String>) -> Vec<String> {
|
||||||
args.extend(["-gaussian-blur".to_string(), self.0.to_string()]);
|
args.extend(["-gaussian-blur".to_string(), format!("0x{}", self.0)]);
|
||||||
|
|
||||||
args
|
args
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue