class Plugin(AbstractPlugin): SERVER_HOST = server_app.SERVER_HOST SERVER_PORT = server_app.SERVER_PORT RESERVED_PORTS: Set[int] = {SERVER_PORT} PING_URL = server_app.PING_URL COMPONENT_NAME = get_directory_name(__file__) COMPONENT_PATH = Path(os.path.dirname(os.path.abspath(__file__))) SCRIPT_PATH = COMPONENT_PATH / "server_app.py" def __init__(self, cli_inputs: CLIInputs): self.cli_inputs = cli_inputs self.plugin_tools = PluginTools(self, self.cli_inputs) self.logger = logging.getLogger(self.COMPONENT_NAME) self.src = self.COMPONENT_PATH self.datadir = None # dynamically allocated self.id = None # dynamically allocated self.port = None # dynamically allocated self.component_info: Optional[Component] = None def install(self) -> None: self.logger.debug( f"Installing {self.COMPONENT_NAME} is not applicable") def start(self) -> None: self.id = self.plugin_tools.get_id(self.COMPONENT_NAME) logfile = self.plugin_tools.get_logfile_path(self.id) env_vars = {"PYTHONUNBUFFERED": "1"} command = f"{sys.executable} {self.SCRIPT_PATH}" self.plugin_tools.spawn_process(command, env_vars=env_vars, id=self.id, component_name=self.COMPONENT_NAME, src=self.src, logfile=logfile) def stop(self) -> None: self.logger.debug( "Attempting to kill the process if it is even running") self.plugin_tools.call_for_component_id_or_type(self.COMPONENT_NAME, callable=kill_process) def reset(self) -> None: self.logger.info("resetting the status monitor is not applicable.")
class Plugin(AbstractPlugin): DEFAULT_PORT = 5050 RESERVED_PORTS: Set[int] = {DEFAULT_PORT} COMPONENT_NAME = get_directory_name(__file__) NODE_HOST = os.environ.get("NODE_HOST") or "127.0.0.1" NODE_RPC_PORT = int(os.environ.get("NODE_RPC_PORT") or 18332) NODE_RPC_USERNAME = os.environ.get("NODE_RPC_USERNAME") or "rpcuser" NODE_RPC_PASSWORD = os.environ.get("NODE_RPC_PASSWORD") or "rpcpassword" NODE_ZMQ_PORT = int(os.environ.get("NODE_ZMQ_PORT") or 28332) MERCHANT_API_HOST = os.environ.get("MERCHANT_API_HOST") or "127.0.0.1" MERCHANT_API_PORT = int( os.environ.get("MERCHANT_API_PORT") or DEFAULT_PORT) def __init__(self, cli_inputs: CLIInputs): self.cli_inputs = cli_inputs self.config = Config() self.plugin_tools = PluginTools(self, self.cli_inputs) self.logger = logging.getLogger(self.COMPONENT_NAME) self.src = self.plugin_tools.get_source_dir(dirname="merchant_api") self.datadir: Optional[Path] = None # dynamically allocated self.id: Optional[str] = None # dynamically allocated self.port: Optional[int] = None # dynamically allocated self.component_info: Optional[Component] = None download_and_init_postgres() # only if necessary def install(self) -> None: assert self.src is not None # typing bug in mypy download_and_install(self.src) if SDK_SKIP_POSTGRES_INIT != 1: if SDK_PORTABLE_MODE == 1: # stop_postgres() # reset_postgres() start_postgres() prepare_fresh_postgres() drop_db_on_install() check_postgres_db() self.logger.debug(f"Installed {self.COMPONENT_NAME}") def start(self) -> None: assert self.src is not None # typing bug if SDK_PORTABLE_MODE == 1: download_and_install(self.src) start_postgres() self.logger.debug(f"Starting Merchant API") prepare_fresh_postgres() check_postgres_db() if not self.src.exists(): self.logger.error( f"source code directory does not exist - try 'electrumsv-sdk install " f"{self.COMPONENT_NAME}' to install the plugin first") sys.exit(1) self.id = self.plugin_tools.get_id(self.COMPONENT_NAME) self.port = self.MERCHANT_API_PORT # The primary reason we need this to be the current directory is so that the `settings.conf` # file is directly accessible to the MAPI executable (it should look there first). os.chdir(self.src) # EXE RUN MODE load_env_vars() try: chmod_exe(self.src) command = get_run_path(self.src) except FileNotFoundError: self.logger.error( f"Could not find version: {MERCHANT_API_VERSION} of the " f"merchant_api. Have you tried re-running 'electrumsv-sdk install merchant_api' to " f"pull the latest version?") return logfile = self.plugin_tools.get_logfile_path(self.id) status_endpoint = "http://127.0.0.1:5050/mapi/feeQuote" self.add_node_thread = AddNodeThread(mapi_url="http://127.0.0.1:5050", max_wait_time=10) self.add_node_thread.start() self.plugin_tools.spawn_process(str(command), env_vars=os.environ.copy(), id=self.id, component_name=self.COMPONENT_NAME, src=self.src, logfile=logfile, status_endpoint=status_endpoint) # will keep trying to add node until mAPI REST API available (up to a limited wait time) self.logger.info("Adding node to mAPI instance (if not already added)") self.add_node_thread.join() def stop(self) -> None: self.plugin_tools.call_for_component_id_or_type(self.COMPONENT_NAME, callable=kill_process) if SDK_PORTABLE_MODE == 1: assert self.config.DATADIR is not None postgres_install_path = self.config.DATADIR / "postgres" # Set this environment variable before importing postgres script os.environ['SDK_POSTGRES_INSTALL_DIR'] = str(postgres_install_path) from .. import _postgres if asyncio.run(_postgres.check_running()): stop_postgres() self.logger.info( f"stopped selected {self.COMPONENT_NAME} instance (if running)") def reset(self) -> None: self.logger.info("resetting Merchant API is not applicable")
class Plugin(AbstractPlugin): # As per woc-explorer/cli_inputs.js # TODO This is obsolete. ElectrumX is no longer supported in the SDK. Either we need to get # rid of the WOC components or replace them with an explorer component which we would # embed in the TestUI project. ELECTRUMX_HOST = os.environ.get("ELECTRUMX_HOST") or "127.0.0.1" ELECTRUMX_PORT = os.environ.get("ELECTRUMX_PORT") or 51001 # As per woc-explorer/app.js RPC_HOST = os.environ.get("RPC_HOST") or "127.0.0.1" RPC_PORT = int(os.environ.get("RPC_PORT") or 18332) RPC_USERNAME = os.environ.get("RPC_USERNAME") or "rpcuser" RPC_PASSWORD = os.environ.get("RPC_PASSWORD") or "rpcpassword" DEFAULT_PORT = 3002 RESERVED_PORTS: Set[int] = {DEFAULT_PORT} COMPONENT_NAME = get_directory_name(__file__) def __init__(self, cli_inputs: CLIInputs): self.cli_inputs = cli_inputs self.config = Config() self.plugin_tools = PluginTools(self, self.cli_inputs) self.tools = LocalTools(self) self.logger = logging.getLogger(self.COMPONENT_NAME) self.src = self.plugin_tools.get_source_dir("woc-explorer") self.datadir = None # N/A self.id = self.plugin_tools.get_id(self.COMPONENT_NAME) self.port = None # N/A self.component_info: Optional[Component] = None def install(self) -> None: if not self.cli_inputs.repo == "": # default self.logger.error( "ignoring --repo flag for whatsonchain - not applicable.") self.tools.fetch_whatsonchain( url="https://github.com/AustEcon/woc-explorer.git", branch='') self.tools.packages_whatsonchain() self.logger.debug(f"Installed {self.COMPONENT_NAME}") def start(self) -> None: self.logger.debug(f"Starting whatsonchain explorer...") assert self.src is not None # typing bug if not self.src.exists(): self.logger.error( f"source code directory does not exist - try 'electrumsv-sdk install " f"{self.COMPONENT_NAME}' to install the plugin first") sys.exit(1) if not self.tools.check_node_for_woc(self.RPC_HOST, self.RPC_PORT, self.RPC_USERNAME, self.RPC_PASSWORD): sys.exit(1) os.chdir(self.src) # npm without .cmd extension doesn't work with Popen shell=False if sys.platform == "win32": command = f"npm.cmd start" elif sys.platform in {"linux", "darwin"}: command = f"npm start" env_vars = { "PYTHONUNBUFFERED": "1", "ELECTRUMX_HOST": self.ELECTRUMX_HOST, "ELECTRUMX_PORT": str(self.ELECTRUMX_PORT), "RPC_HOST": self.RPC_HOST, "RPC_PORT": str(self.RPC_PORT), "RPC_USERNAME": self.RPC_USERNAME, "RPC_PASSWORD": self.RPC_PASSWORD, } self.id = self.plugin_tools.get_id(self.COMPONENT_NAME) logfile = self.plugin_tools.get_logfile_path(self.id) status_endpoint = "http://127.0.0.1:3002" self.plugin_tools.spawn_process(command, env_vars=env_vars, id=self.id, component_name=self.COMPONENT_NAME, src=self.src, logfile=logfile, status_endpoint=status_endpoint) def stop(self) -> None: """some components require graceful shutdown via a REST API or RPC API but most can use the generic 'app_state.kill_component()' function to track down the pid and kill the process.""" self.plugin_tools.call_for_component_id_or_type(self.COMPONENT_NAME, callable=kill_process) self.logger.info( f"stopped selected {self.COMPONENT_NAME} instance (if running)") def reset(self) -> None: self.logger.info("resetting the whatsonchain is not applicable")