feat: osssendfile-rs

This commit is contained in:
2024-08-24 22:22:29 +08:00
parent cda5e9197d
commit 160f34456c
3 changed files with 143 additions and 519 deletions

104
osssendfile-rs/src/main.rs Normal file → Executable file
View File

@@ -1,11 +1,31 @@
#!/usr/bin/env runrs
//! ```cargo
//! [dependencies]
//! aes-gcm-stream = "0.2"
//! base64 = "0.22.1"
//! clap = { version = "4.5", features = ["derive"] }
//! oss = "0.3.2"
//! rand = "0.8.5"
//! reqwest = "0.12"
//! rust_util = "0.6.47"
//! serde = { version = "1.0", features = ["derive"] }
//! serde_json = "1.0"
//! sha2 = "0.10.8"
//! tokio = { version = "1.39", features = ["full"] }
//! ```
use aes_gcm_stream::Aes128GcmStreamEncryptor;
use base64::engine::general_purpose::STANDARD;
use base64::Engine;
use clap::Parser;
use oss::OSSClient;
use reqwest::{Client, Response};
use rust_util::util_io::DEFAULT_BUF_SIZE;
use rust_util::util_time::get_current_secs;
use rust_util::{debugging, iff, information, opt_result, opt_value_result, simple_error, success, util_file, util_time, warning, XResult};
use rust_util::{
failure, information, opt_result, opt_value_result, simple_error, success,
util_file, util_size, util_time, warning, XResult,
};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sha2::Digest;
@@ -13,9 +33,8 @@ use sha2::Sha256;
use std::collections::HashMap;
use std::fs;
use std::fs::File;
use std::io::{BufReader, ErrorKind, Read, Write};
use std::path::{Path, PathBuf};
use xt_oss::oss;
use std::io::{ErrorKind, Read, Write};
use std::path::PathBuf;
const OSS_SEND_FILE_CONFIG_FILE: &str = "~/.jssp/config/osssendfile.json";
const CREATE_STS_URL: &str = "https://hatter.ink/oidc/create_sts.json";
@@ -80,9 +99,9 @@ async fn main() -> XResult<()> {
let client = Client::new();
let oss_send_file_config = load_config(&args.config)?;
information!("Get STS from hatter ink");
let sts = request_sts(&client, &oss_send_file_config).await?;
println!("{:#?}", sts);
information!("Get STS success");
let source_file = args.file.clone();
let filename = source_file.file_name().unwrap().to_str().unwrap();
@@ -94,44 +113,62 @@ async fn main() -> XResult<()> {
}
};
if let Ok(metadata) = source_file.metadata() {
let file_len = metadata.len();
let file_len_display = util_size::get_display_size(file_len as i64);
if file_len < 1024 * 1024 {
information!("File length: {}", file_len_display);
} else if file_len < 10 * 1024 * 1024 {
warning!("File is large, length: {}", file_len_display);
} else {
failure!("File is very large, length: {}", file_len_display);
}
}
information!("Encrypt file {:?} -> {:?}", source_file, temp_file);
let temp_key = encrypt(&source_file, &temp_file)?;
debugging!("Encryption temp key: {:?}", &temp_key);
information!("Encrypt file: {:?} success", &temp_file);
let options = oss::Options::new()
.with_access_key_id(&sts.access_key_id)
.with_access_key_secret(&sts.access_key_secret)
.with_sts_token(&sts.security_token)
.with_bucket(&oss_send_file_config.bucket)
.with_region("oss-cn-shanghai");
let client = oss::Client::new(options);
let oss_client = OSSClient::new_sts(&oss_send_file_config.endpoint,
&sts.access_key_id,
&sts.access_key_secret,
&sts.security_token);
let temp_oss_filename = format!("tempfiles/temp_transfer_{}.{}", util_time::get_current_millis(), filename_ext);
information!("Put object {:?} -> {}", &temp_file, &temp_oss_filename);
let put_object_data = opt_result!(opt_result!(
client.PutObject(&temp_oss_filename).execute().await,
"Put object failed: {}"), "Put object failed-2: {:?}");
if !put_object_data.status().is_success() {
return simple_error!("Put object failed, status: {}", put_object_data.status().as_u16());
let temp_file_read = opt_result!(File::open(&temp_file), "Read temp file failed: {}");
let put_object_response = oss_client.put_file(
&oss_send_file_config.bucket, &temp_oss_filename, 600, temp_file_read).await?;
if !put_object_response.status().is_success() {
return simple_error!("Put object failed, status: {}", put_object_response.status().as_u16());
}
information!("Put object success");
let object_url = client.object_url(&temp_oss_filename);
println!(">> {}", object_url);
let object_url = oss_client.generate_signed_get_url(&oss_send_file_config.bucket, &temp_oss_filename, 600);
information!("Send URL to play security: {}", object_url);
send_file(&client,
&oss_send_file_config.token,
&object_url,
&args.filename.clone().unwrap_or_else(|| get_filename(filename)),
args.keywords.as_deref().unwrap_or(""),
temp_key).await?;
information!("Send URL success");
let delete_object_data = opt_result!(opt_result!(
client.DeleteObject(&temp_oss_filename).execute().await,
"Delete object failed: {}"), "Delete object failed-2: {:?}");;
if !delete_object_data.status().is_success() {
return simple_error!("Delete object failed, status: {}", delete_object_data.status().as_u16());
information!("Delete object: {}", &temp_oss_filename);
let delete_object_response = oss_client.delete_file(
&oss_send_file_config.bucket, &temp_oss_filename).await?;
if !delete_object_response.status().is_success() {
return simple_error!("Delete object failed, status: {}", delete_object_response.status().as_u16());
}
information!("Delete object success");
match fs::remove_file(&temp_file) {
Ok(_) => information!("Delete temp file: {:?}", &temp_file),
Err(e) => warning!("Delete temp file failed: {}", e),
}
success!("File {} upload success", filename);
Ok(())
}
@@ -149,10 +186,19 @@ fn load_config(config: &Option<String>) -> XResult<OssSendFileConfig> {
}
fn get_filename_ext(filename: &str) -> String {
let mut split_filename_parts: Vec<&str> = filename.split(".").collect();
let split_filename_parts: Vec<&str> = filename.split(".").collect();
split_filename_parts[split_filename_parts.len() - 1].to_string()
}
fn get_filename(filename: &str) -> String {
if filename.contains('/') {
let filename_parts = filename.split("/").collect::<Vec<&str>>();
filename_parts[filename_parts.len() - 1].to_string()
} else {
filename.to_string()
}
}
fn new_aes_key_and_nonce() -> ([u8; 16], Vec<u8>) {
let temp_key: [u8; 16] = rand::random();
let mut sha256 = Sha256::new();