use std::path::PathBuf;
use std::sync::{RwLock};
use json::{JsonValue, object};
use serde::{Deserialize, Serialize};
use crate::aliyun::Aliyun;
pub use crate::config::Config;
use crate::tencent::Tencent;
use once_cell::sync::Lazy;
static GLOBAL_CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| {
RwLock::new(Config::default())
});
mod aliyun;
mod tencent;
mod config;
#[derive(Clone)]
pub enum Oss {
Aliyun(Aliyun),
Tencent(Tencent),
None,
}
impl Oss {
pub fn new(config: Config) -> Result<Self, String> {
{
let mut data = GLOBAL_CONFIG.write().unwrap();
data.clone_from(&config);
}
let config = GLOBAL_CONFIG.read().unwrap();
let connection = config.connections.get(config.default.as_str()).unwrap().clone();
match connection.channel {
Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
Channel::None => Ok(Oss::None),
}
}
pub fn create(name: &str, connection: Connection) -> Result<Self, String> {
{
let mut data = GLOBAL_CONFIG.write().unwrap();
if !data.connections.contains_key(name) {
data.connections.insert(name.to_string(), connection);
}
data.default = name.to_string();
}
let config = GLOBAL_CONFIG.read().unwrap();
let connection = config.connections.get(config.default.as_str()).unwrap().clone();
match connection.channel {
Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
Channel::None => Err("mode not supported!".to_string()),
}
}
pub fn connections(&mut self) -> JsonValue {
let mut connections = vec![];
let data = GLOBAL_CONFIG.read().unwrap();
for (item, mut value) in data.connections.clone() {
if value.channel.str().is_empty() {
continue;
}
let mut t = value.json();
t["name"] = item.into();
connections.push(t);
}
connections.into()
}
}
impl OssMode for Oss {
fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String> {
let path = dirname_handle(dirname);
match self {
Oss::Aliyun(e) => e.upload(path.as_str(), file, content_type),
Oss::Tencent(e) => e.upload(path.as_str(), file, content_type),
Oss::None => Err("upload 错误".to_string())
}
}
fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String> {
let path = dirname_handle(dirname);
match self {
Oss::Aliyun(e) => e.download(path.as_str(), key),
Oss::Tencent(e) => e.download(path.as_str(), key),
Oss::None => Err("download 错误".to_string())
}
}
fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String> {
let path = dirname_handle(dirname);
match self {
Oss::Aliyun(e) => e.query(path.as_str(), key),
Oss::Tencent(e) => e.query(path.as_str(), key),
Oss::None => Err("query 错误".to_string())
}
}
fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String> {
let path = dirname_handle(dirname);
match self {
Oss::Aliyun(e) => e.del(path.as_str(), key),
Oss::Tencent(e) => e.del(path.as_str(), key),
Oss::None => Err("del 错误".to_string())
}
}
}
fn dirname_handle(dirname: &str) -> String {
if dirname.is_empty() {
"/".to_string()
} else {
let tt = dirname.trim_start_matches("/").trim_end_matches("/").to_string();
format!("/{tt}/")
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Connection {
pub channel: Channel,
pub endpoint: String,
pub access_key_id: String,
pub access_key_secret: String,
pub bucket_name: String,
}
impl Default for Connection {
fn default() -> Self {
Self {
channel: Channel::None,
endpoint: "".to_string(),
access_key_id: "".to_string(),
access_key_secret: "".to_string(),
bucket_name: "".to_string(),
}
}
}
impl Connection {
pub fn json(&mut self) -> JsonValue {
let mut data = object! {};
data["channel"] = self.channel.str().into();
data["endpoint"] = self.endpoint.clone().into();
data["access_key_id"] = self.access_key_id.clone().into();
data["access_key_secret"] = self.access_key_secret.clone().into();
data["bucket_name"] = self.bucket_name.clone().into();
data
}
pub fn from(data: JsonValue) -> Connection {
Self {
channel: Channel::from(data["channel"].as_str().unwrap_or("")),
endpoint: data["endpoint"].to_string(),
access_key_id: data["access_key_id"].to_string(),
access_key_secret: data["access_key_secret"].to_string(),
bucket_name: data["bucket_name"].to_string(),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Channel {
Aliyun,
Tencent,
None,
}
impl Channel {
pub fn str(&mut self) -> &'static str {
match self {
Channel::Aliyun => "aliyun",
Channel::Tencent => "tencent",
Channel::None => "",
}
}
pub fn from(name: &str) -> Self {
match name {
"aliyun" => Channel::Aliyun,
"tencent" => Channel::Tencent,
_ => Channel::None
}
}
}
pub trait OssMode {
fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String>;
fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String>;
fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String>;
fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String>;
}