use super::ApiError;
use super::FileInfo;
use super::FileInfoIter;
use super::YunApi;
use std::path::PathBuf;
pub fn human_quota(in_quta: i64) -> (f64, f64, f64) {
let tmp_quota = in_quta as f64;
let k = 1024_f64;
let m = (1024 * 1024) as f64;
let g = (1024 * 1024 * 1024) as f64;
(tmp_quota / k, tmp_quota / m, tmp_quota / g)
}
pub fn get_vip_type_str(vip_type: i64) -> Result<String, ApiError> {
match vip_type {
0 => Ok(String::from("普通用户")),
1 => Ok(String::from("普通会员")),
2 => Ok(String::from("超级会员")),
_ => Err(ApiError::from("Not Support vip_type.")),
}
}
pub struct YunFs<'a> {
api: &'a YunApi,
current_path: PathBuf,
}
impl<'a> YunFs<'a> {
pub fn new(api_ref: &'a YunApi) -> YunFs<'a> {
YunFs {
api: api_ref,
current_path: PathBuf::from("/"), }
}
pub fn pwd(&self) -> Result<String, ApiError> {
let path_string: String = self.current_path.to_str().unwrap().into();
if self.api.get_files_list(&path_string, 0, 0).is_ok() {
Ok(path_string.clone())
} else {
Err(ApiError::from(
"Error when pwd():the directory may not exist.",
))
}
}
fn check_dir_fmt(dir_str: &str) -> Result<(), ApiError> {
let states = (0, 1, 2, 3, 4); let mut c_state = states.0;
for item in dir_str.chars() {
if item == '.' {
if c_state == states.0 {
c_state = states.1;
continue;
} else if c_state == states.1 {
c_state = states.2;
continue;
} else {
return Err(ApiError::from(
"path resolve Error: `.` not the correct position.",
));
}
}
if item == '/' {
if c_state != states.3 {
c_state = states.3;
continue;
} else {
return Err(ApiError::from(
"path resolve Error: `/` not the correct position.",
));
}
} else {
if item == '\\' {
return Err(ApiError::from(
"path resolve Error: `\\` not the accepted char.",
));
}
if c_state == states.1 || c_state == states.2 {
return Err(ApiError::from("`.` or `..`can not be here."));
}
c_state = states.4;
continue;
}
}
Ok(())
}
fn resolve_path(&self, dir_str: &str) -> Result<String, ApiError> {
match Self::check_dir_fmt(dir_str) {
Ok(_) => {}
Err(error) => {
return Err(error);
}
}
let mut tmp_dir = String::from(dir_str);
if dir_str == "." || dir_str == "./" {
return Ok(self.current_path.to_str().unwrap().into());
}
if dir_str == ".." || dir_str == "../" {
if self.current_path.to_str().unwrap() == "/" {
return Ok("/".into());
} else {
let mut tmp_path = PathBuf::from(&self.current_path);
tmp_path.pop();
return Ok(tmp_path.to_str().unwrap().into());
}
}
if tmp_dir.len() != 1 && tmp_dir.ends_with("/") {
tmp_dir.pop();
}
if tmp_dir.starts_with("../") {
tmp_dir.remove(0);
tmp_dir.remove(0);
tmp_dir.remove(0);
if self.current_path.to_str().unwrap() == "/" {
let ret_string = format!("/{}", tmp_dir);
return Ok(ret_string);
} else {
let mut tmp_path = PathBuf::from(&self.current_path);
tmp_path.pop();
return Ok(format!("{}/{}", tmp_path.to_str().unwrap(), tmp_dir));
}
}
if tmp_dir.starts_with("/") {
return Ok(tmp_dir);
}
if tmp_dir.starts_with("./") {
tmp_dir.remove(0);
tmp_dir.remove(0);
}
if self.current_path.to_str().unwrap() == "/" {
return Ok(format!("/{}", tmp_dir));
}
let ret_string = format!("{}/{}", self.current_path.to_str().unwrap(), tmp_dir);
Ok(ret_string)
}
pub fn chdir(&mut self, dir_str: &str) -> Result<(), ApiError> {
let resolved_result = self.resolve_path(dir_str);
let dir_resolved = resolved_result?;
if self.api.get_files_list(&dir_resolved, 0, 0).is_ok() {
self.current_path = PathBuf::from(dir_resolved);
Ok(())
} else {
Err(ApiError::from("Error:chdir():the directory may not exist."))
}
}
pub fn ls(&self) -> Result<FileInfoIter, ApiError> {
let list_len = 1000;
let mut ret_vec: Vec<FileInfo> = Vec::new();
loop {
let tmp_list =
match self
.api
.get_files_list(self.current_path.to_str().unwrap(), 0, list_len)
{
Ok(list) => list,
Err(error) => {
return Err(error);
}
};
let mut tmp_vec: Vec<FileInfo> = tmp_list.collect();
let len = tmp_vec.len();
ret_vec.append(&mut tmp_vec);
if len < 1000 {
break;
}
}
Ok(FileInfoIter::new(ret_vec))
}
}
use reqwest::blocking::Client;
use reqwest::header::CONTENT_LENGTH;
use reqwest::header::RANGE;
use reqwest::header::USER_AGENT;
use std::fs::OpenOptions;
use std::io::Write;
pub fn download(url: &str, dst: &str, block_size: i32, access_token: &str, is_debug: bool) {
let mut has_downloaded: i64 = 0;
let size: i32 = 1024 * 1024 * block_size; let downloader = Client::new();
let download_url = format!("{}&access_token={}", url, access_token);
let mut file_to_store = OpenOptions::new()
.append(true)
.create(true)
.open(dst)
.unwrap();
if size == 0 {
let response = downloader
.get(&download_url)
.header(USER_AGENT, "pan.baidu.com")
.send()
.unwrap();
file_to_store
.write_all(&(response.bytes().unwrap()))
.unwrap();
return;
}
let mut range_head = 0;
let mut range = format!("bytes={}-{}", range_head, range_head + size - 1);
loop {
let requestbuild = downloader
.get(&download_url)
.header(USER_AGENT, "pan.baidu.com")
.header(RANGE, &range);
let response = requestbuild.send().unwrap();
let len_rev = response
.headers()
.get(CONTENT_LENGTH)
.unwrap()
.to_str()
.unwrap()
.parse::<i32>()
.unwrap();
if is_debug {
has_downloaded += human_quota(len_rev as i64).1 as i64;
println!("recieve data total {} MB", has_downloaded);
}
file_to_store
.write_all(&(response.bytes().unwrap()))
.unwrap();
if len_rev < size {
if is_debug {
println!("finish download.");
}
break;
} else {
range_head += size;
range = format!("bytes={}-{}", range_head, range_head + size - 1);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_human_quota() {
let (kb, mb, gb) = human_quota(1024);
assert_eq!(kb, 1.0);
assert_eq!(mb, 0.0009765625);
assert_eq!(gb, 9.5367431640625e-7);
}
#[test]
fn test_human_quota_large() {
let (kb, mb, gb) = human_quota(1024 * 1024 * 1024);
assert_eq!(kb, 1048576.0);
assert_eq!(mb, 1024.0);
assert_eq!(gb, 1.0);
}
#[test]
fn test_get_vip_type_str_normal_user() {
let result = get_vip_type_str(0);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "普通用户");
}
#[test]
fn test_get_vip_type_str_normal_member() {
let result = get_vip_type_str(1);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "普通会员");
}
#[test]
fn test_get_vip_type_str_super_member() {
let result = get_vip_type_str(2);
assert!(result.is_ok());
assert_eq!(result.unwrap(), "超级会员");
}
#[test]
fn test_get_vip_type_str_invalid() {
let result = get_vip_type_str(999);
assert!(result.is_err());
let error = result.unwrap_err();
assert_eq!(error.ret_errno(), 8989);
let display = format!("{}", error);
assert!(display.contains("Not Support vip_type."));
}
#[test]
fn test_yunfs_check_dir_fmt_valid_absolute() {
let result = YunFs::check_dir_fmt("/dir1/dir2");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_valid_relative() {
let result = YunFs::check_dir_fmt("./dir1/dir2");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_valid_parent() {
let result = YunFs::check_dir_fmt("../dir1");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_current() {
let result = YunFs::check_dir_fmt(".");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_parent_dir() {
let result = YunFs::check_dir_fmt("..");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_invalid_backslash() {
let result = YunFs::check_dir_fmt("dir1\\dir2");
assert!(result.is_err());
let error = result.unwrap_err();
assert_eq!(error.ret_errno(), 8989);
let display = format!("{}", error);
assert!(display.contains("path resolve Error"));
assert!(display.contains("\\"));
}
#[test]
fn test_yunfs_check_dir_fmt_invalid_double_slash() {
let result = YunFs::check_dir_fmt("//dir1");
assert!(result.is_err());
let error = result.unwrap_err();
assert_eq!(error.ret_errno(), 8989);
let display = format!("{}", error);
assert!(display.contains("path resolve Error"));
assert!(display.contains("/"));
}
#[test]
fn test_yunfs_check_dir_fmt_invalid_dot_position() {
let result = YunFs::check_dir_fmt("dir1./dir2");
assert!(result.is_err());
let error = result.unwrap_err();
assert_eq!(error.ret_errno(), 8989);
let display = format!("{}", error);
assert!(display.contains("path resolve Error"));
}
#[test]
fn test_yunfs_check_dir_fmt_trailing_slash() {
let result = YunFs::check_dir_fmt("/dir1/");
assert!(result.is_ok());
}
#[test]
fn test_yunfs_check_dir_fmt_simple() {
let result = YunFs::check_dir_fmt("dir1");
assert!(result.is_ok());
}
}