netbench/src/scenario.rs (117 lines of code) (raw):

// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 use crate::{operation as op, Result}; use serde::{Deserialize, Serialize}; use std::{collections::BTreeMap, path::Path, sync::Arc}; #[cfg(feature = "builder")] pub mod builder; mod id; #[cfg(feature = "builder")] pub use builder::Builder; pub use id::Id; #[derive(Clone, Debug, Default, Deserialize, Serialize, Hash)] pub struct Scenario { pub id: Id, pub clients: Vec<Arc<Client>>, pub servers: Vec<Arc<Server>>, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub routers: Vec<Arc<Router>>, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub traces: Arc<Vec<String>>, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub certificates: Vec<Arc<Certificate>>, } impl Scenario { #[cfg(feature = "builder")] pub fn build<F: FnOnce(&mut builder::Builder)>(f: F) -> Self { let mut builder = builder::Builder::new(); f(&mut builder); builder.finish() } pub fn open(path: &Path) -> Result<Self> { let file = std::fs::File::open(path)?; let mut file = std::io::BufReader::new(file); let scenario = serde_json::from_reader(&mut file)?; Ok(scenario) } pub fn write<W: std::io::Write>(&self, out: &mut W) -> std::io::Result<()> { serde_json::to_writer(out, self)?; Ok(()) } } #[derive(Clone, Debug, Default, Deserialize, Serialize, Hash)] pub struct Client { #[serde(skip_serializing_if = "String::is_empty", default)] pub name: String, pub scenario: Vec<op::Client>, pub connections: Vec<Arc<Connection>>, #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] pub configuration: BTreeMap<String, String>, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub certificate_authorities: Vec<u64>, } #[derive(Clone, Debug, Default, Deserialize, Serialize, Hash)] pub struct Server { #[serde(skip_serializing_if = "String::is_empty", default)] pub name: String, pub connections: Vec<Arc<Connection>>, #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] pub configuration: BTreeMap<String, String>, pub private_key: u64, pub certificate: u64, pub certificate_authority: u64, } impl Server { pub fn on_server_name(&self, server_name: &str) -> Result<&Arc<Connection>> { let (conn_idx, _) = server_name.split_once('.').ok_or("invalid hostname")?; let conn_idx: usize = conn_idx.parse()?; let conn = self.connections.get(conn_idx).ok_or("invalid connection")?; Ok(conn) } } #[derive(Clone, Debug, Deserialize, Serialize, Hash)] pub struct Connection { #[serde(skip_serializing_if = "Vec::is_empty", default)] pub ops: Vec<op::Connection>, #[serde(skip_serializing_if = "Vec::is_empty", default)] pub peer_streams: Vec<Vec<op::Connection>>, } #[derive(Clone, Debug, Deserialize, Serialize, Hash)] pub struct Router { #[serde(skip_serializing_if = "String::is_empty", default)] pub name: String, pub scenario: Vec<op::Router>, #[serde(skip_serializing_if = "BTreeMap::is_empty", default)] pub configuration: BTreeMap<String, String>, } #[derive(Clone, Debug, Deserialize, Serialize, Hash)] pub struct Certificate { #[serde(skip_serializing_if = "String::is_empty", default)] pub pem: String, #[serde(skip_serializing_if = "Vec::is_empty", with = "pkcs12_format", default)] pub pkcs12: Vec<u8>, } pub(crate) mod pkcs12_format { use serde::{self, Deserialize, Deserializer, Serializer}; pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, { if serializer.is_human_readable() { let out = base64::encode(bytes); serializer.serialize_str(&out) } else { serializer.serialize_bytes(bytes) } } pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error> where D: Deserializer<'de>, { if deserializer.is_human_readable() { let s = String::deserialize(deserializer)?; let out = base64::decode(s).map_err(serde::de::Error::custom)?; Ok(out) } else { Vec::deserialize(deserializer) } } }