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

Commit 73409a8

Browse files
Merge #423
423: http: configuration refactor r=niklaslong a=niklaslong This is a wip but opening as a draft to keep track of this follow up to #421. This is also part of #402. This introduces the `Config` struct to serve as a facade to the configuration module. It's essentially a flattened `CompatibleConfigFile` struct exposing only the fields necessary to running the daemon. Co-authored-by: Niklas Long <[email protected]>
2 parents 83e73ab + eb005bb commit 73409a8

File tree

3 files changed

+72
-58
lines changed

3 files changed

+72
-58
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
# Next
22

3+
* refactor(http): introduce `Config` as the facade for configuration [#423]
34
* feat(http): create `Profile` abstraction [#421]
45

6+
[#423]: https://github.com/rs-ipfs/rust-ipfs/pull/423
57
[#421]: https://github.com/rs-ipfs/rust-ipfs/pull/421
68

79
# 0.2.1

http/src/config.rs

Lines changed: 61 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod keys_proto {
1515
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
1616
}
1717

18+
/// Defines the configuration types supported by the API.
1819
#[derive(Debug, StructOpt)]
1920
pub enum Profile {
2021
Test,
@@ -34,7 +35,7 @@ impl FromStr for Profile {
3435
}
3536
}
3637

37-
/// The way things can go wrong when calling [`initialize`].
38+
/// The way things can go wrong when calling [`init`].
3839
#[derive(Error, Debug)]
3940
pub enum InitializationError {
4041
#[error("repository creation failed: {0}")]
@@ -50,50 +51,29 @@ pub enum InitializationError {
5051
#[error("key encoding failed: {0}")]
5152
PrivateKeyEncodingFailed(prost::EncodeError),
5253
#[error("config serialization failed: {0}")]
53-
ConfigWritingFailed(serde_json::Error),
54+
ConfigWritingFailed(Box<dyn std::error::Error + 'static>),
5455
}
5556

5657
/// Creates the IPFS_PATH directory structure and creates a new compatible configuration file with
57-
/// RSA key of length `bits`.
58-
pub fn initialize(
58+
/// RSA key of length `bits`. Returns the Peer ID.
59+
pub fn init(
5960
ipfs_path: &Path,
6061
bits: NonZeroU16,
6162
profiles: Vec<Profile>,
62-
) -> Result<(), InitializationError> {
63-
// This check is done here to avoid an empty config file being created in the case of an
64-
// unsupported input.
65-
if profiles.len() != 1 {
66-
unimplemented!("Multiple profiles are currently unsupported!");
67-
}
68-
69-
let config_path = ipfs_path.join("config");
70-
71-
fs::create_dir_all(&ipfs_path)
72-
.map_err(InitializationError::DirectoryCreationFailed)
73-
.and_then(|_| {
74-
fs::File::create(&config_path).map_err(InitializationError::ConfigCreationFailed)
75-
})
76-
.and_then(|config_file| create(config_file, bits, profiles))
77-
}
78-
79-
fn create(
80-
config: File,
81-
bits: NonZeroU16,
82-
profiles: Vec<Profile>,
83-
) -> Result<(), InitializationError> {
63+
) -> Result<String, InitializationError> {
8464
use multibase::Base::Base64Pad;
8565
use prost::Message;
86-
use std::io::BufWriter;
66+
use std::fs::OpenOptions;
67+
use std::io::{BufWriter, Write};
8768

88-
let api_addr = match profiles[0] {
89-
Profile::Test => multiaddr!(Ip4([127, 0, 0, 1]), Tcp(0u16)),
90-
Profile::Default => multiaddr!(Ip4([127, 0, 0, 1]), Tcp(4004u16)),
91-
};
69+
if profiles.len() != 1 {
70+
unimplemented!("Multiple profiles are currently unsupported!")
71+
}
9272

9373
let bits = bits.get();
9474

9575
if bits < 2048 || bits > 16 * 1024 {
96-
// ring will not accept a less than 2048 key
76+
// Ring won't accept less than a 2048 bit key.
9777
return Err(InitializationError::InvalidRsaKeyLength(bits));
9878
}
9979

@@ -135,9 +115,14 @@ fn create(
135115

136116
let private_key = Base64Pad.encode(&private_key);
137117

118+
let api_addr = match profiles[0] {
119+
Profile::Test => multiaddr!(Ip4([127, 0, 0, 1]), Tcp(0u16)),
120+
Profile::Default => multiaddr!(Ip4([127, 0, 0, 1]), Tcp(4004u16)),
121+
};
122+
138123
let config_contents = CompatibleConfigFile {
139124
identity: Identity {
140-
peer_id,
125+
peer_id: peer_id.clone(),
141126
private_key,
142127
},
143128
addresses: Addresses {
@@ -146,10 +131,38 @@ fn create(
146131
},
147132
};
148133

149-
serde_json::to_writer_pretty(BufWriter::new(config), &config_contents)
150-
.map_err(InitializationError::ConfigWritingFailed)?;
134+
let config_path = ipfs_path.join("config");
151135

152-
Ok(())
136+
let config_file = fs::create_dir_all(&ipfs_path)
137+
.map_err(InitializationError::DirectoryCreationFailed)
138+
.and_then(|_| {
139+
OpenOptions::new()
140+
.write(true)
141+
.create_new(true)
142+
.open(&config_path)
143+
.map_err(InitializationError::ConfigCreationFailed)
144+
})?;
145+
146+
let mut writer = BufWriter::new(config_file);
147+
148+
serde_json::to_writer_pretty(&mut writer, &config_contents)
149+
.map_err(|e| InitializationError::ConfigWritingFailed(Box::new(e)))?;
150+
151+
writer
152+
.flush()
153+
.map_err(|e| InitializationError::ConfigWritingFailed(Box::new(e)))?;
154+
155+
Ok(peer_id)
156+
}
157+
158+
/// The facade for the configuration of the API.
159+
pub struct Config {
160+
/// Keypair for the ipfs node.
161+
pub keypair: ipfs::Keypair,
162+
/// Peer addresses for the ipfs node.
163+
pub swarm: Vec<Multiaddr>,
164+
/// Address to run the API daemon on.
165+
pub api_addr: Multiaddr,
153166
}
154167

155168
/// Things which can go wrong when loading a `go-ipfs` compatible configuration file.
@@ -172,27 +185,30 @@ pub enum LoadingError {
172185
/// Returns only the keypair and listening addresses or [`LoadingError`] but this should be
173186
/// extended to contain the bootstrap nodes at least later when we need to support those for
174187
/// testing purposes.
175-
pub fn load(config: File) -> Result<(ipfs::Keypair, Vec<Multiaddr>, Multiaddr), LoadingError> {
188+
pub fn load(config: File) -> Result<Config, LoadingError> {
176189
use std::io::BufReader;
177190

178-
let CompatibleConfigFile {
179-
identity,
180-
addresses,
181-
} = serde_json::from_reader(BufReader::new(config))
191+
let config_file: CompatibleConfigFile = serde_json::from_reader(BufReader::new(config))
182192
.map_err(LoadingError::ConfigurationFileFormat)?;
183193

184-
let kp = identity.load_keypair()?;
194+
let kp = config_file.identity.load_keypair()?;
185195

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

188-
if peer_id != identity.peer_id {
198+
if peer_id != config_file.identity.peer_id {
189199
return Err(LoadingError::PeerIdMismatch {
190200
loaded: peer_id,
191-
stored: identity.peer_id,
201+
stored: config_file.identity.peer_id,
192202
});
193203
}
194204

195-
Ok((kp, addresses.swarm, addresses.api))
205+
let config = Config {
206+
keypair: kp,
207+
swarm: config_file.addresses.swarm,
208+
api_addr: config_file.addresses.api,
209+
};
210+
211+
Ok(config)
196212
}
197213

198214
/// Converts a PEM format to DER where PEM is a container for Base64 data with padding, starting on

http/src/main.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn main() {
6363

6464
let config_path = home.join("config");
6565

66-
let (keypair, listening_addrs, api_listening_addr) = match opts {
66+
let config = match opts {
6767
Options::Init { bits, profile } => {
6868
println!("initializing IPFS node at {:?}", home);
6969

@@ -73,20 +73,14 @@ fn main() {
7373
std::process::exit(1);
7474
}
7575

76-
let result = config::initialize(&home, bits, profile);
76+
let result = config::init(&home, bits, profile);
7777

7878
match result {
79-
Ok(_) => {
80-
let (kp, _, _) = std::fs::File::open(config_path)
81-
.map_err(config::LoadingError::ConfigurationFileOpening)
82-
.and_then(config::load)
83-
.unwrap();
84-
79+
Ok(peer_id) => {
8580
// go-ipfs prints here (in addition to earlier "initializing ..."):
8681
//
8782
// generating {}-bit RSA keypair...done
88-
89-
println!("peer identity: {}", kp.public().into_peer_id());
83+
println!("peer identity: {}", peer_id);
9084
std::process::exit(0);
9185
}
9286
Err(config::InitializationError::DirectoryCreationFailed(e)) => {
@@ -141,11 +135,11 @@ fn main() {
141135
rt.block_on(async move {
142136
let opts = IpfsOptions {
143137
ipfs_path: home.clone(),
144-
keypair,
138+
keypair: config.keypair,
145139
bootstrap: Vec::new(),
146140
mdns: false,
147141
kad_protocol: None,
148-
listening_addrs,
142+
listening_addrs: config.swarm,
149143
span: None,
150144
};
151145

@@ -158,11 +152,13 @@ fn main() {
158152

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

161-
let (addr, server) = serve(&ipfs, api_listening_addr);
155+
let (addr, server) = serve(&ipfs, config.api_addr);
162156

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

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

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

0 commit comments

Comments
 (0)