implement delete
This commit is contained in:
parent
92e5c3f985
commit
c9ec5ff082
@ -91,9 +91,44 @@ impl Client {
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn file_detail(
|
||||
&self,
|
||||
req: types::request::FileDetailRequest,
|
||||
) -> anyhow::Result<types::response::FileDetailResponse> {
|
||||
let client = reqwest::Client::new();
|
||||
let request = client
|
||||
.post("https://forest.sendy.jp/cloud/service/file/v1/file")
|
||||
.bearer_auth(&self.token)
|
||||
.json(&req);
|
||||
|
||||
let response = request.send().await?;
|
||||
response
|
||||
.json::<types::response::FileDetailResponse>()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
|
||||
pub async fn delete_file(
|
||||
&self,
|
||||
req: types::request::DeleteFileRequest,
|
||||
) -> anyhow::Result<types::response::JobKeyResponse> {
|
||||
let client = reqwest::Client::new();
|
||||
let request = client
|
||||
.delete("https://forest.sendy.jp/cloud/service/file/v3/files")
|
||||
.bearer_auth(&self.token)
|
||||
.json(&req);
|
||||
|
||||
let response = request.send().await?;
|
||||
response
|
||||
.json::<types::response::JobKeyResponse>()
|
||||
.await
|
||||
.map_err(Into::into)
|
||||
}
|
||||
}
|
||||
|
||||
// https://www.rakuten-drive.com/api/account/refreshtoken POST RefreshTokenRequest RefreshTokenResponse
|
||||
// https://forest.sendy.jp/cloud/service/file/v1/file POST FileDetailRequest FileDetailResponse
|
||||
// https://forest.sendy.jp/cloud/service/file/v1/files POST ListFilesRequest ListFilesResponse
|
||||
// https://forest.sendy.jp/cloud/service/file/v3/files DELETE DeleteFileRequest JobKeyResponse
|
||||
// https://forest.sendy.jp/cloud/service/file/v1/files/create POST CreateFolderRequest
|
||||
|
67
src/main.rs
67
src/main.rs
@ -19,7 +19,7 @@ use types::response::ListFilesResponseFile;
|
||||
mod endpoints;
|
||||
mod types;
|
||||
|
||||
const BEARER_TOKEN: &str = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxNTQwYWM3MWJiOTJhYTA2OTNjODI3MTkwYWNhYmU1YjA1NWNiZWMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoi5bm457-8IOW_l-adkSIsInBsYW4iOiJza2YiLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vc2VuZHktc2VydmljZSIsImF1ZCI6InNlbmR5LXNlcnZpY2UiLCJhdXRoX3RpbWUiOjE3MjEyMjYwMTUsInVzZXJfaWQiOiJHY2xUN0RybkxGaG83dm5JaXJVemp0TUxoUmsyIiwic3ViIjoiR2NsVDdEcm5MRmhvN3ZuSWlyVXpqdE1MaFJrMiIsImlhdCI6MTcyMTI1NTM1OCwiZXhwIjoxNzIxMjU4OTU4LCJlbWFpbCI6ImtvdXN1a2UxMTIzNjEyNEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsia291c3VrZTExMjM2MTI0QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6ImN1c3RvbSJ9fQ.uC-X4XCMTJ-Vv0bmm85cZy65LVdNxRKBlNXxsg8_QqyMV1rRzmpDMQpwWKk10OUDj6xovg1tfmlUW2syL0twANO8hKOSlI_wLZ1Rvvm0TF8EvDLvv8OGFc93nm3OIaSaiZj-xcORZzeJDVHsdraGoYDX3YbYPIJAhDaOsHX5_QbLwuxoz0dxd0fTAoDH7aEpDhcojjTmMImtbGqMzpvUpwNunJaJK2YZTYiHXZtcK7mr9cQLF5b3Exee--R5hGEU9E49jGtXKQNrP_6mkTXVivJh6TdKeFiMCrbc-6xZvuBnkEQ8g0GvU9cERhJTZ73U2jdHLzWbYitCh2nzkbQDNA";
|
||||
const BEARER_TOKEN: &str = "eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxNTQwYWM3MWJiOTJhYTA2OTNjODI3MTkwYWNhYmU1YjA1NWNiZWMiLCJ0eXAiOiJKV1QifQ.eyJuYW1lIjoi5bm457-8IOW_l-adkSIsInBsYW4iOiJza2YiLCJpc3MiOiJodHRwczovL3NlY3VyZXRva2VuLmdvb2dsZS5jb20vc2VuZHktc2VydmljZSIsImF1ZCI6InNlbmR5LXNlcnZpY2UiLCJhdXRoX3RpbWUiOjE3MjEyMjYwMTUsInVzZXJfaWQiOiJHY2xUN0RybkxGaG83dm5JaXJVemp0TUxoUmsyIiwic3ViIjoiR2NsVDdEcm5MRmhvN3ZuSWlyVXpqdE1MaFJrMiIsImlhdCI6MTcyMTI2MDk2NSwiZXhwIjoxNzIxMjY0NTY1LCJlbWFpbCI6ImtvdXN1a2UxMTIzNjEyNEBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsImZpcmViYXNlIjp7ImlkZW50aXRpZXMiOnsiZW1haWwiOlsia291c3VrZTExMjM2MTI0QGdtYWlsLmNvbSJdfSwic2lnbl9pbl9wcm92aWRlciI6ImN1c3RvbSJ9fQ.qgMyyPkP992xCtsTjr28PhzjiqaNBn1O1Z6HYEk3cjgPyVoPRiMV5KaDuWWveP0Z2x5_jvd5We0zsYzpxnOcf1dlf4VmAUqNGrVjCRqWUBuU008EkTAFlKBZAk4yYON0xddNcoUR6OrmYSLKMR5OOOV9FkTbFzd72rydQpcbiy9nmint_uXnN3z_9th0yf0J8oBd4_aXUzGUw2YOG8mBlgJfAoFdO5gMxJCWkC2V9r1TbxYWDMrFwtj7QMLVN4TOz2Bcy8erPiA_T46ap2gc9T0wTaPrE8h436FkTLdiaSJaYBLMEbS7dtXNLZ7SxaA4JOfeIgt2KoN5BrZg4qqt4Q";
|
||||
const HOST_ID: &str = "GclT7DrnLFho7vnIirUzjtMLhRk2";
|
||||
const CHUNK_SIZE: usize = 1024 * 1024 * 10; // 10MB
|
||||
const APP_VERSION: &str = "v21.11.10";
|
||||
@ -38,7 +38,6 @@ enum Commands {
|
||||
prefix: Option<String>,
|
||||
},
|
||||
Upload {
|
||||
#[clap(short, long)]
|
||||
file: PathBuf,
|
||||
#[clap(short, long)]
|
||||
prefix: Option<String>,
|
||||
@ -46,13 +45,16 @@ enum Commands {
|
||||
recursive: bool,
|
||||
},
|
||||
Download {
|
||||
#[clap(short, long)]
|
||||
path: String,
|
||||
#[clap(long)]
|
||||
prefix: Option<String>,
|
||||
},
|
||||
Move {},
|
||||
Delete {},
|
||||
Delete {
|
||||
path: String,
|
||||
#[clap(long)]
|
||||
recursive: bool,
|
||||
},
|
||||
MkDir {},
|
||||
}
|
||||
|
||||
@ -68,7 +70,7 @@ async fn main() {
|
||||
|
||||
match &args.command {
|
||||
Commands::List { prefix } => {
|
||||
let res = list_files(prefix.clone()).await.unwrap();
|
||||
let res = list_files(Some(&prefix.clone().unwrap_or("".to_string()))).await.unwrap();
|
||||
res.file.iter().for_each(|f| {
|
||||
let permission_string = if f.is_folder { "d" } else { "-" };
|
||||
println!(
|
||||
@ -243,7 +245,7 @@ async fn main() {
|
||||
let file_path =
|
||||
path.split('/').collect::<Vec<&str>>()[0..path.split('/').count() - 1].join("/");
|
||||
|
||||
let list = list_files(Some(file_path.clone())).await.unwrap();
|
||||
let list = list_files(Some(&file_path)).await.unwrap();
|
||||
|
||||
let file = list
|
||||
.file
|
||||
@ -286,8 +288,40 @@ async fn main() {
|
||||
Commands::Move {} => {
|
||||
println!("Move");
|
||||
}
|
||||
Commands::Delete {} => {
|
||||
println!("Delete");
|
||||
Commands::Delete { path, recursive } => {
|
||||
let client = endpoints::Client::new(BEARER_TOKEN.to_string(), HOST_ID.to_string());
|
||||
let file = file_detail(path).await.unwrap();
|
||||
if file.is_folder && !*recursive {
|
||||
println!("Use --recursive option for folder delete");
|
||||
return;
|
||||
}
|
||||
let req = types::request::DeleteFileRequest {
|
||||
file: vec![types::request::FileModifyRequestFile {
|
||||
last_modified: file.last_modified,
|
||||
path: file.path,
|
||||
version_id: file.version_id,
|
||||
size: file.size,
|
||||
}],
|
||||
host_id: client.host_id.clone(),
|
||||
prefix: "".to_string(),
|
||||
trash: true,
|
||||
};
|
||||
let res = client.delete_file(req).await.unwrap();
|
||||
|
||||
loop {
|
||||
let req = types::request::CheckActionRequest {
|
||||
key: res.key.clone(),
|
||||
};
|
||||
let res = client.check_action(req).await.unwrap();
|
||||
|
||||
if res.state == "complete" {
|
||||
break;
|
||||
}
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(200));
|
||||
}
|
||||
|
||||
println!("Deleted");
|
||||
}
|
||||
Commands::MkDir {} => {
|
||||
println!("MkDir");
|
||||
@ -440,14 +474,25 @@ async fn multipart_upload(
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn list_files(prefix: Option<String>) -> anyhow::Result<types::response::ListFilesResponse> {
|
||||
async fn file_detail(path: &str) -> anyhow::Result<types::response::FileDetailResponseFile> {
|
||||
let client = endpoints::Client::new(BEARER_TOKEN.to_string(), HOST_ID.to_string());
|
||||
let req = types::request::FileDetailRequest {
|
||||
host_id: client.host_id.clone(),
|
||||
path: path.to_string(),
|
||||
thumbnail_size: 130,
|
||||
};
|
||||
let res = client.file_detail(req).await?;
|
||||
Ok(res.file)
|
||||
}
|
||||
|
||||
async fn list_files(prefix: Option<&str>) -> anyhow::Result<types::response::ListFilesResponse> {
|
||||
let client = endpoints::Client::new(BEARER_TOKEN.to_string(), HOST_ID.to_string());
|
||||
let pagination_size = 40;
|
||||
let mut files = Vec::<ListFilesResponseFile>::new();
|
||||
let req = types::request::ListFilesRequest {
|
||||
from: 0,
|
||||
host_id: client.host_id.clone(),
|
||||
path: prefix.clone().unwrap_or("".to_string()),
|
||||
path: prefix.clone().unwrap_or("").to_string(),
|
||||
sort_type: "path".to_string(),
|
||||
reverse: false,
|
||||
thumbnail_size: 130,
|
||||
@ -463,7 +508,7 @@ async fn list_files(prefix: Option<String>) -> anyhow::Result<types::response::L
|
||||
let req = types::request::ListFilesRequest {
|
||||
from: cursor,
|
||||
host_id: client.host_id.clone(),
|
||||
path: prefix.clone().unwrap_or("".to_string()),
|
||||
path: prefix.clone().unwrap_or("").to_string(),
|
||||
sort_type: "path".to_string(),
|
||||
reverse: false,
|
||||
thumbnail_size: 130,
|
||||
|
@ -29,7 +29,7 @@ pub struct CreateFolderRequest {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct RenameFileRequest {
|
||||
pub file: Vec<RenameFileRequestFile>,
|
||||
pub file: Vec<FileModifyRequestFile>,
|
||||
pub host_id: String,
|
||||
pub name: String,
|
||||
pub path: String,
|
||||
@ -37,7 +37,7 @@ pub struct RenameFileRequest {
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
|
||||
pub struct RenameFileRequestFile {
|
||||
pub struct FileModifyRequestFile {
|
||||
pub last_modified: String, // 1970-01-20T22:07:12.804Z
|
||||
pub path: String,
|
||||
pub size: i64,
|
||||
@ -53,7 +53,7 @@ pub struct CheckActionRequest {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct MoveFileRequest {
|
||||
pub file: Vec<RenameFileRequestFile>,
|
||||
pub file: Vec<FileModifyRequestFile>,
|
||||
pub host_id: String,
|
||||
pub prefix: String,
|
||||
pub path: String,
|
||||
@ -96,7 +96,7 @@ pub struct CompleteUploadRequestFile {
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct DeleteFileRequest {
|
||||
pub file: Vec<RenameFileRequestFile>,
|
||||
pub file: Vec<FileModifyRequestFile>,
|
||||
pub host_id: String,
|
||||
pub prefix: String,
|
||||
pub trash: bool,
|
||||
@ -117,8 +117,10 @@ pub struct GetFileLinkRequestFile {
|
||||
pub size: i64,
|
||||
}
|
||||
|
||||
// #[derive(Debug, Serialize, Deserialize)]
|
||||
// pub struct GetFileLinkRequest {
|
||||
// pub host_id: String,
|
||||
// pub path: String,
|
||||
// }
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct FileDetailRequest {
|
||||
pub host_id: String,
|
||||
pub path: String,
|
||||
pub thumbnail_size: i64,
|
||||
}
|
@ -109,3 +109,42 @@ pub struct GetFileLinkTokenResponse {
|
||||
pub struct GetFileLinkResponse {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub struct FileDetailResponse {
|
||||
pub access_level: String,
|
||||
pub file: FileDetailResponseFile,
|
||||
pub owner: String,
|
||||
pub prefix: String,
|
||||
pub usage_size: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct FileDetailResponseFile {
|
||||
pub access_level: String,
|
||||
pub has_child_folder: bool,
|
||||
|
||||
#[serde(rename = "HostID")]
|
||||
pub host_id: String,
|
||||
pub is_backed_up: bool,
|
||||
pub is_folder: bool,
|
||||
pub is_latest: bool,
|
||||
pub is_share: String,
|
||||
pub items_count: i64,
|
||||
pub last_modified: String, // 2024-07-16T06:18:06.595Z
|
||||
|
||||
#[serde(rename = "LastModifierID")]
|
||||
pub last_modifier_id: String,
|
||||
|
||||
#[serde(rename = "OwnerID")]
|
||||
pub owner_id: String, // OwnerID
|
||||
pub path: String,
|
||||
pub size: i64,
|
||||
pub thumbnail: String,
|
||||
pub version: serde_json::Value, // returns null
|
||||
|
||||
#[serde(rename = "VersionID")]
|
||||
pub version_id: String,
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user