Skip to content
This repository has been archived by the owner on Oct 23, 2022. It is now read-only.

Commit

Permalink
fix(http): introduce Config struct as configuration facade
Browse files Browse the repository at this point in the history
  • Loading branch information
niklaslong committed Oct 29, 2020
1 parent 7c227e3 commit 796ec4b
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 51 deletions.
71 changes: 36 additions & 35 deletions http/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ mod keys_proto {
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
}

/// The facade for the configuration of the API.
pub struct Config {
/// Keypair for the ipfs node
pub keypair: ipfs::Keypair,
/// Peer addresses for the ipfs node
pub swarm: Vec<Multiaddr>,
/// Address to run the API daemon on.
pub api_addr: Multiaddr,
}

/// Defines the configuration types supported by the API.
#[derive(Debug, StructOpt)]
pub enum Profile {
Test,
Expand All @@ -34,7 +45,7 @@ impl FromStr for Profile {
}
}

/// The way things can go wrong when calling [`initialize`].
/// The way things can go wrong when calling [`init`].
#[derive(Error, Debug)]
pub enum InitializationError {
#[error("repository creation failed: {0}")]
Expand All @@ -53,27 +64,13 @@ pub enum InitializationError {
ConfigWritingFailed(serde_json::Error),
}

// Thoughts on config refactor:
//
// 1. The CompatibleConfigFile should be written to the file only once all values have been
// generated (keys, etc...)
// 2. The config API is probably going to just include initialize, though smaller functions could
// be helpers on CompatibleConfigFile.
// 3. Error handling needs to be consitent and well defined.
// 4. When loading the config, CompatibleConfigFile should be passed around instead of the tuples
// currently used.

/// Creates the IPFS_PATH directory structure and creates a new compatible configuration file with
/// RSA key of length `bits`.
/// RSA key of length `bits`. Returns the Peer ID.
pub fn init(
ipfs_path: &Path,
bits: NonZeroU16,
profiles: Vec<Profile>,
) -> Result<CompatibleConfigFile, InitializationError> {
// 1. Create CompatibleConfigFile
// 2. Create file
// 3. Return file?

) -> Result<String, InitializationError> {
use multibase::Base::Base64Pad;
use prost::Message;
use std::io::BufWriter;
Expand Down Expand Up @@ -134,7 +131,7 @@ pub fn init(

let config_contents = CompatibleConfigFile {
identity: Identity {
peer_id,
peer_id: peer_id.clone(),
private_key,
},
addresses: Addresses {
Expand All @@ -154,7 +151,7 @@ pub fn init(
serde_json::to_writer_pretty(BufWriter::new(config_file), &config_contents)
.map_err(InitializationError::ConfigWritingFailed)?;

Ok(config_contents)
Ok(peer_id)
}

/// Things which can go wrong when loading a `go-ipfs` compatible configuration file.
Expand All @@ -177,26 +174,30 @@ pub enum LoadingError {
/// Returns only the keypair and listening addresses or [`LoadingError`] but this should be
/// extended to contain the bootstrap nodes at least later when we need to support those for
/// testing purposes.
pub fn load(config: File) -> Result<CompatibleConfigFile, LoadingError> {
pub fn load(config: File) -> Result<Config, LoadingError> {
use std::io::BufReader;

let config: CompatibleConfigFile = serde_json::from_reader(BufReader::new(config))
let config_file: CompatibleConfigFile = serde_json::from_reader(BufReader::new(config))
.map_err(LoadingError::ConfigurationFileFormat)?;

let kp = config.identity.load_keypair()?;
let kp = config_file.identity.load_keypair()?;

let peer_id = kp.public().into_peer_id().to_string();

if peer_id != config.identity.peer_id {
if peer_id != config_file.identity.peer_id {
return Err(LoadingError::PeerIdMismatch {
loaded: peer_id,
stored: config.identity.peer_id,
stored: config_file.identity.peer_id,
});
}

Ok(config)
let config = Config {
keypair: kp,
swarm: config_file.addresses.swarm,
api_addr: config_file.addresses.api,
};

// Ok((kp, addresses.swarm, addresses.api))
Ok(config)
}

/// Converts a PEM format to DER where PEM is a container for Base64 data with padding, starting on
Expand Down Expand Up @@ -265,30 +266,30 @@ fn pem_to_der(bytes: &[u8]) -> Vec<u8> {

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct CompatibleConfigFile {
pub identity: Identity,
pub addresses: Addresses,
struct CompatibleConfigFile {
identity: Identity,
addresses: Addresses,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Addresses {
pub swarm: Vec<Multiaddr>,
struct Addresses {
swarm: Vec<Multiaddr>,
#[serde(rename = "API")]
pub api: Multiaddr,
api: Multiaddr,
}

#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Identity {
struct Identity {
#[serde(rename = "PeerID")]
pub peer_id: String,
peer_id: String,
#[serde(rename = "PrivKey")]
private_key: String,
}

impl Identity {
pub fn load_keypair(&self) -> Result<ipfs::Keypair, LoadingError> {
fn load_keypair(&self) -> Result<ipfs::Keypair, LoadingError> {
use keys_proto::KeyType;
use multibase::Base::Base64Pad;
use prost::Message;
Expand Down
23 changes: 7 additions & 16 deletions http/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,17 +77,11 @@ fn main() {
let result = config::init(&home, bits, profile);

match result {
Ok(config) => {
// let (kp, _, _) = std::fs::File::open(config_path)
// .map_err(config::LoadingError::ConfigurationFileOpening)
// .and_then(config::load)
// .unwrap();

Ok(peer_id) => {
// go-ipfs prints here (in addition to earlier "initializing ..."):
//
// generating {}-bit RSA keypair...done

println!("peer identity: {}", config.identity.peer_id);
println!("peer identity: {}", peer_id);
std::process::exit(0);
}
Err(config::InitializationError::DirectoryCreationFailed(e)) => {
Expand Down Expand Up @@ -139,19 +133,14 @@ fn main() {

let mut rt = tokio::runtime::Runtime::new().expect("Failed to create event loop");

// Probably want to panic if something isn't right at this point...
let keypair = config.identity.load_keypair().unwrap();
let listening_addrs = config.addresses.swarm;
let api_listening_addr = config.addresses.api;

rt.block_on(async move {
let opts = IpfsOptions {
ipfs_path: home.clone(),
keypair,
keypair: config.keypair,
bootstrap: Vec::new(),
mdns: false,
kad_protocol: None,
listening_addrs,
listening_addrs: config.swarm,
span: None,
};

Expand All @@ -164,11 +153,13 @@ fn main() {

let api_link_file = home.join("api");

let (addr, server) = serve(&ipfs, api_listening_addr);
let (addr, server) = serve(&ipfs, config.api_addr);

// shutdown future will handle signalling the exit
drop(ipfs);

// We can't simply reuse the address from the config as the test profile uses ephemeral
// ports.
let api_multiaddr = format!("/ip4/{}/tcp/{}", addr.ip(), addr.port());

// this file is looked for when js-ipfsd-ctl checks optimistically if the IPFS_PATH has a
Expand Down

0 comments on commit 796ec4b

Please sign in to comment.