1use std::path::PathBuf;
2use std::sync::{RwLock};
3use json::{JsonValue, object};
4use serde::{Deserialize, Serialize};
5use crate::aliyun::Aliyun;
6pub use crate::config::Config;
7use crate::tencent::Tencent;
8use once_cell::sync::Lazy;
9static GLOBAL_CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| {
10 RwLock::new(Config::default())
11});
12
13mod aliyun;
14mod tencent;
15mod config;
16
17#[derive(Clone)]
18pub enum Oss {
19 Aliyun(Aliyun),
20 Tencent(Tencent),
21 None,
22}
23impl Oss {
24 pub fn new(config: Config) -> Result<Self, String> {
26 {
27 let mut data = GLOBAL_CONFIG.write().unwrap();
28 data.clone_from(&config);
29 }
30 let config = GLOBAL_CONFIG.read().unwrap();
31 let connection = config.connections.get(config.default.as_str()).unwrap().clone();
32 match connection.channel {
33 Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
34 Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
35 Channel::None => Ok(Oss::None),
36 }
37 }
38 pub fn create(name: &str, connection: Connection) -> Result<Self, String> {
40 {
41 let mut data = GLOBAL_CONFIG.write().unwrap();
42 if !data.connections.contains_key(name) {
43 data.connections.insert(name.to_string(), connection);
44 }
45 data.default = name.to_string();
46 }
47 let config = GLOBAL_CONFIG.read().unwrap();
48 let connection = config.connections.get(config.default.as_str()).unwrap().clone();
49 match connection.channel {
50 Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
51 Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
52 Channel::None => Err("mode not supported!".to_string()),
53 }
54 }
55
56 pub fn connections(&mut self) -> JsonValue {
57 let mut connections = vec![];
58 let data = GLOBAL_CONFIG.read().unwrap();
59 for (item, mut value) in data.connections.clone() {
60 if value.channel.str().is_empty() {
61 continue;
62 }
63 let mut t = value.json();
64 t["name"] = item.into();
65 connections.push(t);
66 }
67 connections.into()
68 }
69}
70impl OssMode for Oss {
71 fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String> {
74 let path = dirname_handle(dirname);
75 match self {
76 Oss::Aliyun(e) => e.upload(path.as_str(), file, content_type),
77 Oss::Tencent(e) => e.upload(path.as_str(), file, content_type),
78 Oss::None => Err("upload 错误".to_string())
79 }
80 }
81 fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String> {
82 let path = dirname_handle(dirname);
83 match self {
84 Oss::Aliyun(e) => e.download(path.as_str(), key),
85 Oss::Tencent(e) => e.download(path.as_str(), key),
86 Oss::None => Err("download 错误".to_string())
87 }
88 }
89
90 fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String> {
91 let path = dirname_handle(dirname);
92 match self {
93 Oss::Aliyun(e) => e.query(path.as_str(), key),
94 Oss::Tencent(e) => e.query(path.as_str(), key),
95 Oss::None => Err("query 错误".to_string())
96 }
97 }
98
99 fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String> {
101 let path = dirname_handle(dirname);
102 match self {
103 Oss::Aliyun(e) => e.del(path.as_str(), key),
104 Oss::Tencent(e) => e.del(path.as_str(), key),
105 Oss::None => Err("del 错误".to_string())
106 }
107 }
108}
109fn dirname_handle(dirname: &str) -> String {
110 if dirname.is_empty() {
111 "/".to_string()
112 } else {
113 let tt = dirname.trim_start_matches("/").trim_end_matches("/").to_string();
114 format!("/{tt}/")
115 }
116}
117#[derive(Clone, Debug, Serialize, Deserialize)]
118pub struct Connection {
119 pub channel: Channel,
120 pub endpoint: String,
123 pub access_key_id: String,
124 pub access_key_secret: String,
125 pub bucket_name: String,
126}
127
128impl Default for Connection {
129 fn default() -> Self {
130 Self {
131 channel: Channel::None,
132 endpoint: "".to_string(),
133 access_key_id: "".to_string(),
134 access_key_secret: "".to_string(),
135 bucket_name: "".to_string(),
136 }
137 }
138}
139
140impl Connection {
141 pub fn json(&mut self) -> JsonValue {
142 let mut data = object! {};
143 data["channel"] = self.channel.str().into();
144 data["endpoint"] = self.endpoint.clone().into();
145 data["access_key_id"] = self.access_key_id.clone().into();
146 data["access_key_secret"] = self.access_key_secret.clone().into();
147 data["bucket_name"] = self.bucket_name.clone().into();
148 data
149 }
150 pub fn from(data: JsonValue) -> Connection {
151 Self {
152 channel: Channel::from(data["channel"].as_str().unwrap_or("")),
153 endpoint: data["endpoint"].to_string(),
154 access_key_id: data["access_key_id"].to_string(),
155 access_key_secret: data["access_key_secret"].to_string(),
156 bucket_name: data["bucket_name"].to_string(),
157 }
158 }
159}
160
161
162#[derive(Clone, Debug, Serialize, Deserialize)]
163pub enum Channel {
164 Aliyun,
165 Tencent,
166 None,
167}
168
169impl Channel {
170 pub fn str(&mut self) -> &'static str {
171 match self {
172 Channel::Aliyun => "aliyun",
173 Channel::Tencent => "tencent",
174 Channel::None => "",
175 }
176 }
177 pub fn from(name: &str) -> Self {
178 match name {
179 "aliyun" => Channel::Aliyun,
180 "tencent" => Channel::Tencent,
181 _ => Channel::None
182 }
183 }
184}
185
186
187pub trait OssMode {
188 fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String>;
198 fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String>;
203 fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String>;
208 fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String>;
210}