/* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ //! Command, response, and status types. use std::error::Error as StdError; use std::ffi::OsString; use std::fmt; use std::result; use guid_win::Guid; use thiserror::Error; use super::{BitsErrorContext, BitsJobProgress, BitsJobState, BitsJobTimes, BitsProxyUsage}; type HRESULT = i32; /// An HRESULT with a descriptive message #[derive(Clone, Debug)] pub struct HResultMessage { pub hr: HRESULT, pub message: String, } impl fmt::Display for HResultMessage { fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> { self.message.fmt(f) } } impl StdError for HResultMessage {} /// Commands which can be sent to the server. /// /// This is currently unused as the out-of-process Local Service server is not finished. #[doc(hidden)] #[derive(Clone, Debug)] pub enum Command { StartJob(StartJobCommand), MonitorJob(MonitorJobCommand), SuspendJob(SuspendJobCommand), ResumeJob(ResumeJobCommand), SetJobPriority(SetJobPriorityCommand), SetNoProgressTimeout(SetNoProgressTimeoutCommand), SetUpdateInterval(SetUpdateIntervalCommand), CompleteJob(CompleteJobCommand), CancelJob(CancelJobCommand), } /// Combine a [`Command`](enum.Command.html) with its success and failure result types. #[doc(hidden)] pub trait CommandType { type Success; type Failure: StdError; fn wrap(command: Self) -> Command; } // Start Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct StartJobCommand { pub url: OsString, pub save_path: OsString, pub proxy_usage: BitsProxyUsage, pub no_progress_timeout_secs: u32, pub monitor: Option, } impl CommandType for StartJobCommand { type Success = StartJobSuccess; type Failure = StartJobFailure; fn wrap(cmd: Self) -> Command { Command::StartJob(cmd) } } #[doc(hidden)] #[derive(Clone, Debug)] pub struct MonitorConfig { pub pipe_name: OsString, pub interval_millis: u32, } #[derive(Clone, Debug)] pub struct StartJobSuccess { pub guid: Guid, } #[derive(Clone, Debug, Error)] pub enum StartJobFailure { #[error("Argument validation failed: {0}")] ArgumentValidation(String), #[error("Create job: {0}")] Create(HResultMessage), #[error("Add file to job: {0}")] AddFile(HResultMessage), #[error("Apply settings to job: {0}")] ApplySettings(HResultMessage), #[error("Resume job: {0}")] Resume(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Monitor Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct MonitorJobCommand { pub guid: Guid, pub monitor: MonitorConfig, } impl CommandType for MonitorJobCommand { type Success = (); type Failure = MonitorJobFailure; fn wrap(cmd: Self) -> Command { Command::MonitorJob(cmd) } } #[derive(Clone, Debug, Error)] pub enum MonitorJobFailure { #[error("Argument validation failed: {0}")] ArgumentValidation(String), #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Suspend Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct SuspendJobCommand { pub guid: Guid, } impl CommandType for SuspendJobCommand { type Success = (); type Failure = SuspendJobFailure; fn wrap(cmd: Self) -> Command { Command::SuspendJob(cmd) } } #[derive(Clone, Debug, Error)] pub enum SuspendJobFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Suspend job: {0}")] SuspendJob(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Resume Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct ResumeJobCommand { pub guid: Guid, } impl CommandType for ResumeJobCommand { type Success = (); type Failure = ResumeJobFailure; fn wrap(cmd: Self) -> Command { Command::ResumeJob(cmd) } } #[derive(Clone, Debug, Error)] pub enum ResumeJobFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Resume job: {0}")] ResumeJob(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Set Job Priority #[doc(hidden)] #[derive(Clone, Debug)] pub struct SetJobPriorityCommand { pub guid: Guid, pub foreground: bool, } impl CommandType for SetJobPriorityCommand { type Success = (); type Failure = SetJobPriorityFailure; fn wrap(cmd: Self) -> Command { Command::SetJobPriority(cmd) } } #[derive(Clone, Debug, Error)] pub enum SetJobPriorityFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Apply settings to job: {0}")] ApplySettings(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Set No Progress Timeout #[doc(hidden)] #[derive(Clone, Debug)] pub struct SetNoProgressTimeoutCommand { pub guid: Guid, pub timeout_secs: u32, } impl CommandType for SetNoProgressTimeoutCommand { type Success = (); type Failure = SetNoProgressTimeoutFailure; fn wrap(cmd: Self) -> Command { Command::SetNoProgressTimeout(cmd) } } #[derive(Clone, Debug, Error)] pub enum SetNoProgressTimeoutFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Apply settings to job: {0}")] ApplySettings(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Set Update Interval #[doc(hidden)] #[derive(Clone, Debug)] pub struct SetUpdateIntervalCommand { pub guid: Guid, pub interval_millis: u32, } impl CommandType for SetUpdateIntervalCommand { type Success = (); type Failure = SetUpdateIntervalFailure; fn wrap(cmd: Self) -> Command { Command::SetUpdateInterval(cmd) } } #[derive(Clone, Debug, Error)] pub enum SetUpdateIntervalFailure { #[error("Argument validation: {0}")] ArgumentValidation(String), #[error("Monitor not found")] NotFound, #[error("Other failure: {0}")] Other(String), } // Complete Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct CompleteJobCommand { pub guid: Guid, } impl CommandType for CompleteJobCommand { type Success = (); type Failure = CompleteJobFailure; fn wrap(cmd: Self) -> Command { Command::CompleteJob(cmd) } } #[derive(Clone, Debug, Error)] pub enum CompleteJobFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Complete job: {0}")] CompleteJob(HResultMessage), #[error("Job only partially completed")] PartialComplete, #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } // Cancel Job #[doc(hidden)] #[derive(Clone, Debug)] pub struct CancelJobCommand { pub guid: Guid, } impl CommandType for CancelJobCommand { type Success = (); type Failure = CancelJobFailure; fn wrap(cmd: Self) -> Command { Command::CancelJob(cmd) } } #[derive(Clone, Debug, Error)] pub enum CancelJobFailure { #[error("Job not found")] NotFound, #[error("Get job: {0}")] GetJob(HResultMessage), #[error("Cancel job: {0}")] CancelJob(HResultMessage), #[error("Connect to BackgroundCopyManager: {0}")] ConnectBcm(HResultMessage), #[error("BITS error: {0}")] OtherBITS(HResultMessage), #[error("Other failure: {0}")] Other(String), } /// Job status report /// /// This includes a URL which updates with redirect but is otherwise the same as /// `bits::status::BitsJobStatus`. #[derive(Clone, Debug)] pub struct JobStatus { pub state: BitsJobState, pub progress: BitsJobProgress, pub error_count: u32, pub error: Option, pub times: BitsJobTimes, /// None means same as last time pub url: Option, } /// Job error report #[derive(Clone, Debug, Error)] #[error("Job error in context {context_str}: {error}")] pub struct JobError { pub context: BitsErrorContext, pub context_str: String, pub error: HResultMessage, }