I'm going to sleep, pushing broken code, cierp
This commit is contained in:
parent
bdb2b7f887
commit
5641339bfb
213
src/main.rs
213
src/main.rs
|
@ -1,51 +1,49 @@
|
|||
use clap::{App, Arg};
|
||||
use std::process;
|
||||
use std::error::Error;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io;
|
||||
use std::io::{Seek, SeekFrom, Read, Write};
|
||||
use json::object;
|
||||
use multipart::client::lazy::Multipart;
|
||||
use json::{object};
|
||||
use std::path::Path;
|
||||
use std::fmt;
|
||||
use std::fmt::Formatter;
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt,
|
||||
fmt::Formatter,
|
||||
fs::{File, OpenOptions},
|
||||
io,
|
||||
io::{Read, Seek, SeekFrom, Write},
|
||||
path::Path,
|
||||
process,
|
||||
thread::sleep,
|
||||
time::Duration,
|
||||
};
|
||||
use ureq::Response;
|
||||
use color_eyre::eyre::Result;
|
||||
|
||||
mod cli;
|
||||
mod discord;
|
||||
mod config;
|
||||
|
||||
const MAXBUF: u64 = 8380416;
|
||||
|
||||
impl Error for ChuncordError {}
|
||||
|
||||
impl fmt::Display for ChuncordError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
ChuncordError::InvalidIndexJson(j) => write!(f, "Index JSON is invalid: {}", j),
|
||||
ChuncordError::InvalidApiJson(j) => write!(f, "Discord JSON is invalid: {}", j),
|
||||
ChuncordError::FileTooBig => write!(f, "File is too big")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChuncordError {
|
||||
InvalidIndexJson(String),
|
||||
InvalidApiJson(String),
|
||||
FileTooBig
|
||||
}
|
||||
|
||||
fn upload_discord(filename: &str, data: &[u8], webhook: &str) -> Result<(String, String), Box<dyn Error>> {
|
||||
fn upload_discord(
|
||||
filename: &str,
|
||||
data: &[u8],
|
||||
webhook: &str,
|
||||
) -> Result<(String, String), Box<dyn Error>> {
|
||||
let mut mp = Multipart::new();
|
||||
mp.add_stream("file", data, Some(filename.to_string()), None);
|
||||
let mpdata = mp.prepare()?;
|
||||
let response = ureq::post(webhook)
|
||||
.set("Content-Type", &format!("multipart/form-data; boundary={}", mpdata.boundary()))
|
||||
.set(
|
||||
"Content-Type",
|
||||
&format!("multipart/form-data; boundary={}", mpdata.boundary()),
|
||||
)
|
||||
.send(mpdata)?;
|
||||
cool_ratelimit(&response)?;
|
||||
let response_string = response.into_string()?;
|
||||
let mut rjson = json::parse(&response_string)?;
|
||||
let url = rjson["attachments"][0]["url"].take_string().ok_or_else(|| ChuncordError::InvalidApiJson(response_string.clone()))?;
|
||||
let id = rjson["id"].take_string().ok_or_else(|| ChuncordError::InvalidApiJson(response_string.clone()))?;
|
||||
let url = rjson["attachments"][0]["url"]
|
||||
.take_string()
|
||||
.ok_or_else(|| ChuncordError::InvalidApiJson(response_string.clone()))?;
|
||||
let id = rjson["id"]
|
||||
.take_string()
|
||||
.ok_or_else(|| ChuncordError::InvalidApiJson(response_string.clone()))?;
|
||||
Ok((url, id))
|
||||
}
|
||||
|
||||
|
@ -87,7 +85,12 @@ fn upload_command(file: &str, webhook: &str) -> Result<(), Box<dyn Error>> {
|
|||
let mut index_json = object! {name: filename, parts: {}};
|
||||
let mut buffer = vec![0u8; MAXBUF as usize];
|
||||
for fullread in 0..fullreads {
|
||||
print!("Uploading... [{}/{}] {}%\r", fullread, fullreads, fullread*100/fullreads);
|
||||
print!(
|
||||
"Uploading... [{}/{}] {}%\r",
|
||||
fullread,
|
||||
fullreads,
|
||||
fullread * 100 / fullreads
|
||||
);
|
||||
io::stdout().flush()?;
|
||||
file.read_exact(&mut buffer)?;
|
||||
let upload_result = upload_discord(fullread.to_string().as_str(), &buffer, webhook)?;
|
||||
|
@ -97,12 +100,19 @@ fn upload_command(file: &str, webhook: &str) -> Result<(), Box<dyn Error>> {
|
|||
io::stdout().flush()?;
|
||||
if lastread > 0 {
|
||||
file.read_exact(&mut buffer[0..lastread as usize])?;
|
||||
let upload_result = upload_discord(fullreads.to_string().as_str(), &buffer[0..lastread as usize], webhook)?;
|
||||
let upload_result = upload_discord(
|
||||
fullreads.to_string().as_str(),
|
||||
&buffer[0..lastread as usize],
|
||||
webhook,
|
||||
)?;
|
||||
index_json["parts"].insert(upload_result.0.as_str(), upload_result.1.as_str())?;
|
||||
}
|
||||
println!("\nUploading index...");
|
||||
let index_upload_result = upload_discord("index.json", index_json.dump().as_bytes(), webhook)?;
|
||||
println!("\nDone!\nIndex URL: {}\nIndex message ID (needed for delete): {}", index_upload_result.0, index_upload_result.1);
|
||||
println!(
|
||||
"\nDone!\nIndex URL: {}\nIndex message ID (needed for delete): {}",
|
||||
index_upload_result.0, index_upload_result.1
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -114,14 +124,24 @@ fn download_command(file: Option<&str>, index_url: &str) -> Result<(), Box<dyn E
|
|||
if parts_count == 0 {
|
||||
return Err(Box::new(ChuncordError::InvalidIndexJson(index_json)));
|
||||
}
|
||||
let index_filename = parsed_index["name"].take_string().ok_or(ChuncordError::InvalidIndexJson(index_json))?;
|
||||
let index_filename = parsed_index["name"]
|
||||
.take_string()
|
||||
.ok_or(ChuncordError::InvalidIndexJson(index_json))?;
|
||||
let filename = file.unwrap_or_else(|| index_filename.as_str());
|
||||
let mut file = OpenOptions::new().write(true).create_new(true).open(filename)?;
|
||||
let mut file = OpenOptions::new()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(filename)?;
|
||||
let parts = parsed_index["parts"].entries();
|
||||
for part in (0..).zip(parts) {
|
||||
print!("Downloading... [{}/{}] {}%\r", part.0, parts_count-1, part.0*100/(parts_count-1));
|
||||
print!(
|
||||
"Downloading... [{}/{}] {}%\r",
|
||||
part.0,
|
||||
parts_count - 1,
|
||||
part.0 * 100 / (parts_count - 1)
|
||||
);
|
||||
io::stdout().flush()?;
|
||||
let mut downloaded_part = download_file(part.1.0)?;
|
||||
let mut downloaded_part = download_file(part.1 .0)?;
|
||||
io::copy(&mut downloaded_part, &mut file)?;
|
||||
}
|
||||
println!("\nDone!");
|
||||
|
@ -130,9 +150,12 @@ fn download_command(file: Option<&str>, index_url: &str) -> Result<(), Box<dyn E
|
|||
|
||||
fn delete_command(mid: &str, webhook: &str) -> Result<(), Box<dyn Error>> {
|
||||
println!("Downloading index...");
|
||||
let index_message_result = ureq::get(&format!("{}/messages/{}", webhook, mid)).call()?.into_string()?;
|
||||
let index_message_result = ureq::get(&format!("{}/messages/{}", webhook, mid))
|
||||
.call()?
|
||||
.into_string()?;
|
||||
let mut index_message_result_json = json::parse(index_message_result.as_str())?;
|
||||
let index_url = index_message_result_json["attachments"][0]["url"].take_string()
|
||||
let index_url = index_message_result_json["attachments"][0]["url"]
|
||||
.take_string()
|
||||
.ok_or(ChuncordError::InvalidApiJson(index_message_result))?;
|
||||
let index = download_index(&index_url)?;
|
||||
let mut index_json = json::parse(&index)?;
|
||||
|
@ -142,9 +165,21 @@ fn delete_command(mid: &str, webhook: &str) -> Result<(), Box<dyn Error>> {
|
|||
}
|
||||
let parts = index_json["parts"].entries_mut();
|
||||
for part in (0..).zip(parts) {
|
||||
print!("Deleting... [{}/{}] {}%\r", part.0, parts_count-1, part.0*100/(parts_count-1));
|
||||
print!(
|
||||
"Deleting... [{}/{}] {}%\r",
|
||||
part.0,
|
||||
parts_count - 1,
|
||||
part.0 * 100 / (parts_count - 1)
|
||||
);
|
||||
io::stdout().flush()?;
|
||||
delete_discord(&part.1.1.take_string().ok_or_else(|| ChuncordError::InvalidIndexJson(index.clone()))?, webhook)?;
|
||||
delete_discord(
|
||||
&part
|
||||
.1
|
||||
.1
|
||||
.take_string()
|
||||
.ok_or_else(|| ChuncordError::InvalidIndexJson(index.clone()))?,
|
||||
webhook,
|
||||
)?;
|
||||
}
|
||||
println!("\nDeleting index...");
|
||||
delete_discord(mid, webhook)?;
|
||||
|
@ -152,28 +187,84 @@ fn delete_command(mid: &str, webhook: &str) -> Result<(), Box<dyn Error>> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let clapmatch = App::new("Chuncord").version("0.1").author("by ./lemon.sh")
|
||||
fn main() -> Result<()> {
|
||||
color_eyre::install()?;
|
||||
let clapmatch = App::new("Chuncord")
|
||||
.version("0.1")
|
||||
.author("by ./lemon.sh")
|
||||
.about("Upload chunky files to Discord with Webhooks")
|
||||
.subcommand(App::new("upload").about("Upload file")
|
||||
.arg(Arg::new("webhook").required(true).short('w').takes_value(true).about("Discord Webhook"))
|
||||
.arg(Arg::new("file").required(true).short('f').takes_value(true).about("File to upload")))
|
||||
.subcommand(App::new("download").about("Download file")
|
||||
.arg(Arg::new("url").short('u').required(true).about("Index URL").takes_value(true))
|
||||
.arg(Arg::new("file").short('o').about("Output file").takes_value(true)))
|
||||
.subcommand(App::new("delete").about("Delete file")
|
||||
.arg(Arg::new("mid").short('m').required(true).about("Index message ID").takes_value(true))
|
||||
.arg(Arg::new("webhook").required(true).short('w').takes_value(true).about("Discord Webhook")))
|
||||
.subcommand(
|
||||
App::new("upload")
|
||||
.about("Upload file")
|
||||
.arg(
|
||||
Arg::new("webhook")
|
||||
.required(true)
|
||||
.short('w')
|
||||
.takes_value(true)
|
||||
.about("Discord Webhook"),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("file")
|
||||
.required(true)
|
||||
.short('f')
|
||||
.takes_value(true)
|
||||
.about("File to upload"),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
App::new("download")
|
||||
.about("Download file")
|
||||
.arg(
|
||||
Arg::new("url")
|
||||
.short('u')
|
||||
.required(true)
|
||||
.about("Index URL")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("file")
|
||||
.short('o')
|
||||
.about("Output file")
|
||||
.takes_value(true),
|
||||
),
|
||||
)
|
||||
.subcommand(
|
||||
App::new("delete")
|
||||
.about("Delete file")
|
||||
.arg(
|
||||
Arg::new("mid")
|
||||
.short('m')
|
||||
.required(true)
|
||||
.about("Index message ID")
|
||||
.takes_value(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("webhook")
|
||||
.required(true)
|
||||
.short('w')
|
||||
.takes_value(true)
|
||||
.about("Discord Webhook"),
|
||||
),
|
||||
)
|
||||
.get_matches();
|
||||
let subcommand = clapmatch.subcommand().unwrap_or_else(|| {
|
||||
println!("No subcommand provided. See --help");
|
||||
process::exit(1)
|
||||
});
|
||||
if let Err(e) = match subcommand.0 {
|
||||
"upload" => upload_command(subcommand.1.value_of("file").unwrap(), subcommand.1.value_of("webhook").unwrap()),
|
||||
"download" => download_command(subcommand.1.value_of("file"), subcommand.1.value_of("url").unwrap()),
|
||||
"delete" => delete_command(subcommand.1.value_of("mid").unwrap(), subcommand.1.value_of("webhook").unwrap()),
|
||||
_ => Ok(())
|
||||
"upload" => upload_command(
|
||||
subcommand.1.value_of("file").unwrap(),
|
||||
subcommand.1.value_of("webhook").unwrap(),
|
||||
),
|
||||
"download" => download_command(
|
||||
subcommand.1.value_of("file"),
|
||||
subcommand.1.value_of("url").unwrap(),
|
||||
),
|
||||
"delete" => delete_command(
|
||||
subcommand.1.value_of("mid").unwrap(),
|
||||
subcommand.1.value_of("webhook").unwrap(),
|
||||
),
|
||||
_ => Ok(()),
|
||||
} {
|
||||
println!("An error has occurred.\n{}", e);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue