Compare commits
3 commits
485c2cf21c
...
e6957a8de1
| Author | SHA1 | Date | |
|---|---|---|---|
| e6957a8de1 | |||
| 8d8f7bb0a8 | |||
| 58b8c1dd7c |
6 changed files with 189 additions and 138 deletions
12
src/main.rs
12
src/main.rs
|
|
@ -1,7 +1,7 @@
|
|||
mod sharry;
|
||||
|
||||
use log::info;
|
||||
use sharry::{Alias, NewShareRequest, URI};
|
||||
use sharry::{Alias, File, NewShareRequest, Share};
|
||||
use std::time::Duration;
|
||||
use ureq::Agent;
|
||||
|
||||
|
|
@ -14,16 +14,16 @@ fn main() {
|
|||
.into();
|
||||
|
||||
let alias = Alias::new(
|
||||
URI::new("sharry.yavook.de"),
|
||||
"sharry.yavook.de".into(),
|
||||
"G7RYoWME1W7-pcgipemJcr8-39FcMd92gBu-RgufeHc51z6",
|
||||
);
|
||||
|
||||
let share = alias.create_share(&agent, &NewShareRequest::new(Some("foo"), "", 10));
|
||||
|
||||
let share = share.unwrap();
|
||||
let share = NewShareRequest::new(Some("foo"), "", 10);
|
||||
let share = Share::create(&agent, &alias, share).unwrap();
|
||||
info!("share: {:?}", share);
|
||||
|
||||
share.create_file(&agent, "./myfile.dat").unwrap();
|
||||
let file = File::create(&agent, &share, "/lib/x86_64-linux-gnu/liblldb-14.so.1").unwrap();
|
||||
info!("file: {:?}", file);
|
||||
|
||||
share.notify(&agent).unwrap();
|
||||
}
|
||||
|
|
|
|||
38
src/sharry/alias.rs
Normal file
38
src/sharry/alias.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
use std::fmt::{Debug, Display};
|
||||
|
||||
use log::debug;
|
||||
use ureq::RequestBuilder;
|
||||
|
||||
use super::api::URI;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Alias {
|
||||
pub(super) api_uri: String,
|
||||
pub(super) id: String,
|
||||
}
|
||||
|
||||
pub(super) trait SharryAlias {
|
||||
fn sharry_header(self, alias: &Alias) -> Self;
|
||||
}
|
||||
|
||||
impl<B> SharryAlias for RequestBuilder<B> {
|
||||
fn sharry_header(self, alias: &Alias) -> Self {
|
||||
self.header("Sharry-Alias", &alias.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Alias {
|
||||
pub fn new(api_uri: URI, id: impl Into<String>) -> Self {
|
||||
Self {
|
||||
api_uri: api_uri.into(),
|
||||
id: id.into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn get_endpoint(&self, endpoint: impl Display + Debug) -> String {
|
||||
let uri = format!("{}/{}", self.api_uri, endpoint);
|
||||
debug!("endpoint uri: {:?}", uri);
|
||||
|
||||
uri
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,28 @@
|
|||
use std::fmt::Display;
|
||||
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct URI {
|
||||
protocol: String,
|
||||
base_url: String,
|
||||
}
|
||||
|
||||
impl URI {
|
||||
pub fn new_protocol(base_url: impl Into<String>, protocol: impl Into<String>) -> Self {
|
||||
pub fn with_protocol(protocol: impl Into<String>, base_url: impl Into<String>) -> Self {
|
||||
Self {
|
||||
protocol: protocol.into(),
|
||||
base_url: base_url.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(base_url: impl Into<String>) -> Self {
|
||||
Self::new_protocol(base_url, "https")
|
||||
impl From<&str> for URI {
|
||||
fn from(value: &str) -> Self {
|
||||
Self::with_protocol("https", value)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_endpoint(&self, endpoint: impl Display) -> String {
|
||||
let uri = format!("{}://{}/api/v2/{}", self.protocol, self.base_url, endpoint);
|
||||
debug!("uri: {:?}", uri);
|
||||
|
||||
uri
|
||||
impl Into<String> for URI {
|
||||
fn into(self) -> String {
|
||||
format!("{}://{}/api/v2", self.protocol, self.base_url)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -56,7 +53,7 @@ impl NewShareRequest {
|
|||
}
|
||||
|
||||
#[derive(Deserialize, Debug)]
|
||||
pub struct NewShareResponse {
|
||||
pub(super) struct NewShareResponse {
|
||||
pub success: bool,
|
||||
pub message: String,
|
||||
pub id: String,
|
||||
|
|
@ -64,7 +61,7 @@ pub struct NewShareResponse {
|
|||
|
||||
#[derive(Deserialize, Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub struct NotifyShareResponse {
|
||||
pub(super) struct NotifyShareResponse {
|
||||
pub success: bool,
|
||||
pub message: String,
|
||||
}
|
||||
|
|
|
|||
73
src/sharry/file.rs
Normal file
73
src/sharry/file.rs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
use std::{
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
use log::debug;
|
||||
use ureq::http::StatusCode;
|
||||
|
||||
use super::{
|
||||
alias::{Alias, SharryAlias},
|
||||
share::Share,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct File<'t> {
|
||||
alias: &'t Alias,
|
||||
path: PathBuf,
|
||||
patch_uri: String,
|
||||
}
|
||||
|
||||
impl<'t> File<'t> {
|
||||
pub fn create(
|
||||
http: &ureq::Agent,
|
||||
share: &'t Share,
|
||||
path: impl AsRef<OsStr> + AsRef<Path>,
|
||||
) -> Result<Self, ureq::Error> {
|
||||
let filepath = PathBuf::from(&path);
|
||||
|
||||
let endpoint = share
|
||||
.alias
|
||||
.get_endpoint(format!("alias/upload/{}/files/tus", share.id));
|
||||
|
||||
let filename = filepath
|
||||
.file_name()
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("file.bin");
|
||||
|
||||
let res = http
|
||||
.post(endpoint)
|
||||
.sharry_header(share.alias)
|
||||
.header("Sharry-File-Name", filename)
|
||||
.header("Upload-Length", fs::metadata(&filepath)?.len())
|
||||
.send_empty()?;
|
||||
|
||||
if res.status() != StatusCode::CREATED {
|
||||
return Err(ureq::Error::Other("unexpected response status".into()));
|
||||
}
|
||||
|
||||
let location = res
|
||||
.headers()
|
||||
.get("Location")
|
||||
.ok_or_else(|| ureq::Error::Other("Location header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| ureq::Error::Other("Location header invalid".into()))?;
|
||||
|
||||
debug!("location: {}", location);
|
||||
|
||||
// let start = 10;
|
||||
// let count = 10;
|
||||
|
||||
// let mut f = File::open(path)?;
|
||||
// f.seek(SeekFrom::Start(0));
|
||||
// let mut buf = vec![0; count];
|
||||
// f.read_exact(&mut buf)?;
|
||||
|
||||
Ok(Self {
|
||||
alias: share.alias,
|
||||
path: filepath,
|
||||
patch_uri: location.into(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,121 +1,11 @@
|
|||
#![allow(unused_imports)]
|
||||
|
||||
mod alias;
|
||||
mod api;
|
||||
mod file;
|
||||
mod share;
|
||||
|
||||
pub use alias::Alias;
|
||||
pub use api::{NewShareRequest, URI};
|
||||
use api::{NewShareResponse, NotifyShareResponse};
|
||||
use log::debug;
|
||||
use std::{ffi::OsStr, fs, path::Path};
|
||||
use ureq::{self, RequestBuilder};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Alias {
|
||||
uri: URI,
|
||||
id: String,
|
||||
}
|
||||
|
||||
impl Alias {
|
||||
pub fn new(uri: URI, id: impl Into<String>) -> Self {
|
||||
Self { uri, id: id.into() }
|
||||
}
|
||||
|
||||
fn add_headers<B>(&self, req: RequestBuilder<B>) -> RequestBuilder<B> {
|
||||
req.header("Sharry-Alias", &self.id)
|
||||
}
|
||||
|
||||
pub fn create_share(
|
||||
&self,
|
||||
http: &ureq::Agent,
|
||||
data: &NewShareRequest,
|
||||
) -> Result<Share, ureq::Error> {
|
||||
let endpoint = self.uri.get_endpoint("alias/upload/new");
|
||||
|
||||
let res = self
|
||||
.add_headers(http.post(endpoint))
|
||||
.send_json(data)?
|
||||
.body_mut()
|
||||
.read_json::<NewShareResponse>()?;
|
||||
|
||||
debug!("response: {:?}", res);
|
||||
assert!(res.success);
|
||||
assert_eq!(res.message, "Share created.");
|
||||
|
||||
Ok(Share {
|
||||
alias: self,
|
||||
id: res.id,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Share<'t> {
|
||||
alias: &'t Alias,
|
||||
id: String,
|
||||
}
|
||||
|
||||
impl<'t> Share<'t> {
|
||||
pub fn create_file(
|
||||
&self,
|
||||
http: &ureq::Agent,
|
||||
path: impl AsRef<OsStr> + AsRef<Path>,
|
||||
) -> Result<(), ureq::Error> {
|
||||
let filename = Path::new(&path)
|
||||
.file_name()
|
||||
.and_then(OsStr::to_str)
|
||||
.unwrap_or("file.bin");
|
||||
|
||||
let size = fs::metadata(&path)?.len();
|
||||
|
||||
let endpoint = self
|
||||
.alias
|
||||
.uri
|
||||
.get_endpoint(&format!("alias/upload/{}/files/tus", &self.id));
|
||||
|
||||
let res = self
|
||||
.alias
|
||||
.add_headers(http.post(endpoint))
|
||||
.header("Sharry-File-Name", filename)
|
||||
// .header("Sharry-File-Type", "application/octet-stream")
|
||||
// .header("Sharry-File-Length", size)
|
||||
// .header("Tus-Resumable", "1.0.0")
|
||||
.header("Upload-Length", size)
|
||||
.send_empty()?;
|
||||
|
||||
assert_eq!(res.status(), ureq::http::StatusCode::CREATED);
|
||||
|
||||
let location = res
|
||||
.headers()
|
||||
.get("Location")
|
||||
.ok_or_else(|| ureq::Error::Other("Location header not found".into()))?
|
||||
.to_str()
|
||||
.map_err(|_| ureq::Error::Other("Location header invalid".into()))?;
|
||||
|
||||
debug!("location: {}", location);
|
||||
|
||||
// let start = 10;
|
||||
// let count = 10;
|
||||
|
||||
// let mut f = File::open(path)?;
|
||||
// f.seek(SeekFrom::Start(0));
|
||||
// let mut buf = vec![0; count];
|
||||
// f.read_exact(&mut buf)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn notify(&self, http: &ureq::Agent) -> Result<(), ureq::Error> {
|
||||
let endpoint = self
|
||||
.alias
|
||||
.uri
|
||||
.get_endpoint(&format!("alias/mail/notify/{}", &self.id));
|
||||
|
||||
let res = self
|
||||
.alias
|
||||
.add_headers(http.post(endpoint))
|
||||
.send_empty()?
|
||||
.body_mut()
|
||||
.read_json::<NotifyShareResponse>()?;
|
||||
|
||||
debug!("response: {:?}", res);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
pub use file::File;
|
||||
pub use share::Share;
|
||||
|
|
|
|||
53
src/sharry/share.rs
Normal file
53
src/sharry/share.rs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
use log::{debug, warn};
|
||||
|
||||
use super::{
|
||||
alias::{Alias, SharryAlias},
|
||||
api::{NewShareRequest, NewShareResponse, NotifyShareResponse},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Share<'t> {
|
||||
pub(super) alias: &'t Alias,
|
||||
pub(super) id: String,
|
||||
}
|
||||
|
||||
impl<'t> Share<'t> {
|
||||
pub fn create(
|
||||
http: &ureq::Agent,
|
||||
alias: &'t Alias,
|
||||
data: NewShareRequest,
|
||||
) -> Result<Self, ureq::Error> {
|
||||
let res = http
|
||||
.post(alias.get_endpoint("alias/upload/new"))
|
||||
.sharry_header(alias)
|
||||
.send_json(data)?
|
||||
.body_mut()
|
||||
.read_json::<NewShareResponse>()?;
|
||||
|
||||
debug!("response: {:?}", res);
|
||||
|
||||
if !(res.success && (res.message == "Share created.")) {
|
||||
warn!("unexpected json response");
|
||||
return Err(ureq::Error::Other("unexpected json response".into()));
|
||||
}
|
||||
|
||||
Ok(Self { alias, id: res.id })
|
||||
}
|
||||
|
||||
pub fn notify(&self, http: &ureq::Agent) -> Result<(), ureq::Error> {
|
||||
let endpoint = self
|
||||
.alias
|
||||
.get_endpoint(format!("alias/mail/notify/{}", self.id));
|
||||
|
||||
let res = http
|
||||
.post(endpoint)
|
||||
.sharry_header(self.alias)
|
||||
.send_empty()?
|
||||
.body_mut()
|
||||
.read_json::<NotifyShareResponse>()?;
|
||||
|
||||
debug!("response: {:?}", res);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue