use dev_prefix::*;
use jsonrpc_core::{Error as RpcError, ErrorCode, Params, RpcMethodSync};
use serde_json;
use types::*;
use export::ArtifactData;
use user;
use api::constants;
use api::utils;
use utils::unique_id;
use super::LOCKED;
pub struct CreateArtifacts;
impl RpcMethodSync for CreateArtifacts {
fn call(&self, params: Params) -> result::Result<serde_json::Value, RpcError> {
info!("* CreateArtifacts");
do_cu_call(params, true)
}
}
pub struct ReadArtifacts;
impl RpcMethodSync for ReadArtifacts {
fn call(&self, _: Params) -> result::Result<serde_json::Value, RpcError> {
info!("ReadArtifacts");
let locked = LOCKED.lock().unwrap();
Ok(serde_json::to_value(&locked.project_data).expect("serde"))
}
}
pub struct UpdateArtifacts;
impl RpcMethodSync for UpdateArtifacts {
fn call(&self, params: Params) -> result::Result<serde_json::Value, RpcError> {
info!("* UpdateArtifacts");
do_cu_call(params, false)
}
}
pub struct DeleteArtifacts;
impl RpcMethodSync for DeleteArtifacts {
fn call(&self, params: Params) -> result::Result<serde_json::Value, RpcError> {
info!("* DeleteArtifacts");
let mut locked = LOCKED.lock().unwrap();
if locked.cmd.readonly {
return Err(utils::readonly_error());
}
let delete_ids = match params {
Params::Map(mut dict) => match dict.remove("ids") {
Some(value) => match serde_json::from_value::<HashSet<u64>>(value) {
Ok(i) => Ok(i),
Err(e) => Err(utils::parse_error(&format!("{}", e))),
},
None => Err(utils::invalid_params("missing 'ids' param")),
},
_ => Err(utils::invalid_params("missing 'ids' key")),
}?;
let mut remaining: HashMap<u64, ArtifactData> = {
let mut data_artifacts = locked.project_data.artifacts.clone();
let mut out: HashMap<u64, ArtifactData> = HashMap::new();
for dart in data_artifacts.drain(..) {
let id = dart.id;
if out.insert(id, dart).is_some() {
return Err(RpcError {
code: ErrorCode::InternalError,
message: format!("id exists twice: {}", id),
data: None,
});
}
}
out
};
let mut invalid_ids: Vec<u64> = Vec::new();
for id in delete_ids {
if remaining.remove(&id).is_none() {
invalid_ids.push(id);
}
}
if !invalid_ids.is_empty() {
let data = format!("{}: {:?}", constants::X_IDS_NOT_FOUND, invalid_ids);
return Err(RpcError {
code: constants::SERVER_ERROR,
message: constants::X_IDS_NOT_FOUND.to_string(),
data: Some(serde_json::to_value(data).unwrap()),
});
}
let mut save_artifacts = HashMap::new();
for d in remaining.values() {
let (name, a) = utils::from_data(&locked.project.origin, d)?;
save_artifacts.insert(name, a);
}
let mut new_project = Project {
artifacts: save_artifacts,
..locked.project.clone()
};
process_project(&mut new_project)?;
let new_project_data = new_project.to_data();
let out = serde_json::to_value(&new_project_data).expect("serde");
utils::dump_artifacts(&new_project)?;
locked.project = new_project;
locked.project_data = new_project_data;
Ok(out)
}
}
fn do_cu_call(params: Params, for_create: bool) -> result::Result<serde_json::Value, RpcError> {
let mut locked = LOCKED.lock().unwrap();
if locked.cmd.readonly {
return Err(utils::readonly_error());
}
let updated_artifacts = utils::get_artifacts(params)?;
let new_project = update_project(
&locked.project_data.artifacts,
&locked.project,
&updated_artifacts,
for_create,
)?;
drop(updated_artifacts);
let new_project_data = new_project.to_data();
let out = serde_json::to_value(&new_project_data).expect("serde");
utils::dump_artifacts(&new_project)?;
locked.project = new_project;
locked.project_data = new_project_data;
Ok(out)
}
pub(in api) fn update_project(
data_artifacts: &[ArtifactData],
project: &Project,
new_artifacts: &[ArtifactData],
for_create: bool,
) -> result::Result<Project, RpcError> {
let (unchanged_artifacts, mut save_artifacts) =
utils::split_artifacts(project, data_artifacts, new_artifacts, for_create)?;
for artifact in save_artifacts.values_mut() {
if for_create {
artifact.id = unique_id();
} else {
artifact.revision += 1;
}
}
for art_data in unchanged_artifacts.values() {
let (n, a) = utils::from_data(&project.origin, art_data)?;
save_artifacts.insert(n, a);
}
let mut new_project = Project {
artifacts: save_artifacts,
..project.clone()
};
process_project(&mut new_project)?;
Ok(new_project)
}
fn process_project(project: &mut Project) -> result::Result<(), RpcError> {
if let Err(err) = user::process_project(project) {
Err(RpcError {
code: constants::SERVER_ERROR,
message: err.to_string(),
data: None,
})
} else {
Ok(())
}
}