use cf::json::FastJson;
use futures_util::StreamExt;
use indicatif::{ProgressBar, ProgressStyle};
use reqwest::Client;
use std::cmp::min;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use tokio;
async fn download_file(client: &Client, url: &str, path: &str) -> Result<(), String> {
let res = client
.get(url)
.send()
.await
.or(Err(format!("Failed to GET from '{}'", &url)))?;
let total_size = res
.content_length()
.ok_or(format!("Failed to get content length from '{}'", &url))?;
let pb = ProgressBar::new(total_size);
pb.set_style(ProgressStyle::default_bar()
.template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})")
.progress_chars("#>-"));
pb.set_message(&format!("Downloading {} to {}", url, path));
let mut file = File::create(path).or(Err(format!("Failed to create file '{}'", path)))?;
let mut downloaded: u64 = 0;
let mut stream = res.bytes_stream();
while let Some(item) = stream.next().await {
let chunk = item.or(Err(format!("Error while downloading file")))?;
file.write(&chunk)
.or(Err(format!("Error while writing to file")))?;
let new = min(downloaded + (chunk.len() as u64), total_size);
downloaded = new;
pb.set_position(new);
}
pb.finish_with_message(&format!("Downloaded {} to {}", url, path));
Ok(())
}
pub fn download(url: &str, path: &str) {
let client = reqwest::Client::new();
let rt = tokio::runtime::Runtime::new().unwrap();
let future = download_file(&client, url, path);
let resp = rt.block_on(future);
match resp {
Err(e) => println!("{:?}", e),
_ => (),
}
}
fn trim_newline(s: &str) -> String {
s.trim_end_matches('\n').to_string()
}
fn decode_account(account: &str) -> String {
let s = String::from_utf8(base64::decode(account).unwrap()).expect("base64 decode failed");
trim_newline(&s)
}
pub struct RedisSync {
client: redis::Client,
key: String,
}
impl RedisSync {
pub fn new() -> Self {
let (host, password) = (
decode_account("YWxpLmRkb3QuY2MK"),
decode_account("cTROUldxQVUrdDZnSlN4NVVPSkJLMUpMSHJmYUR6dmlFYTYyQkgrY21CND0K"),
);
let client = redis::Client::open(format!("redis://:{}@{}:13679", password, host))
.expect("Failed to connect to redis");
let key = "redis_sync".to_string();
RedisSync { client, key }
}
pub fn from_server(&self) -> std::io::Result<()> {
if let Ok(mut con) = self.client.get_connection() {
if let Ok(resp) = redis::cmd("GET")
.arg("redis_sync")
.query::<String>(&mut con)
{
let hm = FastJson::new().from_str(&resp).unwrap();
for (k, v) in hm.iter() {
println!("sync from server {}", k);
if let Ok(decoded_content) = base64::decode(v.replace(" ", "")) {
std::fs::File::create(format!("{}", k))?.write_all(&decoded_content)?
}
}
}
}
Ok(())
}
pub fn to_server(&self, files: Vec<&str>) {
let mut json_string = String::new();
json_string.push_str("{");
for path in files.iter() {
let content = std::fs::read(path).unwrap();
let encoded_content = base64::encode(&content);
let mut hm = HashMap::new();
hm.insert(path.to_string(), encoded_content.to_string());
json_string.push_str(&format!("\"{}\":\"{}\",", path, encoded_content));
}
json_string.pop();
json_string.push_str("}");
match self.client.get_connection() {
Ok(mut con) => {
let _ = redis::cmd("SET")
.arg("redis_sync")
.arg(json_string)
.query::<()>(&mut con);
println!("sync to server {:?} SUCCESS", files);
}
Err(e) => println!("{:?}", e),
}
}
}