Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

初版 #1

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[env]
SYSTEM_DEPS_BUILD_INTERNAL="always"
[build]
rustflags=["-C link-args=-Wl,-lc"]
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
/target
/minio
/dev_env
/valkey
/config.json
/Cargo.lock
41 changes: 41 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[package]
name = "upload_service"
version = "0.1.0"
edition = "2021"

[dependencies]
tokio-stream = "*"
axum = { version = "0.7", features = ["http2","multipart"] }
tokio = { version = "1.0", features = ["rt-multi-thread","signal","process"] }
tokio-util = { version = "0.7.8", features = ["io"] }
futures = "0.3"
futures-util = { version = "0.3", default-features = false, features = ["sink", "std"] }
headers = "^0.3.8"
serde = {version="^1.0.164",features=["derive"]}
serde_json ="1"
image = {git="https://github.com/kozakura913/image.git",branch="main"}
webp = { version = "0.3.0", default-features = false }
resvg = {version="0.41",features = [ "text","memmap-fonts","raster-images" ] }
rexif = "0.7"
avif-decoder_dep = { path="./avif-decoder_dep" ,optional = true }
chrono = "0.4"
fast_image_resize = "3.0"
rust-s3 = { git = "https://github.com/kozakura913/rust-s3" ,branch="with_metadata", default-features = false, features = ["tokio-rustls-tls", "fail-on-err"] }
uuid = { version = "1.10", features = ["v4"] }
redis = { version = "0.26", features = ["tokio-comp"] }
sha2 = "0.10"
base64 = "0.22.1"
md5 = "0.7.0"
nsfw = { version = "0.2.0", default-features = false }
reqwest = { version = "0.12", default-features = false , features = ["rustls-tls", "charset"] }
blurhash = "0.2.3"
infer = { version = "0.16", default-features = false }
percent-encoding = "2.3.1"
ndarray = "0.15.6"
tract-data = "0.21.6"

[profile.dev]
opt-level = 1

[profile.dev.package."*"]
opt-level = 3
12 changes: 12 additions & 0 deletions avif-decoder_dep/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name="avif-decoder_dep"
version = "0.1.0"
edition = "2021"

[dependencies]
image = { version = "*" , features = ["avif-native"] }

[target.'cfg(any(target_arch = "x86",target_arch = "x86_64"))'.dependencies.image]
version = "*"
default-features = false
features = ["nasm"]
Empty file added avif-decoder_dep/src/lib.rs
Empty file.
18 changes: 18 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: "3"
services:
valkey:
image: valkey/valkey:alpine
restart: always
volumes:
- ./valkey:/data
networks:
- external_network
ports:
- "6379:6379"
healthcheck:
test: "valkey-cli ping"
interval: 5s
retries: 20
networks:
external_network:

20 changes: 20 additions & 0 deletions src/abort.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use axum::{http::StatusCode, response::IntoResponse};

use crate::Context;

pub async fn post(
mut ctx:Context,
request: axum::extract::Request,
)->axum::response::Response{
let authorization=request.headers().get("Authorization");
let (session,_hashed_sid)=match ctx.upload_session(authorization,true).await{
Ok(v)=>v,
Err(e)=>return e,
};
if let Some(upload_id)=session.upload_id.as_ref(){
let _=ctx.bucket.abort_upload(&session.s3_key,upload_id).await;
}
let mut header=axum::http::header::HeaderMap::new();
ctx.config.set_cors_header(&mut header);
(StatusCode::NO_CONTENT,header).into_response()
}
136 changes: 136 additions & 0 deletions src/backend.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
use core::str;
use std::sync::Arc;

use serde::{Deserialize, Serialize};

use crate::ConfigFile;

#[derive(Clone,Debug)]
pub struct BackendService{
client:reqwest::Client,
config:Arc<ConfigFile>,
}
impl BackendService{
pub fn new(config:Arc<ConfigFile>)->Self{
Self{
client:reqwest::Client::new(),
config,
}
}
pub async fn preflight(&self,req:&mut PreflightRequest)->Result<PreflightResponse,String>{
req.upload_service_key=Some(self.config.backend.key.clone());
let post=self.client.post(format!("{}/drive/files/upload-preflight",self.config.backend.endpoint));
let post=post.header(reqwest::header::CONTENT_TYPE,"application/json");
let post=post.body(serde_json::to_string(&req).unwrap());
let res=match post.send().await{
Ok(v)=>v,
Err(e)=>{
eprintln!("preflight send error {:?}",e);
return Err("{}".to_owned());
}
};
let res=res.bytes().await.map_err(|e|{
format!("{{\"error\":{{\"message\":\"{}\"}} }}",e.to_string())
})?;
let res=match serde_json::from_slice(&res){
Ok(v)=>Ok(v),
Err(e)=>{
eprintln!("preflight parse error {:?}\n{:?}",e,str::from_utf8(&res));
Err(str::from_utf8(&res).map_err(|_e|"{}".to_owned())?.to_owned())
}
};
res
}
pub async fn register(&self,req:&mut RegisterRequest)->Result<(u16,String),String>{
req.upload_service_key=Some(self.config.backend.key.clone());
let post=self.client.post(format!("{}/drive/files/upload-service",self.config.backend.endpoint));
let post=post.header(reqwest::header::CONTENT_TYPE,"application/json");
let post=post.body(serde_json::to_string(&req).unwrap());
let res=match post.send().await{
Ok(v)=>v,
Err(e)=>{
eprintln!("register send error {:?}",e);
return Err("{}".to_owned());
}
};
let status=res.status().as_u16();
let res=res.bytes().await.map_err(|e|{
format!("{{\"error\":{{\"message\":\"{}\"}} }}",e.to_string())
})?;
let res=match String::from_utf8(res.into()){
Ok(v)=>Ok((status,v)),
Err(e)=>{
eprintln!("register parse error {:?}",e);
Err(format!("register parse error {:?}",e))
}
};
res
}
}
#[derive(Default,Clone,Debug,Serialize,Deserialize)]
pub struct PreflightRequest{
pub upload_service_key:Option<String>,
#[serde(rename = "folderId")]
pub folder_id:Option<String>,
pub name:Option<String>,
#[serde(rename = "isSensitive")]
pub is_sensitive:bool,
pub comment:Option<String>,
pub size:u64,
pub ext:Option<String>,
#[serde(rename = "isLink")]
pub is_link:bool,
pub url:Option<String>,
pub uri:Option<String>,
pub i:Option<String>,
pub user_id:Option<String>,
}
#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct RegisterRequest{
pub upload_service_key:Option<String>,
//https://s3.example.com/prefix/
#[serde(rename = "baseUrl")]
pub base_url:String,
//c4f38298-2e66-43e9-8e29-7dfa29db8754.webp
#[serde(rename = "accessKey")]
pub access_key:String,
//thumbnail-ae8b311e-f834-4eff-8605-6e5a7165f1c0.webp
//サムネイルを生成できないファイルの場合None
#[serde(rename = "thumbnailKey")]
pub thumbnail_key:Option<String>,
pub md5:String,
pub blurhash:Option<String>,
pub size:u64,
pub width:u32,
pub height:u32,
#[serde(rename = "sourceUrl")]
pub source_url:Option<String>,
#[serde(rename = "remoteUri")]
pub remote_uri:Option<String>,
#[serde(rename = "isLink")]
pub is_link:bool,
#[serde(rename = "folderId")]
pub folder_id:Option<String>,
pub name:String,
pub comment:Option<String>,
#[serde(rename = "isSensitive")]
pub is_sensitive:bool,
#[serde(rename = "maybeSensitive")]
pub maybe_sensitive:bool,
#[serde(rename = "contentType")]
pub content_type:String,
pub force:bool,
pub i:Option<String>,
pub user_id:Option<String>,
}
#[derive(Clone,Debug,Serialize,Deserialize)]
pub struct PreflightResponse{
#[serde(rename = "skipSensitiveDetection")]
pub skip_sensitive_detection: bool,
#[serde(rename = "sensitiveThreshold")]
pub sensitive_threshold: f32,
#[serde(rename = "enableSensitiveMediaDetectionForVideos")]
pub enable_sensitive_media_detection_for_videos: bool,
#[serde(rename = "detectedName")]
pub detected_name: String,
}
42 changes: 42 additions & 0 deletions src/browsersafe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
pub const FILE_TYPE_BROWSERSAFE: [&str; 29] = [
// Images
"image/png",
"image/gif",
"image/jpeg",
"image/webp",
"image/avif",
"image/apng",
"image/bmp",
"image/tiff",
"image/x-icon",

// OggS
"audio/opus",
"video/ogg",
"audio/ogg",
"application/ogg",

// ISO/IEC base media file format
"video/quicktime",
"video/mp4",
"audio/mp4",
"video/x-m4v",
"audio/x-m4a",
"video/3gpp",
"video/3gpp2",

"video/mpeg",
"audio/mpeg",

"video/webm",
"audio/webm",

"audio/aac",

// see https://github.com/misskey-dev/misskey/pull/10686
"audio/flac",
"audio/wav",
// backward compatibility
"audio/x-flac",
"audio/vnd.wave",
];
Loading