Browse Source

CoinDaemon: move non-coin-specific methods to new Daemon superclass

The MMGen Project 5 years ago
parent
commit
e33d56c09e
1 changed files with 113 additions and 112 deletions
  1. 113 112
      mmgen/daemon.py

+ 113 - 112
mmgen/daemon.py

@@ -26,10 +26,120 @@ from collections import namedtuple
 from mmgen.exception import *
 from mmgen.common import *
 
-class CoinDaemon(MMGenObject):
-	cfg_file_hdr = ''
+class Daemon(MMGenObject):
 
 	subclasses_must_implement = ('state','stop_cmd')
+	debug = False
+	wait = True
+	use_pidfile = True
+	conf_file = None
+
+	def subclass_init(self): pass
+
+	def exec_cmd_thread(self,cmd,check):
+		import threading
+		t = threading.Thread(target=self.exec_cmd,args=(cmd,check))
+		t.daemon = True
+		t.start()
+		Msg_r(' \b') # blocks w/o this...crazy
+
+	def exec_cmd(self,cmd,check):
+		cp = run(cmd,check=False,stdout=PIPE,stderr=PIPE)
+		if check and cp.returncode != 0:
+			raise MMGenCalledProcessError(cp)
+		return cp
+
+	def run_cmd(self,cmd,silent=False,check=True,is_daemon=False):
+		if is_daemon and not silent:
+			msg('Starting {} {}'.format(self.net_desc,self.desc))
+
+		if self.debug:
+			msg('\nExecuting: {}'.format(' '.join(cmd)))
+
+		if self.platform == 'win' and is_daemon:
+			cp = self.exec_cmd_thread(cmd,check)
+		else:
+			cp = self.exec_cmd(cmd,check)
+		if cp:
+			out = cp.stdout.decode().rstrip()
+			err = cp.stderr.decode().rstrip()
+			if out and (self.debug or not silent):
+				msg(out)
+			if err and (self.debug or (cp.returncode and not silent)):
+				msg(err)
+
+		return cp
+
+	@property
+	def pid(self):
+		return open(self.pidfile).read().strip() if self.use_pidfile else '(unknown)'
+
+	def cmd(self,action,*args,**kwargs):
+		return getattr(self,action)(*args,**kwargs)
+
+	def do_start(self,silent=False):
+		if not silent:
+			msg('Starting {} {}'.format(self.net_desc,self.desc))
+		return self.run_cmd(self.start_cmd,silent=True,is_daemon=True)
+
+	def do_stop(self,silent=False):
+		if not silent:
+			msg('Stopping {} {}'.format(self.net_desc,self.desc))
+		return self.run_cmd(self.stop_cmd,silent=True)
+
+	def cli(self,*cmds,silent=False,check=True):
+		return self.run_cmd(self.cli_cmd(*cmds),silent=silent,check=check)
+
+	def start(self,silent=False):
+		if self.is_ready:
+			if not silent:
+				m = '{} {} already running with pid {}'
+				msg(m.format(self.net_desc,self.desc,self.pid))
+		else:
+			os.makedirs(self.datadir,exist_ok=True)
+			if self.conf_file:
+				open('{}/{}'.format(self.datadir,self.conf_file),'w').write(self.cfg_file_hdr)
+			if self.use_pidfile and os.path.exists(self.pidfile):
+				# Parity just overwrites the data in an existing pidfile, leading to
+				# interesting consequences.
+				os.unlink(self.pidfile)
+			ret = self.do_start(silent=silent)
+			if self.wait:
+				self.wait_for_state('ready')
+			return ret
+
+	def stop(self,silent=False):
+		if self.is_ready:
+			ret = self.do_stop(silent=silent)
+			if self.wait:
+				self.wait_for_state('stopped')
+			return ret
+		else:
+			if not silent:
+				msg('{} {} not running'.format(self.net_desc,self.desc))
+		# rm -rf $datadir
+
+	def wait_for_state(self,req_state):
+		for i in range(200):
+			if self.state == req_state:
+				return True
+			time.sleep(0.2)
+		else:
+			die(2,'Daemon wait timeout for {} {} exceeded'.format(self.coin,self.network))
+
+	@property
+	def is_ready(self):
+		return self.state == 'ready'
+
+	@classmethod
+	def check_implement(cls):
+		m = 'required method {}() missing in class {}'
+		for subcls in cls.__subclasses__():
+			for k in cls.subclasses_must_implement:
+				assert k in subcls.__dict__, m.format(k,subcls.__name__)
+
+class CoinDaemon(Daemon):
+	cfg_file_hdr = ''
 
 	network_ids = ('btc','btc_tn','btc_rt','bch','bch_tn','bch_rt','ltc','ltc_tn','ltc_rt','xmr','eth','etc')
 
@@ -43,12 +153,7 @@ class CoinDaemon(MMGenObject):
 		'etc': cd('Ethereum Classic','parity',      'parity',      'parity.conf',   8545,None,None)
 	}
 
-	debug = False
-	wait = True
-	use_pidfile = True
-
 	testnet_arg = []
-
 	coind_args = []
 	cli_args = []
 	shared_args = []
@@ -70,7 +175,7 @@ class CoinDaemon(MMGenObject):
 			rel_datadir = os.path.join('test','daemons')
 			desc = 'test suite daemon'
 		elif not network_id.endswith('_rt'):
-			raise RuntimeError('only test suite and regtest supported')
+			raise RuntimeError('only test suite and regtest supported for CoinDaemon')
 
 		if network_id.endswith('_tn'):
 			daemon_id = network_id[:-3]
@@ -122,49 +227,6 @@ class CoinDaemon(MMGenObject):
 		self.net_desc = '{} {}'.format(self.coin,self.network)
 		self.subclass_init()
 
-	def subclass_init(self): pass
-
-	def exec_cmd_thread(self,cmd,check):
-		import threading
-		t = threading.Thread(target=self.exec_cmd,args=(cmd,check))
-		t.daemon = True
-		t.start()
-		Msg_r(' \b') # blocks w/o this...crazy
-
-	def exec_cmd(self,cmd,check):
-		cp = run(cmd,check=False,stdout=PIPE,stderr=PIPE)
-		if check and cp.returncode != 0:
-			raise MMGenCalledProcessError(cp)
-		return cp
-
-	def run_cmd(self,cmd,silent=False,check=True,is_daemon=False):
-		if is_daemon and not silent:
-			msg('Starting {} {}'.format(self.net_desc,self.desc))
-
-		if self.debug:
-			msg('\nExecuting: {}'.format(' '.join(cmd)))
-
-		if self.platform == 'win' and is_daemon:
-			cp = self.exec_cmd_thread(cmd,check)
-		else:
-			cp = self.exec_cmd(cmd,check)
-		if cp:
-			out = cp.stdout.decode().rstrip()
-			err = cp.stderr.decode().rstrip()
-			if out and (self.debug or not silent):
-				msg(out)
-			if err and (self.debug or (cp.returncode and not silent)):
-				msg(err)
-
-		return cp
-
-	@property
-	def pid(self):
-		return open(self.pidfile).read().strip() if self.use_pidfile else '(unknown)'
-
-	def cmd(self,action,*args,**kwargs):
-		return getattr(self,action)(*args,**kwargs)
-
 	@property
 	def start_cmd(self):
 		return ([self.coind_exec]
@@ -188,67 +250,6 @@ class CoinDaemon(MMGenObject):
 				+ self.usr_shared_args
 				+ list(cmds))
 
-	def do_start(self,silent=False):
-		if not silent:
-			msg('Starting {} {}'.format(self.net_desc,self.desc))
-		return self.run_cmd(self.start_cmd,silent=True,is_daemon=True)
-
-	def do_stop(self,silent=False):
-		if not silent:
-			msg('Stopping {} {}'.format(self.net_desc,self.desc))
-		return self.run_cmd(self.stop_cmd,silent=True)
-
-	def cli(self,*cmds,silent=False,check=True):
-		return self.run_cmd(self.cli_cmd(*cmds),silent=silent,check=check)
-
-	def start(self,silent=False):
-		if self.is_ready:
-			if not silent:
-				m = '{} {} already running with pid {}'
-				msg(m.format(self.net_desc,self.desc,self.pid))
-		else:
-			os.makedirs(self.datadir,exist_ok=True)
-			if self.conf_file:
-				open('{}/{}'.format(self.datadir,self.conf_file),'w').write(self.cfg_file_hdr)
-			if self.use_pidfile and os.path.exists(self.pidfile):
-				# Parity just overwrites the data in an existing pidfile, leading to
-				# interesting consequences.
-				os.unlink(self.pidfile)
-			ret = self.do_start(silent=silent)
-			if self.wait:
-				self.wait_for_state('ready')
-			return ret
-
-	def stop(self,silent=False):
-		if self.is_ready:
-			ret = self.do_stop(silent=silent)
-			if self.wait:
-				self.wait_for_state('stopped')
-			return ret
-		else:
-			if not silent:
-				msg('{} {} not running'.format(self.net_desc,self.desc))
-		# rm -rf $datadir
-
-	def wait_for_state(self,req_state):
-		for i in range(200):
-			if self.state == req_state:
-				return True
-			time.sleep(0.2)
-		else:
-			die(2,'Daemon wait timeout for {} {} exceeded'.format(self.coin,self.network))
-
-	@property
-	def is_ready(self):
-		return self.state == 'ready'
-
-	@classmethod
-	def check_implement(cls):
-		m = 'required method {}() missing in class {}'
-		for subcls in cls.__subclasses__():
-			for k in cls.subclasses_must_implement:
-				assert k in subcls.__dict__, m.format(k,subcls.__name__)
-
 class BitcoinDaemon(CoinDaemon):
 	cfg_file_hdr = '# BitcoinDaemon config file\n'