artifact_app/api/
utils.rs1use dev_prefix::*;
2use jsonrpc_core::{Error as RpcError, ErrorCode, Params};
3use serde_json;
4
5use types::*;
6use export::ArtifactData;
7use user;
8use api::constants;
9
10pub fn invalid_params(desc: &str) -> RpcError {
11 RpcError {
12 code: ErrorCode::InvalidParams,
13 message: desc.to_string(),
14 data: None,
15 }
16}
17
18pub fn parse_error(desc: &str) -> RpcError {
19 RpcError {
20 code: ErrorCode::ParseError,
21 message: desc.to_string(),
22 data: None,
23 }
24}
25
26pub fn readonly_error() -> RpcError {
27 RpcError {
28 code: ErrorCode::MethodNotFound,
29 message: "method not available when readonly=true".to_string(),
30 data: None,
31 }
32}
33
34pub fn convert_artifact(
37 origin: &Path,
38 artifact_data: &ArtifactData,
39) -> result::Result<(NameRc, Artifact), String> {
40 Artifact::from_data(origin, artifact_data).map_err(|err| err.to_string())
41}
42
43pub fn get_artifacts(params: Params) -> result::Result<Vec<ArtifactData>, RpcError> {
45 match params {
46 Params::Map(mut dict) => match dict.remove("artifacts") {
47 Some(value) => match serde_json::from_value::<Vec<ArtifactData>>(value) {
48 Ok(a) => Ok(a),
49 Err(e) => Err(parse_error(&format!("{}", e))),
50 },
51 None => Err(invalid_params("missing 'artifacts' param")),
52 },
53 _ => Err(invalid_params("params must have 'artifacts' key")),
54 }
55}
56
57pub fn from_data(
58 origin: &Path,
59 data: &ArtifactData,
60) -> result::Result<(NameRc, Artifact), RpcError> {
61 match convert_artifact(origin, data) {
62 Ok(v) => Ok(v),
63 Err(msg) => {
64 let e = RpcError {
65 code: constants::SERVER_ERROR,
66 message: format!(
67 "Could not convert artifact back {:?}, GOT ERROR: {}",
68 data,
69 msg
70 ),
71 data: None,
72 };
73 Err(e)
74 }
75 }
76}
77
78pub fn dump_artifacts(project: &Project) -> result::Result<(), RpcError> {
79 let text = match user::ProjectText::from_project(project) {
81 Ok(t) => t,
82 Err(e) => {
83 return Err(RpcError {
84 code: ErrorCode::InternalError,
85 message: format!("{}", e.display()),
86 data: None,
87 })
88 }
89 };
90
91 if let Err(e) = text.dump() {
93 return Err(RpcError {
94 code: ErrorCode::InternalError,
95 message: format!("{}", e.display()),
96 data: None,
97 });
98 }
99 Ok(())
100}
101
102#[allow(useless_let_if_seq)]
111pub fn split_artifacts(
112 project: &Project,
113 data_artifacts: &[ArtifactData],
114 new_artifacts: &[ArtifactData],
115 for_create: bool,
116) -> result::Result<(HashMap<u64, ArtifactData>, Artifacts), RpcError> {
117 let mut unchanged_artifacts: HashMap<u64, ArtifactData> =
118 data_artifacts.iter().map(|a| (a.id, a.clone())).collect();
119
120 let mut save_artifacts: Artifacts = Artifacts::new();
121
122 let mut files_not_found: Vec<PathBuf> = Vec::new();
124 let mut invalid_ids: Vec<u64> = Vec::new();
125 let mut invalid_revisions: Vec<u64> = Vec::new();
126 let mut name_errors: Vec<String> = Vec::new();
127 let mut name_overlap: Vec<String> = Vec::new();
128
129 for new_artifact in new_artifacts {
130 let path = project.origin.join(&new_artifact.def);
131 if !project.files.contains(&path) {
132 files_not_found.push(path);
133 }
134 if for_create {
135 if new_artifact.id != 0 {
137 invalid_ids.push(new_artifact.id)
138 }
139 if new_artifact.revision != 0 {
140 invalid_revisions.push(new_artifact.revision)
141 }
142 } else if let Some(a) = unchanged_artifacts.remove(&new_artifact.id) {
143 if new_artifact.revision != a.revision {
146 invalid_revisions.push(new_artifact.revision)
147 }
148 } else {
149 invalid_ids.push(new_artifact.id)
151 }
152 let (name, a) = match convert_artifact(&project.origin, new_artifact) {
153 Ok(v) => v,
154 Err(err) => {
155 name_errors.push(err);
156 continue;
157 }
158 };
159 if save_artifacts.insert(name.clone(), a).is_some() {
160 name_overlap.push(format!("{}", name));
161 }
162 }
163
164 {
166 let mut existing_names: HashSet<NameRc> = HashSet::new();
167 for name in unchanged_artifacts
168 .values()
169 .map(
170 |a| NameRc::from_str(&a.name).unwrap(), )
172 .chain(save_artifacts.keys().cloned())
173 {
174 if !existing_names.insert(name.clone()) {
175 name_overlap.push(format!("{}", name));
176 }
177 }
178 }
179
180 let mut data: HashMap<&str, Vec<String>> = HashMap::new();
182 let mut err = None;
183 if !name_errors.is_empty() {
184 data.insert(constants::X_INVALID_NAME, name_errors);
185 err = Some(constants::X_INVALID_NAME);
186 }
187 if !files_not_found.is_empty() {
188 data.insert(
189 constants::X_FILES_NOT_FOUND,
190 files_not_found
191 .iter()
192 .map(|f| format!("{}", f.display()))
193 .collect(),
194 );
195 err = Some(constants::X_FILES_NOT_FOUND);
196 }
197 if !invalid_ids.is_empty() {
198 let id_strs = invalid_ids.iter().map(u64::to_string).collect();
199 if for_create {
200 data.insert(constants::X_IDS_EXIST, id_strs);
201 err = Some(constants::X_IDS_EXIST);
202 } else {
203 data.insert(constants::X_IDS_NOT_FOUND, id_strs);
204 err = Some(constants::X_IDS_NOT_FOUND);
205 }
206 }
207 if !invalid_revisions.is_empty() {
208 let revision_strs = invalid_revisions.iter().map(u64::to_string).collect();
209 data.insert(constants::X_INVALID_REVISIONS, revision_strs);
210 err = Some(constants::X_INVALID_REVISIONS);
211 }
212 if !name_overlap.is_empty() {
213 data.insert(constants::X_NAMES_OVERLAP, name_overlap);
214 err = Some(constants::X_NAMES_OVERLAP);
215 }
216 if data.len() > 1 {
217 err = Some(constants::X_MULTIPLE_ERRORS);
218 }
219 if let Some(msg) = err {
220 return Err(RpcError {
221 code: constants::SERVER_ERROR,
222 message: msg.to_string(),
223 data: Some(serde_json::to_value(data).unwrap()),
224 });
225 }
226
227 Ok((unchanged_artifacts, save_artifacts))
228}