From 31db321814810a484c6ad3be0e4795ec4e83d586 Mon Sep 17 00:00:00 2001
From: Arkadiy Paronyan <arkady.paronyan@gmail.com>
Date: Sat, 28 Jul 2018 08:31:16 +0200
Subject: [PATCH] Exit signal gets its own trait (#433)

* Exit signal gets its own trait

* Typo

* Removed clone bounds
---
 substrate/polkadot/cli/src/lib.rs      | 14 ++++----------
 substrate/polkadot/collator/src/lib.rs | 19 ++++++++++++-------
 substrate/polkadot/src/main.rs         | 14 ++++++++------
 substrate/substrate/cli/src/lib.rs     | 22 +++++++++++++++-------
 4 files changed, 39 insertions(+), 30 deletions(-)

diff --git a/substrate/polkadot/cli/src/lib.rs b/substrate/polkadot/cli/src/lib.rs
index ba29a39ecce..b2da24ee103 100644
--- a/substrate/polkadot/cli/src/lib.rs
+++ b/substrate/polkadot/cli/src/lib.rs
@@ -38,7 +38,7 @@ use chain_spec::ChainSpec;
 use futures::Future;
 use tokio::runtime::Runtime;
 pub use service::{Components as ServiceComponents, Service, CustomConfiguration};
-pub use cli::VersionInfo;
+pub use cli::{VersionInfo, IntoExit};
 
 fn load_spec(id: &str) -> Result<Option<service::ChainSpec>, String> {
 	Ok(match ChainSpec::from(id) {
@@ -51,22 +51,16 @@ fn load_spec(id: &str) -> Result<Option<service::ChainSpec>, String> {
 ///
 /// This will be invoked with the service and spawn a future that resolves
 /// when complete.
-pub trait Worker {
+pub trait Worker: IntoExit {
 	/// A future that resolves when the work is done or the node should exit.
 	/// This will be run on a tokio runtime.
 	type Work: Future<Item=(),Error=()> + Send + 'static;
 
-	/// An exit scheduled for the future.
-	type Exit: Future<Item=(),Error=()> + Send + 'static;
-
 	/// Return configuration for the polkadot node.
 	// TODO: make this the full configuration, so embedded nodes don't need
 	// string CLI args
 	fn configuration(&self) -> service::CustomConfiguration { Default::default() }
 
-	/// Don't work, but schedule an exit.
-	fn exit_only(&self) -> Self::Exit;
-
 	/// Do work and schedule exit.
 	fn work<C: service::Components>(self, service: &service::Service<C>) -> Self::Work;
 }
@@ -85,9 +79,9 @@ pub fn run<I, T, W>(args: I, worker: W, version: cli::VersionInfo) -> error::Res
 	W: Worker,
 {
 
-	match cli::prepare_execution::<service::Factory, _, _, _, _>(args, worker.exit_only(), version, load_spec, "parity-polkadot")? {
+	match cli::prepare_execution::<service::Factory, _, _, _, _>(args, worker, version, load_spec, "parity-polkadot")? {
 		cli::Action::ExecutedInternally => (),
-		cli::Action::RunService(mut config) => {
+		cli::Action::RunService((mut config, worker)) => {
 			info!("Parity ·:· Polkadot");
 			info!("  version {}", config.full_version());
 			info!("  by Parity Technologies, 2017, 2018");
diff --git a/substrate/polkadot/collator/src/lib.rs b/substrate/polkadot/collator/src/lib.rs
index 0acee408b68..37428495d9d 100644
--- a/substrate/polkadot/collator/src/lib.rs
+++ b/substrate/polkadot/collator/src/lib.rs
@@ -69,7 +69,7 @@ use polkadot_api::PolkadotApi;
 use polkadot_primitives::{AccountId, BlockId, SessionKey};
 use polkadot_primitives::parachain::{self, BlockData, DutyRoster, HeadData, ConsolidatedIngress, Message, Id as ParaId};
 use polkadot_cli::{ServiceComponents, Service, CustomConfiguration, VersionInfo};
-use polkadot_cli::Worker;
+use polkadot_cli::{Worker, IntoExit};
 use tokio::timer::Deadline;
 
 const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
@@ -211,12 +211,21 @@ struct CollationNode<P, E> {
 	key: Arc<ed25519::Pair>,
 }
 
+impl<P, E> IntoExit for CollationNode<P, E> where
+	P: ParachainContext + Send + 'static,
+	E: Future<Item=(),Error=()> + Send + 'static
+{
+	type Exit = E;
+	fn into_exit(self) -> Self::Exit {
+		self.exit
+	}
+}
+
 impl<P, E> Worker for CollationNode<P, E> where
 	P: ParachainContext + Send + 'static,
-	E: Future<Item=(),Error=()> + Send + Clone + 'static
+	E: Future<Item=(),Error=()> + Send + 'static
 {
 	type Work = Box<Future<Item=(),Error=()> + Send>;
-	type Exit = E;
 
 	fn configuration(&self) -> CustomConfiguration {
 		let mut config = CustomConfiguration::default();
@@ -227,10 +236,6 @@ impl<P, E> Worker for CollationNode<P, E> where
 		config
 	}
 
-	fn exit_only(&self) -> Self::Exit {
-		self.exit.clone()
-	}
-
 	fn work<C: ServiceComponents>(self, service: &Service<C>) -> Self::Work {
 		let CollationNode { parachain_context, exit, para_id, key } = self;
 		let client = service.client();
diff --git a/substrate/polkadot/src/main.rs b/substrate/polkadot/src/main.rs
index 4e3fba054f9..d3e951596e2 100644
--- a/substrate/polkadot/src/main.rs
+++ b/substrate/polkadot/src/main.rs
@@ -38,11 +38,9 @@ mod vergen {
 
 // the regular polkadot worker simply does nothing until ctrl-c
 struct Worker;
-impl cli::Worker for Worker {
-	type Work = Self::Exit;
+impl cli::IntoExit for Worker {
 	type Exit = future::MapErr<oneshot::Receiver<()>, fn(oneshot::Canceled) -> ()>;
-
-	fn exit_only(&self) -> Self::Exit {
+	fn into_exit(self) -> Self::Exit {
 		// can't use signal directly here because CtrlC takes only `Fn`.
 		let (exit_send, exit) = oneshot::channel();
 
@@ -55,9 +53,13 @@ impl cli::Worker for Worker {
 
 		exit.map_err(drop)
 	}
+}
 
-	fn work<C: ServiceComponents>(self, _service: &Service<C>) -> Self::Exit {
-		self.exit_only()
+impl cli::Worker for Worker {
+	type Work = <Self as cli::IntoExit>::Exit;
+	fn work<C: ServiceComponents>(self, _service: &Service<C>) -> Self::Work {
+		use cli::IntoExit;
+		self.into_exit()
 	}
 }
 
diff --git a/substrate/substrate/cli/src/lib.rs b/substrate/substrate/cli/src/lib.rs
index 4feeb711f37..324121073ea 100644
--- a/substrate/substrate/cli/src/lib.rs
+++ b/substrate/substrate/cli/src/lib.rs
@@ -85,11 +85,19 @@ pub struct VersionInfo {
 }
 
 /// CLI Action
-pub enum Action<F: ServiceFactory> {
+pub enum Action<F: ServiceFactory, E: IntoExit> {
 	/// Substrate handled the command. No need to do anything.
 	ExecutedInternally,
 	/// Service mode requested. Caller should start the service.
-	RunService(FactoryFullConfiguration<F>),
+	RunService((FactoryFullConfiguration<F>, E)),
+}
+
+/// Something that can be converted into an exit signal.
+pub trait IntoExit {
+	/// Exit signal type.
+	type Exit: Future<Item=(),Error=()> + Send + 'static;
+	/// Convert into exit signal.
+	fn into_exit(self) -> Self::Exit;
 }
 
 fn load_spec<F, G>(matches: &clap::ArgMatches, factory: F) -> Result<ChainSpec<G>, String>
@@ -146,11 +154,11 @@ pub fn prepare_execution<F, I, T, E, S>(
 	version: VersionInfo,
 	spec_factory: S,
 	impl_name: &'static str,
-) -> error::Result<Action<F>>
+) -> error::Result<Action<F, E>>
 where
 	I: IntoIterator<Item = T>,
 	T: Into<std::ffi::OsString> + Clone,
-	E: Future<Item=(),Error=()> + Send + 'static,
+	E: IntoExit,
 	F: ServiceFactory,
 	S: FnOnce(&str) -> Result<Option<ChainSpec<FactoryGenesis<F>>>, String>,
 {
@@ -182,13 +190,13 @@ where
 
 	if let Some(matches) = matches.subcommand_matches("export-blocks") {
 		let spec = load_spec(&matches, spec_factory)?;
-		export_blocks::<F, _>(matches, spec, exit)?;
+		export_blocks::<F, _>(matches, spec, exit.into_exit())?;
 		return Ok(Action::ExecutedInternally);
 	}
 
 	if let Some(matches) = matches.subcommand_matches("import-blocks") {
 		let spec = load_spec(&matches, spec_factory)?;
-		import_blocks::<F, _>(matches, spec, exit)?;
+		import_blocks::<F, _>(matches, spec, exit.into_exit())?;
 		return Ok(Action::ExecutedInternally);
 	}
 
@@ -298,7 +306,7 @@ where
 		config.telemetry_url = Some(url.to_owned());
 	}
 
-	Ok(Action::RunService(config))
+	Ok(Action::RunService((config, exit)))
 }
 
 fn build_spec<F>(matches: &clap::ArgMatches, spec: ChainSpec<FactoryGenesis<F>>) -> error::Result<()>
-- 
GitLab