ring_api/requests/
submit.rs

1//! Submit a job.
2
3use std::borrow::Cow;
4use std::io::Read;
5use std::path::Path;
6use std::ffi::OsStr;
7use std::fs::read_to_string;
8use reqwest::Method;
9use super::{ Request, RequestBody };
10use crate::{
11    settings::Settings,
12    multipart::FormFile,
13    job::{ JobId, JobStatus },
14    error::Result,
15};
16
17/// Submitting a RING job based on a known PDB ID.
18#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
19pub struct SubmitId {
20    /// The PDB ID of the protein to be RING'd.
21    #[serde(rename = "pdbName")]
22    pub pdb_id: String,
23    /// The settings with which to perform the job.
24    #[serde(flatten, default)]
25    pub settings: Settings,
26}
27
28/// Submitting a request based on a PDB structure.
29#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
30pub struct SubmitStructure {
31    /// The contents of the PDB structure itself. Typically comes from a file.
32    #[serde(rename = "file")]
33    pub pdb_structure: FormFile,
34    /// The file name, if any (optional).
35    #[serde(rename = "fileName", default, skip_serializing_if = "Option::is_none")]
36    pub file_name: Option<String>,
37    /// The RING settings.
38    #[serde(flatten, default)]
39    pub settings: Settings,
40}
41
42/// The response from the "submit" endpoint.
43#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
44pub struct SubmitResponse {
45    /// The Job ID which can be used later for querying the results.
46    #[serde(rename = "jobid")]
47    pub job_id: JobId,
48    /// The initially-reported status of the job, usually "in progress".
49    pub status: JobStatus,
50}
51
52impl SubmitId {
53    /// Convenience constructor.
54    /// Creates a submit ID request with the default settings.
55    pub fn with_pdb_id<T: Into<String>>(pdb_id: T) -> Self {
56        SubmitId {
57            pdb_id: pdb_id.into(),
58            settings: Settings::default(),
59        }
60    }
61}
62
63impl SubmitStructure {
64    /// Convenience constructor.
65    /// Creates a submit structure request with the specified structure,
66    /// default settings, and no file name. (Only for the form's
67    /// Content-Disposition, a dummy file name will be used.)
68    pub fn with_pdb_structure<T: Into<String>>(pdb_structure: T) -> Self {
69        SubmitStructure {
70            pdb_structure: FormFile::with_contents_and_file_name(
71                pdb_structure.into(),
72                String::from("rust_ring_api_dummy.pdb"),
73            ),
74            file_name: None,
75            settings: Settings::default(),
76        }
77    }
78
79    /// Convenience constructor.
80    /// Creates a submit structure request from an `io::Read`, with the
81    /// default settings and no file name. (Only for the form's
82    /// Content-Disposition, a dummy file name will be used.)
83    pub fn with_reader<R: Read>(mut reader: R) -> Result<Self> {
84        let mut structure = String::new();
85        reader.read_to_string(&mut structure)?;
86        Ok(Self::with_pdb_structure(structure))
87    }
88
89    /// Convenience constructor.
90    /// Creates a submit structure request from a file, with the
91    /// default settings and the specified file name (if the latter can be
92    /// converted to a UTF-8 string - otherwise, a dummy one will be used).
93    pub fn with_pdb_file<P: AsRef<Path>>(file: P) -> Result<Self> {
94        let path = file.as_ref();
95        let maybe_file_name = path
96            .file_name()
97            .and_then(OsStr::to_str)
98            .map(Into::into);
99        let structure = read_to_string(path)?;
100
101        Ok(SubmitStructure {
102            pdb_structure: FormFile::with_contents_and_file_name(
103                structure,
104                maybe_file_name.clone().unwrap_or_else(
105                    || String::from("rust_ring_api_dummy.pdb")
106                )
107            ),
108            file_name: maybe_file_name,
109            settings: Settings::default(),
110        })
111    }
112
113    /// Builder method for unconditionally setting the file name.
114    pub fn file_name<T: Into<String>>(mut self, file_name: T) -> Self {
115        let file_name = file_name.into();
116
117        self.file_name.replace(file_name.clone());
118        self.pdb_structure.set_file_name(file_name);
119        self
120    }
121
122    /// Builder method for setting the file name only if it does not exist.
123    pub fn or_file_name<T: Into<String>>(self, file_name: T) -> Self {
124        if self.file_name.is_none() {
125            self.file_name(file_name)
126        } else {
127            self
128        }
129    }
130
131    /// Builder method for changing the settings.
132    pub fn settings(self, settings: Settings) -> Self {
133        SubmitStructure { settings, ..self }
134    }
135}
136
137impl Request for SubmitId {
138    type Body = Self;
139    type Response = SubmitResponse;
140
141    const METHOD: Method = Method::POST;
142
143    fn endpoint(&self) -> Cow<str> {
144        Cow::from("/submit")
145    }
146
147    fn body(&self) -> RequestBody<&Self::Body> {
148        RequestBody::Json(self)
149    }
150}
151
152impl Request for SubmitStructure {
153    type Body = Self;
154    type Response = SubmitResponse;
155
156    const METHOD: Method = Method::POST;
157
158    fn endpoint(&self) -> Cow<str> {
159        Cow::from("/submit")
160    }
161
162    fn body(&self) -> RequestBody<&Self::Body> {
163        RequestBody::Multipart(self)
164    }
165}