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

Commit ded7549

Browse files
committed
fix(http): create Profile abstraction to allow port choice
1 parent e3e1cc2 commit ded7549

File tree

2 files changed

+58
-25
lines changed

2 files changed

+58
-25
lines changed

http/src/config.rs

Lines changed: 41 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@
33
use parity_multiaddr::Multiaddr;
44
use serde::{Deserialize, Serialize};
55
use std::fs::{self, File};
6+
use std::net::SocketAddr;
67
use std::num::NonZeroU16;
78
use std::path::Path;
9+
use std::str::FromStr;
10+
use structopt::StructOpt;
811
use thiserror::Error;
912

1013
/// Temporary module required to de/ser config files base64'd protobuf rsa private key format.
@@ -13,6 +16,24 @@ mod keys_proto {
1316
include!(concat!(env!("OUT_DIR"), "/keys_proto.rs"));
1417
}
1518

19+
#[derive(Debug, StructOpt)]
20+
pub enum Profile {
21+
Test,
22+
Default,
23+
}
24+
25+
impl FromStr for Profile {
26+
type Err = InitializationError;
27+
28+
fn from_str(profile: &str) -> Result<Self, Self::Err> {
29+
match profile {
30+
"test" => Ok(Profile::Test),
31+
"default" => Ok(Profile::Default),
32+
_ => Err(InitializationError::InvalidProfile(profile.to_string())),
33+
}
34+
}
35+
}
36+
1637
/// The way things can go wrong when calling [`initialize`].
1738
#[derive(Error, Debug)]
1839
pub enum InitializationError {
@@ -23,7 +44,7 @@ pub enum InitializationError {
2344
#[error("invalid RSA key length given: {0}")]
2445
InvalidRsaKeyLength(u16),
2546
#[error("unsupported profiles selected: {0:?}")]
26-
InvalidProfiles(Vec<String>),
47+
InvalidProfile(String),
2748
#[error("key generation failed: {0}")]
2849
KeyGeneration(Box<dyn std::error::Error + 'static>),
2950
#[error("key encoding failed: {0}")]
@@ -37,7 +58,7 @@ pub enum InitializationError {
3758
pub fn initialize(
3859
ipfs_path: &Path,
3960
bits: NonZeroU16,
40-
profiles: Vec<String>,
61+
profile: Profile,
4162
) -> Result<(), InitializationError> {
4263
let config_path = ipfs_path.join("config");
4364

@@ -46,14 +67,10 @@ pub fn initialize(
4667
.and_then(|_| {
4768
fs::File::create(&config_path).map_err(InitializationError::ConfigCreationFailed)
4869
})
49-
.and_then(|config_file| create(config_file, bits, profiles))
70+
.and_then(|config_file| create(config_file, bits, profile))
5071
}
5172

52-
fn create(
53-
config: File,
54-
bits: NonZeroU16,
55-
profiles: Vec<String>,
56-
) -> Result<(), InitializationError> {
73+
fn create(config: File, bits: NonZeroU16, profile: Profile) -> Result<(), InitializationError> {
5774
use multibase::Base::Base64Pad;
5875
use prost::Message;
5976
use std::io::BufWriter;
@@ -65,13 +82,18 @@ fn create(
6582
return Err(InitializationError::InvalidRsaKeyLength(bits));
6683
}
6784

68-
if profiles.len() != 1 || profiles[0] != "test" {
69-
// profiles are expected to be (comma separated) "test" as there are no bootstrap peer
70-
// handling yet. the conformance test cases seem to init `go-ipfs` in this profile where
71-
// it does not have any bootstrap nodes, and multi node tests later call swarm apis to
72-
// dial the nodes together.
73-
return Err(InitializationError::InvalidProfiles(profiles));
74-
}
85+
// if profiles.len() != 1 || profiles[0] != "test" || profiles[0] != "default" {
86+
// // profiles are expected to be (comma separated) "test" as there are no bootstrap peer
87+
// // handling yet. the conformance test cases seem to init `go-ipfs` in this profile where
88+
// // it does not have any bootstrap nodes, and multi node tests later call swarm apis to
89+
// // dial the nodes together.
90+
// return Err(InitializationError::InvalidProfile(profiles));
91+
// }
92+
93+
let api_addrs = match profile {
94+
Profile::Test => "127.0.0.1:0",
95+
Profile::Default => "127.0.0.1:4004",
96+
};
7597

7698
let pk = openssl::rsa::Rsa::generate(bits as u32)
7799
.map_err(|e| InitializationError::KeyGeneration(Box::new(e)))?;
@@ -118,6 +140,7 @@ fn create(
118140
},
119141
addresses: Addresses {
120142
swarm: vec!["/ip4/127.0.0.1/tcp/0".parse().unwrap()],
143+
api: api_addrs.parse().unwrap(),
121144
},
122145
};
123146

@@ -147,7 +170,7 @@ pub enum LoadingError {
147170
/// Returns only the keypair and listening addresses or [`LoadingError`] but this should be
148171
/// extended to contain the bootstrap nodes at least later when we need to support those for
149172
/// testing purposes.
150-
pub fn load(config: File) -> Result<(ipfs::Keypair, Vec<Multiaddr>), LoadingError> {
173+
pub fn load(config: File) -> Result<(ipfs::Keypair, Vec<Multiaddr>, SocketAddr), LoadingError> {
151174
use std::io::BufReader;
152175

153176
let CompatibleConfigFile {
@@ -167,7 +190,7 @@ pub fn load(config: File) -> Result<(ipfs::Keypair, Vec<Multiaddr>), LoadingErro
167190
});
168191
}
169192

170-
Ok((kp, addresses.swarm))
193+
Ok((kp, addresses.swarm, addresses.api))
171194
}
172195

173196
/// Converts a PEM format to DER where PEM is a container for Base64 data with padding, starting on
@@ -245,6 +268,7 @@ struct CompatibleConfigFile {
245268
#[serde(rename_all = "PascalCase")]
246269
struct Addresses {
247270
swarm: Vec<Multiaddr>,
271+
api: SocketAddr,
248272
}
249273

250274
#[derive(Debug, Serialize, Deserialize)]

http/src/main.rs

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ enum Options {
1717
#[structopt(long)]
1818
bits: NonZeroU16,
1919
/// List of configuration profiles to apply
20-
#[structopt(long, use_delimiter = true)]
21-
profile: Vec<String>,
20+
#[structopt(long)]
21+
profile: config::Profile,
2222
},
2323
/// Start the IPFS node in the foreground (not detaching from parent process).
2424
Daemon,
@@ -59,7 +59,7 @@ fn main() {
5959

6060
let config_path = home.join("config");
6161

62-
let (keypair, listening_addrs) = match opts {
62+
let (keypair, listening_addrs, api_listening_addrs) = match opts {
6363
Options::Init { bits, profile } => {
6464
println!("initializing IPFS node at {:?}", home);
6565

@@ -73,7 +73,7 @@ fn main() {
7373

7474
match result {
7575
Ok(_) => {
76-
let (kp, _) = std::fs::File::open(config_path)
76+
let (kp, _, _) = std::fs::File::open(config_path)
7777
.map_err(config::LoadingError::ConfigurationFileOpening)
7878
.and_then(config::load)
7979
.unwrap();
@@ -101,8 +101,8 @@ fn main() {
101101
eprintln!("This is a fake version of ipfs cli which does not support much");
102102
std::process::exit(1);
103103
}
104-
Err(config::InitializationError::InvalidProfiles(profiles)) => {
105-
eprintln!("Error: unsupported profile selection: {:?}", profiles);
104+
Err(config::InitializationError::InvalidProfile(profile)) => {
105+
eprintln!("Error: unsupported profile selection: {:?}", profile);
106106
eprintln!("This is a fake version of ipfs cli which does not support much");
107107
std::process::exit(1);
108108
}
@@ -153,7 +153,13 @@ fn main() {
153153
tokio::spawn(task);
154154

155155
let api_link_file = home.join("api");
156-
let (addr, server) = serve(&ipfs);
156+
157+
// If the port is specified, use that to start the server, if it isn't use ephemeral ports,
158+
// i.e.:
159+
//
160+
// port => port
161+
// none => 0
162+
let (addr, server) = serve(&ipfs, api_listening_addrs);
157163

158164
// shutdown future will handle signalling the exit
159165
drop(ipfs);
@@ -185,6 +191,7 @@ fn main() {
185191

186192
fn serve<Types: IpfsTypes>(
187193
ipfs: &Ipfs<Types>,
194+
listening_addrs: std::net::SocketAddr,
188195
) -> (std::net::SocketAddr, impl std::future::Future<Output = ()>) {
189196
use tokio::stream::StreamExt;
190197
use warp::Filter;
@@ -195,7 +202,9 @@ fn serve<Types: IpfsTypes>(
195202

196203
let ipfs = ipfs.clone();
197204

198-
warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 0), async move {
205+
println!("SOCKET_ADDR: {:?}", listening_addrs);
206+
207+
warp::serve(routes).bind_with_graceful_shutdown(listening_addrs, async move {
199208
shutdown_rx.next().await;
200209
info!("Shutdown trigger received; starting shutdown");
201210
ipfs.exit_daemon().await;

0 commit comments

Comments
 (0)