Migrate to actix-web 4 (#171)
* Migrate to actix-web 4 * Change expected swagger test status code * update tokio to 1.0 * fix clippy warnings
This commit is contained in:
parent
90fd6bbcc9
commit
374d0ca56f
11 changed files with 707 additions and 1001 deletions
1550
Cargo.lock
generated
1550
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
32
Cargo.toml
32
Cargo.toml
|
@ -11,39 +11,41 @@ bundle-sqlite = ["libsqlite3-sys"]
|
||||||
ui = ["native-windows-gui", "native-windows-derive"]
|
ui = ["native-windows-gui", "native-windows-derive"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-files = { version = "0.5" }
|
actix-files = { version = "0.6" }
|
||||||
actix-web = { version = "3" }
|
actix-web = { version = "4" }
|
||||||
actix-web-httpauth = { version = "0.5.1" }
|
actix-web-httpauth = { version = "0.6" }
|
||||||
anyhow = "1.0.52"
|
actix-test = "=0.1.0-beta.13"
|
||||||
|
anyhow = "1.0.56"
|
||||||
ape = "0.4.0"
|
ape = "0.4.0"
|
||||||
base64 = "0.13"
|
base64 = "0.13"
|
||||||
branca = "0.10.0"
|
branca = "0.10.1"
|
||||||
cookie = { version = "0.14", features = ["signed", "key-expansion"] }
|
cookie = { version = "0.16", features = ["signed", "key-expansion"] }
|
||||||
crossbeam-channel = "0.5"
|
crossbeam-channel = "0.5"
|
||||||
diesel_migrations = { version = "1.4", features = ["sqlite"] }
|
diesel_migrations = { version = "1.4", features = ["sqlite"] }
|
||||||
futures-util = { version = "0.3" }
|
futures-util = { version = "0.3" }
|
||||||
getopts = "0.2.21"
|
getopts = "0.2.21"
|
||||||
http = "0.2.6"
|
http = "0.2.6"
|
||||||
id3 = "1.0.2"
|
id3 = "1.0.2"
|
||||||
libsqlite3-sys = { version = "0.22", features = ["bundled", "bundled-windows"], optional = true }
|
|
||||||
lewton = "0.10.2"
|
lewton = "0.10.2"
|
||||||
|
libsqlite3-sys = { version = "0.22", features = ["bundled", "bundled-windows"], optional = true }
|
||||||
log = "0.4.14"
|
log = "0.4.14"
|
||||||
metaflac = "0.2.5"
|
metaflac = "0.2.5"
|
||||||
mp3-duration = "0.1.10"
|
mp3-duration = "0.1.10"
|
||||||
mp4ameta = "0.11.0"
|
mp4ameta = "0.11.0"
|
||||||
num_cpus = "1.13.1"
|
num_cpus = "1.13.1"
|
||||||
opus_headers = "0.1.2"
|
opus_headers = "0.1.2"
|
||||||
|
pbkdf2 = "0.11"
|
||||||
percent-encoding = "2.1"
|
percent-encoding = "2.1"
|
||||||
pbkdf2 = "0.10"
|
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
rayon = "1.5"
|
rayon = "1.5"
|
||||||
regex = "1.5.4"
|
regex = "1.5.5"
|
||||||
rustfm-scrobble = "1.1.1"
|
rustfm-scrobble = "1.1.1"
|
||||||
serde = { version = "1.0.133", features = ["derive"] }
|
serde = { version = "1.0.136", features = ["derive"] }
|
||||||
serde_derive = "1.0.133"
|
serde_derive = "1.0.136"
|
||||||
serde_json = "1.0.74"
|
serde_json = "1.0.79"
|
||||||
simplelog = "0.11.1"
|
simplelog = "0.11.2"
|
||||||
thiserror = "1.0.30"
|
thiserror = "1.0.30"
|
||||||
|
tokio = "1.0"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
ureq = "1.5.5"
|
ureq = "1.5.5"
|
||||||
url = "2.2"
|
url = "2.2"
|
||||||
|
@ -54,7 +56,7 @@ default_features = false
|
||||||
features = ["libsqlite3-sys", "r2d2", "sqlite", "64-column-tables"]
|
features = ["libsqlite3-sys", "r2d2", "sqlite", "64-column-tables"]
|
||||||
|
|
||||||
[dependencies.image]
|
[dependencies.image]
|
||||||
version = "0.23.14"
|
version = "0.24.1"
|
||||||
default_features = false
|
default_features = false
|
||||||
features = ["bmp", "gif", "jpeg", "png"]
|
features = ["bmp", "gif", "jpeg", "png"]
|
||||||
|
|
||||||
|
@ -64,7 +66,7 @@ native-windows-derive = {version = "1.0.4", optional = true }
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
daemonize = "0.4.1"
|
daemonize = "0.4.1"
|
||||||
sd-notify = "0.3.0"
|
sd-notify = "0.4.0"
|
||||||
|
|
||||||
[target.'cfg(windows)'.build-dependencies]
|
[target.'cfg(windows)'.build-dependencies]
|
||||||
winres = "0.1"
|
winres = "0.1"
|
||||||
|
|
|
@ -33,13 +33,13 @@ impl Manager {
|
||||||
|
|
||||||
if let Some(mount_dirs) = &config.mount_dirs {
|
if let Some(mount_dirs) = &config.mount_dirs {
|
||||||
self.vfs_manager
|
self.vfs_manager
|
||||||
.set_mount_dirs(&mount_dirs)
|
.set_mount_dirs(mount_dirs)
|
||||||
.map_err(|_| Error::Unspecified)?;
|
.map_err(|_| Error::Unspecified)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ddns_config) = &config.ydns {
|
if let Some(ddns_config) = &config.ydns {
|
||||||
self.ddns_manager
|
self.ddns_manager
|
||||||
.set_config(&ddns_config)
|
.set_config(ddns_config)
|
||||||
.map_err(|_| Error::Unspecified)?;
|
.map_err(|_| Error::Unspecified)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,7 @@ impl Index {
|
||||||
settings_manager,
|
settings_manager,
|
||||||
|
|
||||||
pending_reindex: Arc::new((
|
pending_reindex: Arc::new((
|
||||||
#[allow(clippy::clippy::mutex_atomic)]
|
#[allow(clippy::mutex_atomic)]
|
||||||
Mutex::new(false),
|
Mutex::new(false),
|
||||||
Condvar::new(),
|
Condvar::new(),
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -29,7 +29,7 @@ impl Manager {
|
||||||
fn get_thumbnail_path(&self, image_path: &Path, thumbnailoptions: &Options) -> PathBuf {
|
fn get_thumbnail_path(&self, image_path: &Path, thumbnailoptions: &Options) -> PathBuf {
|
||||||
let hash = Manager::hash(image_path, thumbnailoptions);
|
let hash = Manager::hash(image_path, thumbnailoptions);
|
||||||
let mut thumbnail_path = self.thumbnails_dir_path.clone();
|
let mut thumbnail_path = self.thumbnails_dir_path.clone();
|
||||||
thumbnail_path.push(format!("{}.jpg", hash.to_string()));
|
thumbnail_path.push(format!("{}.jpg", hash));
|
||||||
thumbnail_path
|
thumbnail_path
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,19 +40,19 @@ fn read_flac(path: &Path) -> Result<DynamicImage> {
|
||||||
fn read_mp3(path: &Path) -> Result<DynamicImage> {
|
fn read_mp3(path: &Path) -> Result<DynamicImage> {
|
||||||
let tag = id3::Tag::read_from_path(path)?;
|
let tag = id3::Tag::read_from_path(path)?;
|
||||||
|
|
||||||
read_id3(&path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_aiff(path: &Path) -> Result<DynamicImage> {
|
fn read_aiff(path: &Path) -> Result<DynamicImage> {
|
||||||
let tag = id3::Tag::read_from_aiff_path(path)?;
|
let tag = id3::Tag::read_from_aiff_path(path)?;
|
||||||
|
|
||||||
read_id3(&path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_wave(path: &Path) -> Result<DynamicImage> {
|
fn read_wave(path: &Path) -> Result<DynamicImage> {
|
||||||
let tag = id3::Tag::read_from_wav_path(path)?;
|
let tag = id3::Tag::read_from_wav_path(path)?;
|
||||||
|
|
||||||
read_id3(&path, &tag)
|
read_id3(path, &tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_id3(path: &Path, tag: &id3::Tag) -> Result<DynamicImage> {
|
fn read_id3(path: &Path, tag: &id3::Tag) -> Result<DynamicImage> {
|
||||||
|
|
|
@ -1,18 +1,19 @@
|
||||||
use actix_files::NamedFile;
|
use actix_files::NamedFile;
|
||||||
|
use actix_web::body::{BoxBody, MessageBody};
|
||||||
|
use actix_web::http::header::ContentEncoding;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
client::HttpError,
|
|
||||||
delete,
|
delete,
|
||||||
dev::{BodyEncoding, MessageBody, Payload, Service, ServiceRequest, ServiceResponse},
|
dev::{Payload, Service, ServiceRequest, ServiceResponse},
|
||||||
error::{BlockingError, ErrorForbidden, ErrorInternalServerError, ErrorUnauthorized},
|
error::{ErrorForbidden, ErrorInternalServerError, ErrorUnauthorized},
|
||||||
get,
|
get,
|
||||||
http::{ContentEncoding, StatusCode},
|
http::StatusCode,
|
||||||
post, put,
|
post, put,
|
||||||
web::{self, Data, Json, JsonConfig, ServiceConfig},
|
web::{self, Data, Json, JsonConfig, ServiceConfig},
|
||||||
FromRequest, HttpMessage, HttpRequest, HttpResponse, Responder, ResponseError,
|
FromRequest, HttpRequest, HttpResponse, Responder, ResponseError,
|
||||||
};
|
};
|
||||||
use actix_web_httpauth::extractors::{basic::BasicAuth, bearer::BearerAuth};
|
use actix_web_httpauth::extractors::{basic::BasicAuth, bearer::BearerAuth};
|
||||||
use cookie::{self, *};
|
use cookie::{self, *};
|
||||||
use futures_util::future::{err, ok, ready, Ready};
|
use futures_util::future::{err, ok};
|
||||||
use percent_encoding::percent_decode_str;
|
use percent_encoding::percent_decode_str;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
@ -113,7 +114,7 @@ impl Cookies {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_signed(&mut self, cookie: Cookie<'static>) {
|
fn add_signed(&mut self, cookie: Cookie<'static>) {
|
||||||
self.jar.signed(&self.key).add(cookie);
|
self.jar.signed_mut(&self.key).add(cookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
@ -129,7 +130,6 @@ impl Cookies {
|
||||||
impl FromRequest for Cookies {
|
impl FromRequest for Cookies {
|
||||||
type Error = actix_web::Error;
|
type Error = actix_web::Error;
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
||||||
type Config = ();
|
|
||||||
|
|
||||||
fn from_request(request: &HttpRequest, _payload: &mut Payload) -> Self::Future {
|
fn from_request(request: &HttpRequest, _payload: &mut Payload) -> Self::Future {
|
||||||
let request_cookies = match request.cookies() {
|
let request_cookies = match request.cookies() {
|
||||||
|
@ -168,7 +168,6 @@ struct Auth {
|
||||||
impl FromRequest for Auth {
|
impl FromRequest for Auth {
|
||||||
type Error = actix_web::Error;
|
type Error = actix_web::Error;
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
||||||
type Config = ();
|
|
||||||
|
|
||||||
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
||||||
|
@ -256,7 +255,6 @@ struct AdminRights {
|
||||||
impl FromRequest for AdminRights {
|
impl FromRequest for AdminRights {
|
||||||
type Error = actix_web::Error;
|
type Error = actix_web::Error;
|
||||||
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
type Future = Pin<Box<dyn Future<Output = Result<Self, Self::Error>>>>;
|
||||||
type Config = ();
|
|
||||||
|
|
||||||
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
fn from_request(request: &HttpRequest, payload: &mut Payload) -> Self::Future {
|
||||||
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
||||||
|
@ -289,11 +287,10 @@ impl FromRequest for AdminRights {
|
||||||
|
|
||||||
pub fn http_auth_middleware<
|
pub fn http_auth_middleware<
|
||||||
B: MessageBody + 'static,
|
B: MessageBody + 'static,
|
||||||
S: Service<Response = ServiceResponse<B>, Request = ServiceRequest, Error = actix_web::Error>
|
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error> + 'static,
|
||||||
+ 'static,
|
|
||||||
>(
|
>(
|
||||||
request: ServiceRequest,
|
request: ServiceRequest,
|
||||||
service: &mut S,
|
service: &S,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<ServiceResponse<B>, actix_web::Error>>>> {
|
) -> Pin<Box<dyn Future<Output = Result<ServiceResponse<B>, actix_web::Error>>>> {
|
||||||
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
let user_manager = match request.app_data::<Data<user::Manager>>() {
|
||||||
Some(m) => m.clone(),
|
Some(m) => m.clone(),
|
||||||
|
@ -303,10 +300,7 @@ pub fn http_auth_middleware<
|
||||||
let (request, mut payload) = request.into_parts();
|
let (request, mut payload) = request.into_parts();
|
||||||
let auth_future = Auth::from_request(&request, &mut payload);
|
let auth_future = Auth::from_request(&request, &mut payload);
|
||||||
let cookies_future = Cookies::from_request(&request, &mut payload);
|
let cookies_future = Cookies::from_request(&request, &mut payload);
|
||||||
let request = match ServiceRequest::from_parts(request, payload) {
|
let request = ServiceRequest::from_parts(request, payload);
|
||||||
Ok(s) => s,
|
|
||||||
Err(_) => return Box::pin(err(ErrorInternalServerError(APIError::Unspecified))),
|
|
||||||
};
|
|
||||||
|
|
||||||
let response_future = service.call(request);
|
let response_future = service.call(request);
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
|
@ -339,7 +333,7 @@ fn add_auth_cookies<T>(
|
||||||
cookies: &Cookies,
|
cookies: &Cookies,
|
||||||
username: &str,
|
username: &str,
|
||||||
is_admin: bool,
|
is_admin: bool,
|
||||||
) -> Result<(), HttpError> {
|
) -> Result<(), http::Error> {
|
||||||
let mut cookies = cookies.clone();
|
let mut cookies = cookies.clone();
|
||||||
|
|
||||||
cookies.add_signed(
|
cookies.add_signed(
|
||||||
|
@ -384,25 +378,20 @@ struct MediaFile {
|
||||||
|
|
||||||
impl MediaFile {
|
impl MediaFile {
|
||||||
fn new(named_file: NamedFile) -> Self {
|
fn new(named_file: NamedFile) -> Self {
|
||||||
Self {
|
Self { named_file }
|
||||||
named_file: named_file,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Responder for MediaFile {
|
impl Responder for MediaFile {
|
||||||
type Error = actix_web::Error;
|
type Body = BoxBody;
|
||||||
type Future = Ready<Result<HttpResponse, actix_web::Error>>;
|
|
||||||
|
|
||||||
fn respond_to(self, req: &HttpRequest) -> Self::Future {
|
fn respond_to(self, req: &HttpRequest) -> HttpResponse<Self::Body> {
|
||||||
let mut response = self.named_file.into_response(req);
|
// Intentionally turn off content encoding for media files because:
|
||||||
if let Ok(r) = response.as_mut() {
|
// 1. There is little value in compressing files that are already compressed (mp3, jpg, etc.)
|
||||||
// Intentionally turn off content encoding for media files because:
|
// 2. The Content-Length header is incompatible with content encoding (other than identity), and can be valuable for clients
|
||||||
// 1. There is little value in compressing files that are already compressed (mp3, jpg, etc.)
|
self.named_file
|
||||||
// 2. The Content-Length header is incompatible with content encoding (other than identity), and can be valuable for clients
|
.set_content_encoding(ContentEncoding::Identity)
|
||||||
r.encoding(ContentEncoding::Identity);
|
.into_response(req)
|
||||||
}
|
|
||||||
return ready(response);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,10 +401,10 @@ where
|
||||||
I: Send + 'static,
|
I: Send + 'static,
|
||||||
E: Send + std::fmt::Debug + 'static + Into<APIError>,
|
E: Send + std::fmt::Debug + 'static + Into<APIError>,
|
||||||
{
|
{
|
||||||
actix_web::web::block(f).await.map_err(|e| match e {
|
actix_web::web::block(f)
|
||||||
BlockingError::Error(e) => e.into(),
|
.await
|
||||||
BlockingError::Canceled => APIError::Unspecified,
|
.map_err(|_| APIError::Unspecified)
|
||||||
})
|
.and_then(|r| r.map_err(|e| e.into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/version")]
|
#[get("/version")]
|
||||||
|
@ -488,8 +477,8 @@ async fn put_mount_dirs(
|
||||||
new_mount_dirs: Json<Vec<dto::MountDir>>,
|
new_mount_dirs: Json<Vec<dto::MountDir>>,
|
||||||
) -> Result<HttpResponse, APIError> {
|
) -> Result<HttpResponse, APIError> {
|
||||||
let new_mount_dirs: Vec<MountDir> = new_mount_dirs
|
let new_mount_dirs: Vec<MountDir> = new_mount_dirs
|
||||||
.to_owned()
|
.iter()
|
||||||
.into_iter()
|
.cloned()
|
||||||
.map(|m| m.into())
|
.map(|m| m.into())
|
||||||
.collect();
|
.collect();
|
||||||
block(move || vfs_manager.set_mount_dirs(&new_mount_dirs)).await?;
|
block(move || vfs_manager.set_mount_dirs(&new_mount_dirs)).await?;
|
||||||
|
@ -646,7 +635,7 @@ async fn browse(
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
) -> Result<Json<Vec<index::CollectionFile>>, APIError> {
|
) -> Result<Json<Vec<index::CollectionFile>>, APIError> {
|
||||||
let result = block(move || {
|
let result = block(move || {
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
index.browse(Path::new(path.as_ref()))
|
index.browse(Path::new(path.as_ref()))
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -666,7 +655,7 @@ async fn flatten(
|
||||||
path: web::Path<String>,
|
path: web::Path<String>,
|
||||||
) -> Result<Json<Vec<index::Song>>, APIError> {
|
) -> Result<Json<Vec<index::Song>>, APIError> {
|
||||||
let songs = block(move || {
|
let songs = block(move || {
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
index.flatten(Path::new(path.as_ref()))
|
index.flatten(Path::new(path.as_ref()))
|
||||||
})
|
})
|
||||||
.await?;
|
.await?;
|
||||||
|
@ -712,7 +701,7 @@ async fn get_audio(
|
||||||
) -> Result<MediaFile, APIError> {
|
) -> Result<MediaFile, APIError> {
|
||||||
let audio_path = block(move || {
|
let audio_path = block(move || {
|
||||||
let vfs = vfs_manager.get_vfs()?;
|
let vfs = vfs_manager.get_vfs()?;
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
vfs.virtual_to_real(Path::new(path.as_ref()))
|
vfs.virtual_to_real(Path::new(path.as_ref()))
|
||||||
.map_err(|_| APIError::VFSPathNotFound)
|
.map_err(|_| APIError::VFSPathNotFound)
|
||||||
})
|
})
|
||||||
|
@ -734,7 +723,7 @@ async fn get_thumbnail(
|
||||||
|
|
||||||
let thumbnail_path = block(move || {
|
let thumbnail_path = block(move || {
|
||||||
let vfs = vfs_manager.get_vfs()?;
|
let vfs = vfs_manager.get_vfs()?;
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
let image_path = vfs
|
let image_path = vfs
|
||||||
.virtual_to_real(Path::new(path.as_ref()))
|
.virtual_to_real(Path::new(path.as_ref()))
|
||||||
.map_err(|_| APIError::VFSPathNotFound)?;
|
.map_err(|_| APIError::VFSPathNotFound)?;
|
||||||
|
@ -806,7 +795,7 @@ async fn lastfm_now_playing(
|
||||||
if !user_manager.is_lastfm_linked(&auth.username) {
|
if !user_manager.is_lastfm_linked(&auth.username) {
|
||||||
return Err(APIError::LastFMAccountNotLinked);
|
return Err(APIError::LastFMAccountNotLinked);
|
||||||
}
|
}
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
lastfm_manager.now_playing(&auth.username, Path::new(path.as_ref()))?;
|
lastfm_manager.now_playing(&auth.username, Path::new(path.as_ref()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
@ -825,7 +814,7 @@ async fn lastfm_scrobble(
|
||||||
if !user_manager.is_lastfm_linked(&auth.username) {
|
if !user_manager.is_lastfm_linked(&auth.username) {
|
||||||
return Err(APIError::LastFMAccountNotLinked);
|
return Err(APIError::LastFMAccountNotLinked);
|
||||||
}
|
}
|
||||||
let path = percent_decode_str(&(path.0)).decode_utf8_lossy();
|
let path = percent_decode_str(&path).decode_utf8_lossy();
|
||||||
lastfm_manager.scrobble(&auth.username, Path::new(path.as_ref()))?;
|
lastfm_manager.scrobble(&auth.username, Path::new(path.as_ref()))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
middleware::{normalize::TrailingSlash, Compress, Logger, NormalizePath},
|
middleware::{Compress, Logger, NormalizePath},
|
||||||
rt::System,
|
rt::System,
|
||||||
web::{self, ServiceConfig},
|
web::{self, ServiceConfig},
|
||||||
App as ActixApp, HttpServer,
|
App as ActixApp, HttpServer,
|
||||||
};
|
};
|
||||||
use anyhow::*;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
|
||||||
use crate::app::App;
|
use crate::app::App;
|
||||||
|
@ -31,7 +30,7 @@ pub fn make_config(app: App) -> impl FnOnce(&mut ServiceConfig) + Clone {
|
||||||
web::scope("/api")
|
web::scope("/api")
|
||||||
.configure(api::make_config())
|
.configure(api::make_config())
|
||||||
.wrap_fn(api::http_auth_middleware)
|
.wrap_fn(api::http_auth_middleware)
|
||||||
.wrap(NormalizePath::new(TrailingSlash::Trim)),
|
.wrap(NormalizePath::trim()),
|
||||||
)
|
)
|
||||||
.service(
|
.service(
|
||||||
actix_files::Files::new("/swagger", app.swagger_dir_path)
|
actix_files::Files::new("/swagger", app.swagger_dir_path)
|
||||||
|
@ -46,9 +45,9 @@ pub fn make_config(app: App) -> impl FnOnce(&mut ServiceConfig) + Clone {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(app: App) -> Result<()> {
|
pub fn run(app: App) -> anyhow::Result<()> {
|
||||||
System::run(move || {
|
let address = ("0.0.0.0", app.port);
|
||||||
let address = format!("0.0.0.0:{}", app.port);
|
System::new().block_on(
|
||||||
HttpServer::new(move || {
|
HttpServer::new(move || {
|
||||||
ActixApp::new()
|
ActixApp::new()
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
|
@ -57,9 +56,11 @@ pub fn run(app: App) -> Result<()> {
|
||||||
})
|
})
|
||||||
.disable_signals()
|
.disable_signals()
|
||||||
.bind(address)
|
.bind(address)
|
||||||
.map(|server| server.run())
|
.map_err(|e| {
|
||||||
.map_err(|e| error!("Error starting HTTP server: {:?}", e))
|
error!("Error starting HTTP server: {:?}", e);
|
||||||
.ok();
|
e
|
||||||
})?;
|
})?
|
||||||
|
.run()
|
||||||
|
)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
use actix_test::TestServer;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
middleware::{Compress, Logger},
|
middleware::{Compress, Logger},
|
||||||
rt::{System, SystemRunner},
|
rt::{System, SystemRunner},
|
||||||
test,
|
|
||||||
test::*,
|
|
||||||
web::Bytes,
|
web::Bytes,
|
||||||
App as ActixApp,
|
App as ActixApp,
|
||||||
};
|
};
|
||||||
|
@ -44,7 +43,7 @@ impl ActixTestService {
|
||||||
.timeout(std::time::Duration::from_secs(30));
|
.timeout(std::time::Duration::from_secs(30));
|
||||||
|
|
||||||
for (name, value) in request.headers() {
|
for (name, value) in request.headers() {
|
||||||
actix_request = actix_request.set_header(name, value.clone());
|
actix_request = actix_request.insert_header((name, value.clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(ref authorization) = self.authorization {
|
if let Some(ref authorization) = self.authorization {
|
||||||
|
@ -92,8 +91,8 @@ impl TestService for ActixTestService {
|
||||||
|
|
||||||
let app = App::new(5050, paths).unwrap();
|
let app = App::new(5050, paths).unwrap();
|
||||||
|
|
||||||
let system_runner = System::new("test");
|
let system_runner = System::new();
|
||||||
let server = test::start(move || {
|
let server = actix_test::start(move || {
|
||||||
let config = make_config(app.clone());
|
let config = make_config(app.clone());
|
||||||
ActixApp::new()
|
ActixApp::new()
|
||||||
.wrap(Logger::default())
|
.wrap(Logger::default())
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub enum ThumbnailSize {
|
||||||
Native,
|
Native,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::clippy::clippy::from_over_into)]
|
#[allow(clippy::from_over_into)]
|
||||||
impl Into<Option<u32>> for ThumbnailSize {
|
impl Into<Option<u32>> for ThumbnailSize {
|
||||||
fn into(self) -> Option<u32> {
|
fn into(self) -> Option<u32> {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -8,8 +8,7 @@ fn can_get_swagger_index() {
|
||||||
let mut service = ServiceType::new(&test_name!());
|
let mut service = ServiceType::new(&test_name!());
|
||||||
let request = protocol::swagger_index();
|
let request = protocol::swagger_index();
|
||||||
let response = service.fetch(&request);
|
let response = service.fetch(&request);
|
||||||
let status = response.status();
|
assert_eq!(response.status(), StatusCode::OK);
|
||||||
assert_eq!(status, StatusCode::FOUND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Reference in a new issue