import subprocess import time import shutil import signal import os from collections import namedtuple import re import sys from testUtils import Utils Wallet=namedtuple("Wallet", "name password host port") # pylint: disable=too-many-instance-attributes class WalletMgr(object): __walletLogOutFile="test_keosd_out.log" __walletLogErrFile="test_keosd_err.log" __walletDataDir="test_wallet_0" __MaxPort=9999 # pylint: disable=too-many-arguments # walletd [True|False] True=Launch wallet(keosd) process; False=Manage launch process externally. def __init__(self, walletd, nodeosPort=8888, nodeosHost="localhost", port=9899, host="localhost"): self.walletd=walletd self.nodeosPort=nodeosPort self.nodeosHost=nodeosHost self.port=port self.host=host self.wallets={} self.__walletPid=None def getWalletEndpointArgs(self): if not self.walletd or not self.isLaunched(): return "" return " --wallet-url http://%s:%d" % (self.host, self.port) def getArgs(self): return " --url http://%s:%d%s %s" % (self.nodeosHost, self.nodeosPort, self.getWalletEndpointArgs(), Utils.MiscEosClientArgs) def isLaunched(self): return self.__walletPid is not None def isLocal(self): return self.host=="localhost" or self.host=="127.0.0.1" def findAvailablePort(self): for i in range(WalletMgr.__MaxPort): port=self.port+i if port > WalletMgr.__MaxPort: port-=WalletMgr.__MaxPort if Utils.arePortsAvailable(port): return port if Utils.Debug: Utils.Print("Port %d not available for %s" % (port, Utils.EosWalletPath)) Utils.errorExit("Failed to find free port to use for %s" % (Utils.EosWalletPath)) def launch(self): if not self.walletd: Utils.Print("ERROR: Wallet Manager wasn't configured to launch keosd") return False if self.isLaunched(): return True if self.isLocal(): self.port=self.findAvailablePort() pgrepCmd=Utils.pgrepCmd(Utils.EosWalletName) if Utils.Debug: portTaken=False if self.isLocal(): if not Utils.arePortsAvailable(self.port): portTaken=True psOut=Utils.checkOutput(pgrepCmd.split(), ignoreError=True) if psOut or portTaken: statusMsg="" if psOut: statusMsg+=" %s - {%s}." % (pgrepCmd, psOut) if portTaken: statusMsg+=" port %d is NOT available." % (self.port) Utils.Print("Launching %s, note similar processes running. %s" % (Utils.EosWalletName, statusMsg)) cmd="%s --data-dir %s --config-dir %s --http-server-address=%s:%d --verbose-http-errors" % ( Utils.EosWalletPath, WalletMgr.__walletDataDir, WalletMgr.__walletDataDir, self.host, self.port) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) with open(WalletMgr.__walletLogOutFile, 'w') as sout, open(WalletMgr.__walletLogErrFile, 'w') as serr: popen=subprocess.Popen(cmd.split(), stdout=sout, stderr=serr) self.__walletPid=popen.pid # Give keosd time to warm up time.sleep(2) try: if Utils.Debug: Utils.Print("Checking if %s launched. %s" % (Utils.EosWalletName, pgrepCmd)) psOut=Utils.checkOutput(pgrepCmd.split()) if Utils.Debug: Utils.Print("Launched %s. {%s}" % (Utils.EosWalletName, psOut)) except subprocess.CalledProcessError as ex: Utils.errorExit("Failed to launch the wallet manager") return True def create(self, name, accounts=None, exitOnError=True): wallet=self.wallets.get(name) if wallet is not None: if Utils.Debug: Utils.Print("Wallet \"%s\" already exists. Returning same." % name) return wallet p = re.compile(r'\n\"(\w+)\"\n', re.MULTILINE) cmdDesc="wallet create" cmd="%s %s %s --name %s --to-console" % (Utils.EosClientPath, self.getArgs(), cmdDesc, name) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr=None maxRetryCount=4 retryCount=0 while True: try: retStr=Utils.checkOutput(cmd.split()) break except subprocess.CalledProcessError as ex: retryCount+=1 if retryCount