lsys_lib_sms/sms_lib/
mod.rs1use base64::{
2 alphabet,
3 engine::{self, general_purpose},
4};
5use rand::seq::SliceRandom;
6use reqwest::Response;
7use reqwest::StatusCode;
8
9use std::{
10 collections::HashMap,
11 time::{SystemTime, SystemTimeError},
12};
13use tracing::debug;
14const CUSTOM_ENGINE: engine::GeneralPurpose =
15 engine::GeneralPurpose::new(&alphabet::URL_SAFE, general_purpose::PAD);
16
17#[derive(Debug)]
18pub enum SendError {
19 Next(String),
20 Finish(String),
21}
22
23#[derive(Debug, Clone)]
24pub enum SendStatus {
25 Progress, Completed, Failed(bool), }
29
30#[derive(Debug)]
31pub struct SendResultItem {
32 pub mobile: String,
33 pub status: SendStatus,
34 pub message: String,
35 pub send_id: String,
36}
37
38pub type BranchSendResult = Result<Vec<SendResultItem>, SendError>;
39
40#[derive(Debug)]
41pub struct SendDetailItem {
42 pub send_id: String,
43 pub status: SendNotifyStatus,
44 pub message: String,
45 pub code: String,
46 pub receive_time: Option<u64>,
47 pub send_time: Option<u64>,
48 pub mobile: Option<String>,
49}
50
51pub type BranchSendDetailResult = Result<Vec<SendDetailItem>, String>;
52
53#[derive(Debug, Clone)]
54pub enum SendNotifyStatus {
55 Progress, Completed, Failed, }
59
60#[derive(Debug)]
61pub enum SendNotifyError {
62 Msg(String),
63 Sign(String),
64 Ignore,
65}
66
67#[derive(Debug, Clone)]
68pub struct SendNotifyItem {
69 pub status: SendNotifyStatus,
70 pub message: String,
71 pub code: String,
72 pub receive_time: Option<u64>,
73 pub send_time: Option<u64>,
74 pub send_id: String,
75 pub mobile: Option<String>,
76}
77
78pub type BranchSendNotifyResult = Result<Vec<SendNotifyItem>, SendNotifyError>;
79
80pub(crate) fn rand_str(len: usize) -> String {
81 let base_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
82 let mut rng = &mut rand::thread_rng();
83 String::from_utf8(
84 base_str
85 .as_bytes()
86 .choose_multiple(&mut rng, len)
87 .cloned()
88 .collect(),
89 )
90 .unwrap_or_default()
91}
92
93pub(crate) fn now_time() -> Result<u64, SystemTimeError> {
94 Ok(SystemTime::now()
95 .duration_since(SystemTime::UNIX_EPOCH)?
96 .as_secs())
97}
98
99pub(crate) fn phone_numbers_check<'t>(
100 phone_numbers: &'t [&'t str],
101) -> Result<Vec<&'t str>, SendError> {
102 let out = phone_numbers
103 .iter()
104 .map(|e| e.trim())
105 .filter(|e| !e.is_empty())
106 .collect::<Vec<_>>();
107 if out.is_empty() {
108 return Err(SendError::Finish("not find any mobile".to_string()));
109 }
110 Ok(out)
111}
112
113pub(crate) async fn response_check(
114 result: Response,
115 is_json: bool,
116) -> Result<(StatusCode, String), String> {
117 let status = result.status();
118 let data = result
119 .bytes()
120 .await
121 .map_err(|e| format!("request read body fail:{}", e))?;
122 let res = unsafe { String::from_utf8_unchecked(data.to_vec()) };
123 debug!("sms response succ: {}", &res);
125 if is_json && !gjson::valid(&res) {
126 return Err(format!("body not json :{}", res));
127 }
128 Ok((status, res))
129}
130
131pub(crate) fn response_msg(result: &str, paths: &[&str]) -> String {
132 for path in paths {
133 let msg = gjson::get(result, path).to_string();
134 if !msg.is_empty() {
135 return format!("api fail,msg:{}", msg);
136 }
137 }
138 format!("api fail,data:{}", result)
139}
140
141pub fn template_map_to_arr(template_var: &str, template_map: &str) -> Option<Vec<String>> {
142 if let Ok(tmp) = serde_json::from_str::<HashMap<String, String>>(template_var) {
143 let map_data = template_map.split(',');
144 let mut set_data = vec![];
145 if !tmp.is_empty() {
146 for sp in map_data {
147 if let Some(tv) = tmp.get(sp) {
148 set_data.push(tv.to_owned())
149 }
150 }
151 }
152 if !set_data.is_empty() {
153 return Some(set_data);
154 }
155 }
156 None
157}
158#[cfg(feature = "aliyun")]
159mod sender_aliyun;
160#[cfg(feature = "aliyun")]
161pub use sender_aliyun::*;
162#[cfg(feature = "huawei")]
163mod sender_huawei;
164#[cfg(feature = "huawei")]
165pub use sender_huawei::*;
166
167#[cfg(feature = "tencent")]
168mod sender_tencent;
169#[cfg(feature = "tencent")]
170pub use sender_tencent::*;
171
172#[cfg(feature = "jdcloud")]
173mod sender_jdcloud;
174#[cfg(feature = "jdcloud")]
175pub use sender_jdcloud::*;
176
177#[cfg(feature = "netease")]
178mod sender_netease;
179#[cfg(feature = "netease")]
180pub use sender_netease::*;
181
182#[cfg(feature = "cloopen")]
183mod sender_cloopen;
184#[cfg(feature = "cloopen")]
185pub use sender_cloopen::*;