forked from rs-ipfs/rust-ipfs
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmain.rs
203 lines (167 loc) · 7.02 KB
/
main.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
use std::num::NonZeroU16;
use std::path::PathBuf;
use structopt::StructOpt;
use ipfs::{Ipfs, IpfsOptions, IpfsTypes, UninitializedIpfs};
use ipfs_http::{config, v0};
#[macro_use]
extern crate tracing;
#[derive(Debug, StructOpt)]
enum Options {
/// Should initialize the repository (create directories and such). `js-ipfsd-ctl` calls this
/// with two arguments by default, `--bits 1024` and `--profile test`.
Init {
/// Generated key length
#[structopt(long)]
bits: NonZeroU16,
/// List of configuration profiles to apply
#[structopt(long, use_delimiter = true)]
profile: Vec<String>,
},
/// Start the IPFS node in the foreground (not detaching from parent process).
Daemon,
}
fn main() {
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var(
"RUST_LOG",
"ipfs_http=trace,ipfs=trace,bitswap=trace,ipfs_unixfs=trace",
);
}
tracing_subscriber::fmt::init();
let opts = Options::from_args();
println!("Invoked with args: {:?}", opts);
// go-ipfs seems to deduce like this
let home = std::env::var_os("IPFS_PATH")
.map(PathBuf::from)
.or_else(|| {
std::env::var_os("HOME").map(|tilde| {
let mut path = PathBuf::from(tilde);
path.push(".ipfs");
path
})
});
// FIXME: need to process cmdline args here, but trying to understand js-ipfsd-ctl right now a
// bit more.
let home = home.unwrap_or_else(|| {
eprintln!("IPFS_PATH and HOME unset");
std::process::exit(1);
});
let config_path = home.join("config");
let (keypair, listening_addrs) = match opts {
Options::Init { bits, profile } => {
println!("initializing IPFS node at {:?}", home);
if config_path.is_file() {
eprintln!("Error: ipfs configuration file already exists!");
eprintln!("Reinitializing would override your keys.");
std::process::exit(1);
}
let result = config::initialize(&home, bits, profile);
match result {
Ok(_) => {
let (kp, _) = std::fs::File::open(config_path)
.map_err(config::LoadingError::ConfigurationFileOpening)
.and_then(config::load)
.unwrap();
// go-ipfs prints here (in addition to earlier "initializing ..."):
//
// generating {}-bit RSA keypair...done
println!("peer identity: {}", kp.public().into_peer_id());
std::process::exit(0);
}
Err(config::InitializationError::DirectoryCreationFailed(e)) => {
eprintln!("Error: failed to create repository path {:?}: {}", home, e);
std::process::exit(1);
}
Err(config::InitializationError::ConfigCreationFailed(_)) => {
// this can be any number of errors like permission denied but these are the
// strings from go-ipfs
eprintln!("Error: ipfs configuration file already exists!");
eprintln!("Reinitializing would override your keys.");
std::process::exit(1);
}
Err(config::InitializationError::InvalidRsaKeyLength(bits)) => {
eprintln!("Error: --bits out of range [1024, 16384]: {}", bits);
eprintln!("This is a fake version of ipfs cli which does not support much");
std::process::exit(1);
}
Err(config::InitializationError::InvalidProfiles(profiles)) => {
eprintln!("Error: unsupported profile selection: {:?}", profiles);
eprintln!("This is a fake version of ipfs cli which does not support much");
std::process::exit(1);
}
Err(e) => {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
}
Options::Daemon => {
if !config_path.is_file() {
eprintln!("Error: no IPFS repo found in {:?}", home);
eprintln!("please run: 'ipfs init'");
std::process::exit(1);
}
std::fs::File::open(config_path)
.map_err(config::LoadingError::ConfigurationFileOpening)
.and_then(config::load)
.unwrap()
}
};
println!("IPFS_PATH: {:?}", home);
println!("Process id: {}", std::process::id());
// TODO: sigterm should initiate graceful shutdown, second time should shutdown right now
// NOTE: sigkill ... well surely it will stop the process right away
let mut rt = tokio::runtime::Runtime::new().expect("Failed to create event loop");
rt.block_on(async move {
let opts: IpfsOptions = IpfsOptions::new(
home.clone(),
keypair,
Vec::new(),
false,
None,
listening_addrs,
);
let (ipfs, task): (Ipfs<ipfs::Types>, _) = UninitializedIpfs::new(opts, None)
.await
.start()
.await
.expect("Initialization failed");
tokio::spawn(task);
let api_link_file = home.join("api");
let (addr, server) = serve(&ipfs);
// shutdown future will handle signalling the exit
drop(ipfs);
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
// daemon running already. go-ipfs file does not contain newline at the end.
let wrote = tokio::fs::write(&api_link_file, &api_multiaddr)
.await
.is_ok();
println!("API listening on {}", api_multiaddr);
println!("daemon is running");
server.await;
if wrote {
// FIXME: this should probably make sure the contents match what we wrote or do some
// locking on the repo, unsure how go-ipfs locks the fsstore
let _ = tokio::fs::File::create(&api_link_file)
.await
.map_err(|e| info!("Failed to truncate {:?}: {}", api_link_file, e));
}
});
info!("Shutdown complete");
}
fn serve<Types: IpfsTypes>(
ipfs: &Ipfs<Types>,
) -> (std::net::SocketAddr, impl std::future::Future<Output = ()>) {
use tokio::stream::StreamExt;
use warp::Filter;
let (shutdown_tx, mut shutdown_rx) = tokio::sync::mpsc::channel::<()>(1);
let routes = v0::routes(ipfs, shutdown_tx);
let routes = routes.with(warp::log(env!("CARGO_PKG_NAME")));
let ipfs = ipfs.clone();
warp::serve(routes).bind_with_graceful_shutdown(([127, 0, 0, 1], 0), async move {
shutdown_rx.next().await;
info!("Shutdown trigger received; starting shutdown");
ipfs.exit_daemon().await;
})
}