use diesel::prelude::*;
use diesel::sql_types::{Binary, Integer, Nullable, Text};
use std::collections::HashMap;
use std::convert::TryFrom;
use super::{list_services::AdminServiceStoreListServicesOperation, AdminServiceStoreOperations};
use crate::admin::store::{
diesel::{
models::{CircuitMemberModel, CircuitModel, NodeEndpointModel},
schema::{circuit, circuit_member, node_endpoint},
},
error::AdminServiceStoreError,
AuthorizationType, Circuit, CircuitBuilder, CircuitNode, CircuitNodeBuilder, CircuitStatus,
DurabilityType, PersistenceType, RouteType, Service,
};
use crate::error::InvalidStateError;
use crate::public_key::PublicKey;
pub(in crate::admin::store::diesel) trait AdminServiceStoreFetchCircuitOperation {
fn get_circuit(&self, circuit_id: &str) -> Result<Option<Circuit>, AdminServiceStoreError>;
}
impl<'a, C> AdminServiceStoreFetchCircuitOperation for AdminServiceStoreOperations<'a, C>
where
C: diesel::Connection,
String: diesel::deserialize::FromSql<Text, C::Backend>,
i64: diesel::deserialize::FromSql<diesel::sql_types::BigInt, C::Backend>,
i32: diesel::deserialize::FromSql<Integer, C::Backend>,
i16: diesel::deserialize::FromSql<diesel::sql_types::SmallInt, C::Backend>,
CircuitMemberModel: diesel::Queryable<(Text, Text, Integer, Nullable<Binary>), C::Backend>,
{
fn get_circuit(&self, circuit_id: &str) -> Result<Option<Circuit>, AdminServiceStoreError> {
self.conn.transaction::<Option<Circuit>, _, _>(|| {
let circuit: CircuitModel = match circuit::table
.select(circuit::all_columns)
.filter(circuit::circuit_id.eq(circuit_id.to_string()))
.first::<CircuitModel>(self.conn)
.optional()?
{
Some(circuit) => circuit,
None => return Ok(None),
};
let nodes_info: Vec<(CircuitMemberModel, NodeEndpointModel)> = circuit_member::table
.filter(circuit_member::circuit_id.eq(circuit_id.to_string()))
.order(circuit_member::position)
.inner_join(
node_endpoint::table.on(circuit_member::node_id.eq(node_endpoint::node_id)),
)
.load(self.conn)?;
let mut node_map: HashMap<String, Vec<String>> = HashMap::new();
let mut nodes: HashMap<String, CircuitMemberModel> = HashMap::new();
nodes_info.into_iter().for_each(|(node, node_endpoint)| {
if let Some(endpoint_list) = node_map.get_mut(&node.node_id) {
endpoint_list.push(node_endpoint.endpoint);
endpoint_list.sort();
endpoint_list.dedup();
} else {
node_map.insert(node.node_id.to_string(), vec![node_endpoint.endpoint]);
}
if !nodes.contains_key(&node.node_id) {
nodes.insert(node.node_id.to_string(), node);
}
});
let mut nodes_vec: Vec<CircuitMemberModel> =
nodes.into_iter().map(|(_, node)| node).collect();
nodes_vec.sort_by_key(|node| node.position);
let services: Vec<Service> = self.list_services(circuit_id)?.collect();
let circuit_members: Vec<CircuitNode> = nodes_vec
.iter()
.map(|member| {
let mut builder = CircuitNodeBuilder::new().with_node_id(&member.node_id);
if let Some(endpoints) = node_map.get(&member.node_id) {
builder = builder.with_endpoints(endpoints);
}
if let Some(public_key) = &member.public_key {
builder =
builder.with_public_key(&PublicKey::from_bytes(public_key.to_vec()));
}
builder.build()
})
.collect::<Result<Vec<CircuitNode>, InvalidStateError>>()
.map_err(AdminServiceStoreError::InvalidStateError)?;
let mut builder = CircuitBuilder::new()
.with_circuit_id(&circuit.circuit_id)
.with_roster(&services)
.with_members(&circuit_members)
.with_authorization_type(&AuthorizationType::try_from(circuit.authorization_type)?)
.with_persistence(&PersistenceType::try_from(circuit.persistence)?)
.with_durability(&DurabilityType::try_from(circuit.durability)?)
.with_routes(&RouteType::try_from(circuit.routes)?)
.with_circuit_management_type(&circuit.circuit_management_type)
.with_circuit_version(circuit.circuit_version)
.with_circuit_status(&CircuitStatus::from(&circuit.circuit_status));
if let Some(display_name) = circuit.display_name {
builder = builder.with_display_name(&display_name);
}
Ok(Some(
builder
.build()
.map_err(AdminServiceStoreError::InvalidStateError)?,
))
})
}
}