Clippy lints

master
Edward Shen 2021-07-12 00:12:15 -04:00
parent 8f3430fb77
commit 69587b9ade
Signed by: edward
GPG Key ID: 19182661E818369F
4 changed files with 99 additions and 79 deletions

9
src/cache/compat.rs vendored
View File

@ -1,10 +1,11 @@
//! These structs have alternative deserialize and serializations
//! implementations to assist reading from the official client file format.
use std::str::FromStr;
use chrono::{DateTime, FixedOffset};
use serde::{
de::{Unexpected, Visitor},
Deserialize, Serialize,
};
use serde::de::{Unexpected, Visitor};
use serde::{Deserialize, Serialize};
use super::ImageContentType;

126
src/cache/disk.rs vendored
View File

@ -1,5 +1,7 @@
//! Low memory caching stuff
use std::convert::TryFrom;
use std::hint::unreachable_unchecked;
use std::os::unix::prelude::OsStrExt;
use std::path::{Path, PathBuf};
use std::str::FromStr;
@ -12,7 +14,7 @@ use log::{debug, error, warn, LevelFilter};
use md5::digest::generic_array::GenericArray;
use md5::{Digest, Md5};
use sqlx::sqlite::SqliteConnectOptions;
use sqlx::{ConnectOptions, SqlitePool};
use sqlx::{ConnectOptions, Sqlite, SqlitePool, Transaction};
use tokio::fs::remove_file;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio_stream::wrappers::ReceiverStream;
@ -112,7 +114,6 @@ async fn db_listener(
) {
let mut recv_stream = ReceiverStream::new(db_rx).ready_chunks(128);
while let Some(messages) = recv_stream.next().await {
let now = chrono::Utc::now();
let mut transaction = match db_pool.begin().await {
Ok(transaction) => transaction,
Err(e) => {
@ -120,45 +121,12 @@ async fn db_listener(
continue;
}
};
for message in messages {
match message {
DbMessage::Get(entry) => {
let hash = Md5Hash::from(entry.as_path());
let hash_str = hash.to_hex_string();
let key = entry.as_os_str().to_str();
// let legacy_key = key.map();
let query = sqlx::query!(
"update Images set accessed = ? where id = ? or id = ?",
now,
key,
hash_str
)
.execute(&mut transaction)
.await;
if let Err(e) = query {
warn!("Failed to update timestamp in db for {:?}: {}", key, e);
}
}
DbMessage::Get(entry) => handle_db_get(entry, &mut transaction).await,
DbMessage::Put(entry, size) => {
let key = entry.as_os_str().to_str();
{
// This is intentional.
#[allow(clippy::cast_possible_wrap)]
let size = size as i64;
let query = sqlx::query!(
"insert into Images (id, size, accessed) values (?, ?, ?) on conflict do nothing",
key,
size,
now,
)
.execute(&mut transaction)
.await;
if let Err(e) = query {
warn!("Failed to add {:?} to db: {}", key, e);
}
}
cache.disk_cur_size.fetch_add(size, Ordering::Release);
handle_db_put(entry, size, &cache, &mut transaction).await;
}
}
}
@ -233,6 +201,60 @@ async fn db_listener(
}
}
async fn handle_db_get(entry: Arc<PathBuf>, transaction: &mut Transaction<'_, Sqlite>) {
let hash = if let Ok(hash) = Md5Hash::try_from(entry.as_path()) {
hash
} else {
error!(
"Failed to derive hash from entry, dropping message: {}",
entry.to_string_lossy()
);
return;
};
let hash_str = hash.to_hex_string();
let key = entry.as_os_str().to_str();
let now = chrono::Utc::now();
let query = sqlx::query!(
"update Images set accessed = ? where id = ? or id = ?",
now,
key,
hash_str
)
.execute(transaction)
.await;
if let Err(e) = query {
warn!("Failed to update timestamp in db for {:?}: {}", key, e);
}
}
async fn handle_db_put(
entry: Arc<PathBuf>,
size: u64,
cache: &DiskCache,
transaction: &mut Transaction<'_, Sqlite>,
) {
let key = entry.as_os_str().to_str();
let now = chrono::Utc::now();
// This is intentional.
#[allow(clippy::cast_possible_wrap)]
let casted_size = size as i64;
let query = sqlx::query!(
"insert into Images (id, size, accessed) values (?, ?, ?) on conflict do nothing",
key,
casted_size,
now,
)
.execute(transaction)
.await;
if let Err(e) = query {
warn!("Failed to add {:?} to db: {}", key, e);
}
cache.disk_cur_size.fetch_add(size, Ordering::Release);
}
/// Represents a Md5 hash that can be converted to and from a path. This is used
/// for compatibility with the official client, where the image id and on-disk
/// path is determined by file path.
@ -245,12 +267,14 @@ impl Md5Hash {
}
}
impl From<&Path> for Md5Hash {
fn from(path: &Path) -> Self {
impl TryFrom<&Path> for Md5Hash {
type Error = ();
fn try_from(path: &Path) -> Result<Self, Self::Error> {
let mut iter = path.iter();
let file_name = iter.next_back().unwrap();
let chapter_hash = iter.next_back().unwrap();
let is_data_saver = iter.next_back().unwrap() == "saver";
let file_name = iter.next_back().ok_or(())?;
let chapter_hash = iter.next_back().ok_or(())?;
let is_data_saver = iter.next_back().ok_or(())? == "saver";
let mut hasher = Md5::new();
if is_data_saver {
hasher.update("saver");
@ -258,23 +282,23 @@ impl From<&Path> for Md5Hash {
hasher.update(chapter_hash.as_bytes());
hasher.update(".");
hasher.update(file_name.as_bytes());
Self(hasher.finalize())
Ok(Self(hasher.finalize()))
}
}
// Lint is overly aggressive here, as Md5Hash guarantees there to be at least 3
// bytes.
#[allow(clippy::fallible_impl_from)]
impl From<Md5Hash> for PathBuf {
fn from(hash: Md5Hash) -> Self {
let hex_value = hash.to_hex_string();
hex_value[0..3]
let path = hex_value[0..3]
.chars()
.rev()
.map(|char| Self::from(char.to_string()))
.reduce(|first, second| first.join(second))
.unwrap() // literally not possible
.join(hex_value)
.reduce(|first, second| first.join(second));
match path {
Some(p) => p.join(hex_value),
None => unsafe { unreachable_unchecked() }, // literally not possible
}
}
}

17
src/cache/mod.rs vendored
View File

@ -115,12 +115,11 @@ impl From<LegacyImageMetadata> for ImageMetadata {
}
}
#[allow(clippy::enum_variant_names)]
#[derive(Debug)]
pub enum ImageRequestError {
InvalidContentType,
InvalidContentLength,
InvalidLastModified,
ContentType,
ContentLength,
LastModified,
}
impl ImageMetadata {
@ -136,14 +135,14 @@ impl ImageMetadata {
Err(_) => Err(InvalidContentType),
})
.transpose()
.map_err(|_| ImageRequestError::InvalidContentType)?,
.map_err(|_| ImageRequestError::ContentType)?,
content_length: content_length
.map(|header_val| {
header_val
.to_str()
.map_err(|_| ImageRequestError::InvalidContentLength)?
.map_err(|_| ImageRequestError::ContentLength)?
.parse()
.map_err(|_| ImageRequestError::InvalidContentLength)
.map_err(|_| ImageRequestError::ContentLength)
})
.transpose()?,
last_modified: last_modified
@ -151,9 +150,9 @@ impl ImageMetadata {
DateTime::parse_from_rfc2822(
header_val
.to_str()
.map_err(|_| ImageRequestError::InvalidLastModified)?,
.map_err(|_| ImageRequestError::LastModified)?,
)
.map_err(|_| ImageRequestError::InvalidLastModified)
.map_err(|_| ImageRequestError::LastModified)
})
.transpose()?,
})

View File

@ -1,24 +1,20 @@
use std::{collections::HashMap, sync::Arc, time::Duration};
use std::collections::HashMap;
use std::sync::Arc;
use std::time::Duration;
use actix_web::{
http::{HeaderMap, HeaderName, HeaderValue},
web::Data,
};
use actix_web::http::{HeaderMap, HeaderName, HeaderValue};
use actix_web::web::Data;
use bytes::Bytes;
use log::{debug, error, warn};
use once_cell::sync::Lazy;
use parking_lot::RwLock;
use reqwest::{
header::{
ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS, CACHE_CONTROL, CONTENT_LENGTH,
CONTENT_TYPE, LAST_MODIFIED, X_CONTENT_TYPE_OPTIONS,
},
Client, StatusCode,
};
use tokio::sync::{
watch::{channel, Receiver},
Notify,
use reqwest::header::{
ACCESS_CONTROL_ALLOW_ORIGIN, ACCESS_CONTROL_EXPOSE_HEADERS, CACHE_CONTROL, CONTENT_LENGTH,
CONTENT_TYPE, LAST_MODIFIED, X_CONTENT_TYPE_OPTIONS,
};
use reqwest::{Client, StatusCode};
use tokio::sync::watch::{channel, Receiver};
use tokio::sync::Notify;
use crate::cache::{Cache, CacheKey, ImageMetadata};