use thiserror::Error;
use crate::api::data::{Error as DataError, OwnedData};
use crate::api::nonce::{request_nonce, NonceError};
use crate::api::request::{ensure_success, ResponseError};
use crate::api::url::UrlBuilder;
use crate::api::Version;
use crate::client::Client;
use crate::file::remote_file::RemoteFile;
pub const PARAMS_DOWNLOAD_MIN: u8 = 1;
pub const PARAMS_DOWNLOAD_MAX: u8 = 20;
pub struct Params<'a> {
file: &'a RemoteFile,
params: ParamsData,
nonce: Vec<u8>,
}
impl<'a> Params<'a> {
pub fn new(file: &'a RemoteFile, params: ParamsData, nonce: Option<Vec<u8>>) -> Self {
Self {
file,
params,
nonce: nonce.unwrap_or_default(),
}
}
pub fn invoke(mut self, client: &Client) -> Result<(), Error> {
if self.nonce.is_empty() {
self.nonce = self.fetch_auth_nonce(client)?;
}
let data = OwnedData::from(self.params.clone(), &self.file)
.map_err(|err| -> PrepareError { err.into() })?;
self.change_params(client, &data)
}
fn fetch_auth_nonce(&self, client: &Client) -> Result<Vec<u8>, Error> {
request_nonce(client, UrlBuilder::download(self.file, false)).map_err(|err| err.into())
}
fn change_params(&self, client: &Client, data: &OwnedData<ParamsData>) -> Result<(), Error> {
let url = UrlBuilder::api_params(self.file);
let response = client
.post(url)
.json(&data)
.send()
.map_err(|_| ChangeError::Request)?;
ensure_success(&response).map_err(|err| err.into())
}
}
#[derive(Clone, Debug, Builder, Serialize)]
pub struct ParamsData {
#[serde(default)]
#[builder(default)]
pub download_limit: Option<u8>,
#[serde(default)]
#[builder(default)]
#[serde(rename = "timeLimit")]
pub expiry_time: Option<usize>,
}
impl ParamsData {
pub fn new() -> Self {
Self::default()
}
pub fn from(download_limit: Option<u8>, expiry_time: Option<usize>) -> Self {
ParamsData {
download_limit,
expiry_time,
}
}
pub fn set_download_limit(
&mut self,
download_limit: Option<u8>,
) -> Result<(), ParamsDataError> {
if let Some(d) = download_limit {
if d < PARAMS_DOWNLOAD_MIN || d > PARAMS_DOWNLOAD_MAX {
return Err(ParamsDataError::DownloadBounds);
}
}
self.download_limit = download_limit;
Ok(())
}
#[cfg(feature = "send3")]
pub fn set_expiry_time(&mut self, expiry_time: Option<usize>) -> Result<(), ParamsDataError> {
self.expiry_time = expiry_time;
Ok(())
}
pub fn is_empty(&self) -> bool {
self.download_limit.is_none() && self.expiry_time.is_none()
}
#[allow(unused_variables)]
pub fn normalize(&mut self, version: Version) {
#[cfg(feature = "send2")]
{
#[allow(unreachable_patterns)]
match version {
Version::V2 => self.expiry_time = None,
_ => {}
}
}
}
}
impl Default for ParamsData {
fn default() -> ParamsData {
ParamsData {
download_limit: None,
expiry_time: None,
}
}
}
#[derive(Error, Debug)]
pub enum Error {
#[error("failed to prepare setting the parameters")]
Prepare(#[from] PrepareError),
#[error("the file has expired or did never exist")]
Expired,
#[error("failed to send the parameter change request")]
Change(#[from] ChangeError),
}
impl From<NonceError> for Error {
fn from(err: NonceError) -> Error {
match err {
NonceError::Expired => Error::Expired,
err => Error::Prepare(PrepareError::Auth(err)),
}
}
}
impl From<ResponseError> for Error {
fn from(err: ResponseError) -> Error {
match err {
ResponseError::Expired => Error::Expired,
err => Error::Change(ChangeError::Response(err)),
}
}
}
#[derive(Debug, Error)]
pub enum ParamsDataError {
#[error("invalid number of downloads, must be between 1 and 20")]
DownloadBounds,
#[error("")]
Owned(#[from] DataError),
}
#[derive(Error, Debug)]
pub enum PrepareError {
#[error("failed to authenticate")]
Auth(#[from] NonceError),
#[error("invalid parameters")]
ParamsData(#[from] ParamsDataError),
}
impl From<DataError> for PrepareError {
fn from(err: DataError) -> PrepareError {
PrepareError::ParamsData(ParamsDataError::Owned(err))
}
}
#[derive(Error, Debug)]
pub enum ChangeError {
#[error("failed to send parameter change request")]
Request,
#[error("bad response from server while changing parameters")]
Response(#[from] ResponseError),
}