@@ -24,10 +24,9 @@ extern crate atty;
24
24
extern crate ansi_term;
25
25
extern crate regex;
26
26
extern crate time;
27
+ extern crate fdlimit;
27
28
extern crate futures;
28
29
extern crate tokio;
29
- extern crate ctrlc;
30
- extern crate fdlimit;
31
30
extern crate ed25519;
32
31
extern crate triehash;
33
32
extern crate parking_lot;
@@ -66,6 +65,11 @@ mod informant;
66
65
mod chain_spec;
67
66
68
67
pub use chain_spec:: ChainSpec ;
68
+ pub use client:: error:: Error as ClientError ;
69
+ pub use client:: backend:: Backend as ClientBackend ;
70
+ pub use state_machine:: Backend as StateMachineBackend ;
71
+ pub use polkadot_primitives:: Block as PolkadotBlock ;
72
+ pub use service:: { Components as ServiceComponents , Service } ;
69
73
70
74
use std:: io:: { self , Write , Read , stdin, stdout} ;
71
75
use std:: fs:: File ;
@@ -117,6 +121,26 @@ fn base_path(matches: &clap::ArgMatches) -> PathBuf {
117
121
. unwrap_or_else ( default_base_path)
118
122
}
119
123
124
+ /// Additional worker making use of the node, to run asynchronously before shutdown.
125
+ ///
126
+ /// This will be invoked with the service and spawn a future that resolves
127
+ /// when complete.
128
+ pub trait Worker {
129
+ /// A future that resolves when the work is done or the node should exit.
130
+ /// This will be run on a tokio runtime.
131
+ type Work : Future < Item =( ) , Error =( ) > ;
132
+
133
+ /// An exit scheduled for the future.
134
+ type Exit : Future < Item =( ) , Error =( ) > + Send + ' static ;
135
+
136
+ /// Don't work, but schedule an exit.
137
+ fn exit_only ( self ) -> Self :: Exit ;
138
+
139
+ /// Do work and schedule exit.
140
+ fn work < C : ServiceComponents > ( self , service : & Service < C > ) -> Self :: Work
141
+ where ClientError : From < <<<C as ServiceComponents >:: Backend as ClientBackend < PolkadotBlock > >:: State as StateMachineBackend >:: Error > ;
142
+ }
143
+
120
144
/// Parse command line arguments and start the node.
121
145
///
122
146
/// IANA unassigned port ranges that we could use:
@@ -125,9 +149,10 @@ fn base_path(matches: &clap::ArgMatches) -> PathBuf {
125
149
/// 9556-9591 Unassigned
126
150
/// 9803-9874 Unassigned
127
151
/// 9926-9949 Unassigned
128
- pub fn run < I , T > ( args : I ) -> error:: Result < ( ) > where
152
+ pub fn run < I , T , W > ( args : I , worker : W ) -> error:: Result < ( ) > where
129
153
I : IntoIterator < Item = T > ,
130
154
T : Into < std:: ffi:: OsString > + Clone ,
155
+ W : Worker ,
131
156
{
132
157
let yaml = load_yaml ! ( "./cli.yml" ) ;
133
158
let matches = match clap:: App :: from_yaml ( yaml) . version ( & ( crate_version ! ( ) . to_owned ( ) + "\n " ) [ ..] ) . get_matches_from_safe ( args) {
@@ -154,11 +179,11 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
154
179
}
155
180
156
181
if let Some ( matches) = matches. subcommand_matches ( "export-blocks" ) {
157
- return export_blocks ( matches) ;
182
+ return export_blocks ( matches, worker . exit_only ( ) ) ;
158
183
}
159
184
160
185
if let Some ( matches) = matches. subcommand_matches ( "import-blocks" ) {
161
- return import_blocks ( matches) ;
186
+ return import_blocks ( matches, worker . exit_only ( ) ) ;
162
187
}
163
188
164
189
let spec = load_spec ( & matches) ?;
@@ -255,8 +280,8 @@ pub fn run<I, T>(args: I) -> error::Result<()> where
255
280
} ;
256
281
257
282
match role == service:: Role :: LIGHT {
258
- true => run_until_exit ( & mut runtime, service:: new_light ( config, executor) ?, & matches, sys_conf) ?,
259
- false => run_until_exit ( & mut runtime, service:: new_full ( config, executor) ?, & matches, sys_conf) ?,
283
+ true => run_until_exit ( & mut runtime, service:: new_light ( config, executor) ?, & matches, sys_conf, worker ) ?,
284
+ false => run_until_exit ( & mut runtime, service:: new_full ( config, executor) ?, & matches, sys_conf, worker ) ?,
260
285
}
261
286
262
287
// TODO: hard exit if this stalls?
@@ -272,16 +297,19 @@ fn build_spec(matches: &clap::ArgMatches) -> error::Result<()> {
272
297
Ok ( ( ) )
273
298
}
274
299
275
- fn export_blocks ( matches : & clap:: ArgMatches ) -> error:: Result < ( ) > {
300
+ fn export_blocks < E > ( matches : & clap:: ArgMatches , exit : E ) -> error:: Result < ( ) >
301
+ where E : Future < Item =( ) , Error =( ) > + Send + ' static
302
+ {
276
303
let base_path = base_path ( matches) ;
277
304
let spec = load_spec ( & matches) ?;
278
305
let mut config = service:: Configuration :: default_with_spec ( spec) ;
279
306
config. database_path = db_path ( & base_path) . to_string_lossy ( ) . into ( ) ;
280
307
info ! ( "DB path: {}" , config. database_path) ;
281
308
let client = service:: new_client ( config) ?;
282
- let ( exit_send, exit) = std:: sync:: mpsc:: channel ( ) ;
283
- ctrlc:: CtrlC :: set_handler ( move || {
284
- exit_send. clone ( ) . send ( ( ) ) . expect ( "Error sending exit notification" ) ;
309
+ let ( exit_send, exit_recv) = std:: sync:: mpsc:: channel ( ) ;
310
+ :: std:: thread:: spawn ( move || {
311
+ let _ = exit. wait ( ) ;
312
+ let _ = exit_send. send ( ( ) ) ;
285
313
} ) ;
286
314
info ! ( "Exporting blocks" ) ;
287
315
let mut block: u32 = match matches. value_of ( "from" ) {
@@ -310,7 +338,7 @@ fn export_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
310
338
}
311
339
312
340
loop {
313
- if exit . try_recv ( ) . is_ok ( ) {
341
+ if exit_recv . try_recv ( ) . is_ok ( ) {
314
342
break ;
315
343
}
316
344
match client. block ( & BlockId :: number ( block as u64 ) ) ? {
@@ -334,15 +362,19 @@ fn export_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
334
362
Ok ( ( ) )
335
363
}
336
364
337
- fn import_blocks ( matches : & clap:: ArgMatches ) -> error:: Result < ( ) > {
365
+ fn import_blocks < E > ( matches : & clap:: ArgMatches , exit : E ) -> error:: Result < ( ) >
366
+ where E : Future < Item =( ) , Error =( ) > + Send + ' static
367
+ {
338
368
let spec = load_spec ( & matches) ?;
339
369
let base_path = base_path ( matches) ;
340
370
let mut config = service:: Configuration :: default_with_spec ( spec) ;
341
371
config. database_path = db_path ( & base_path) . to_string_lossy ( ) . into ( ) ;
342
372
let client = service:: new_client ( config) ?;
343
- let ( exit_send, exit) = std:: sync:: mpsc:: channel ( ) ;
344
- ctrlc:: CtrlC :: set_handler ( move || {
345
- exit_send. clone ( ) . send ( ( ) ) . expect ( "Error sending exit notification" ) ;
373
+ let ( exit_send, exit_recv) = std:: sync:: mpsc:: channel ( ) ;
374
+
375
+ :: std:: thread:: spawn ( move || {
376
+ let _ = exit. wait ( ) ;
377
+ let _ = exit_send. send ( ( ) ) ;
346
378
} ) ;
347
379
348
380
let mut file: Box < Read > = match matches. value_of ( "INPUT" ) {
@@ -354,7 +386,7 @@ fn import_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
354
386
let count: u32 = Slicable :: decode ( & mut file) . ok_or ( "Error reading file" ) ?;
355
387
let mut block = 0 ;
356
388
for _ in 0 .. count {
357
- if exit . try_recv ( ) . is_ok ( ) {
389
+ if exit_recv . try_recv ( ) . is_ok ( ) {
358
390
break ;
359
391
}
360
392
match SignedBlock :: decode ( & mut file) {
@@ -377,27 +409,19 @@ fn import_blocks(matches: &clap::ArgMatches) -> error::Result<()> {
377
409
Ok ( ( ) )
378
410
}
379
411
380
- fn run_until_exit < C > ( runtime : & mut Runtime , service : service:: Service < C > , matches : & clap:: ArgMatches , sys_conf : SystemConfiguration ) -> error:: Result < ( ) >
412
+ fn run_until_exit < C , W > (
413
+ runtime : & mut Runtime ,
414
+ service : service:: Service < C > ,
415
+ matches : & clap:: ArgMatches ,
416
+ sys_conf : SystemConfiguration ,
417
+ worker : W ,
418
+ ) -> error:: Result < ( ) >
381
419
where
382
420
C : service:: Components ,
421
+ W : Worker ,
383
422
client:: error:: Error : From < <<<C as service:: Components >:: Backend as client:: backend:: Backend < Block > >:: State as state_machine:: Backend >:: Error > ,
384
423
{
385
- let exit = {
386
- let ( exit_send, exit) = exit_future:: signal ( ) ;
387
- let exit_send = :: std:: cell:: RefCell :: new ( Some ( exit_send) ) ;
388
- ctrlc:: CtrlC :: set_handler ( move || {
389
- let exit_send = exit_send
390
- . try_borrow_mut ( )
391
- . expect ( "only borrowed in non-reetrant signal handler; qed" )
392
- . take ( ) ;
393
-
394
- if let Some ( signal) = exit_send {
395
- signal. fire ( ) ;
396
- }
397
- } ) ;
398
-
399
- exit
400
- } ;
424
+ let ( exit_send, exit) = exit_future:: signal ( ) ;
401
425
402
426
let executor = runtime. executor ( ) ;
403
427
informant:: start ( & service, exit. clone ( ) , executor. clone ( ) ) ;
@@ -422,7 +446,8 @@ fn run_until_exit<C>(runtime: &mut Runtime, service: service::Service<C>, matche
422
446
)
423
447
} ;
424
448
425
- let _ = exit. wait ( ) ;
449
+ let _ = worker. work ( & service) . wait ( ) ;
450
+ exit_send. fire ( ) ;
426
451
Ok ( ( ) )
427
452
}
428
453
0 commit comments