def create_app(settings_name: str, additional_handlers: list) -> Application: log.info("Starting web server") handlers = [ url(r"/", IndexHandler, name="index"), url(r"/setup/(.*)", SetupHandler, name="setup"), url(r"/create_wallet", WalletCreationHandler, name="create_wallet"), url(r"/account/(.*)", AccountDetailHandler, name="account"), url(r"/keystore/(.*)/(.*)", KeystoreHandler, name="keystore"), url(r"/launch/(.*)", LaunchHandler, name="launch"), url(r"/gas_price/(.*)", GasPriceHandler, name="gas_price"), url( r"/api/configuration/(.*)", ConfigurationItemAPIHandler, name="api-configuration-detail", ), ] settings = load_settings(settings_name) return Application(handlers + additional_handlers, debug=DEBUG, static_path=os.path.join(RESOURCE_FOLDER_PATH, "static"), template_path=os.path.join(RESOURCE_FOLDER_PATH, "templates"), installer_settings=settings)
def _send_task_complete(self, message_text): self.write_message( json.dumps({ "type": "task-complete", "text": message_text })) log.info(message_text)
def wait_for_web_ui_ready(self, status_callback: Callable = None): """ Params: status_callback: A function, that will receive the /status API responses before the status is `ready`. """ if not self.is_running: raise RuntimeError("Raiden is not running") uri = urlparse(self.WEB_UI_INDEX_URL) while True: self._process_id = self.get_process_id() if not self.is_running or self.is_zombie: raise RaidenClientError( "client process terminated while waiting for web ui") log.info("Waiting for raiden to start...") while not self.check_status_api(status_callback=status_callback): time.sleep(1) with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: try: connected = sock.connect_ex((uri.hostname, uri.port)) == 0 if connected: return except socket.gaierror: pass time.sleep(1)
def _send_status_update(self, message_text): self.write_message( json.dumps({ "type": "status-update", "text": message_text })) log.info(message_text)
def _send_redirect(self, redirect_url): self.write_message( json.dumps({ "type": "redirect", "redirect_url": redirect_url })) log.info(f"Redirecting to {redirect_url}")
def _send_status_update(self, message_text, icon=None): if not isinstance(message_text, list): message_text = [message_text] body = {"type": "status-update", "text": message_text} if icon: body["icon"] = icon self.write_message(json.dumps(body)) log.info(" ".join(message_text))
def kill(self): process = self._process_id and psutil.Process(self._process_id) if process is not None: log.info(f"Killing process {self._process_id}") process.kill() process.wait() self._process_id = self.get_process_id() assert self._process_id is None
def _send_summary(self, text, **kw): if not isinstance(text, list): text = [text] message = {"type": "summary", "text": text} icon = kw.get("icon") if icon: message["icon"] = icon self.write_message(message) log.info(" ".join(text))
def _send_next_step(self, message_text, title, step): if not isinstance(message_text, list): message_text = [message_text] body = { "type": "next-step", "text": message_text, "title": title, "step": step } self.write_message(json.dumps(body)) log.info(" ".join(message_text)) log.info(f"Update progress to step {step}: {title}")
def run_server(app: Application, port: int): # pragma: no cover sockets = bind_sockets(port, "localhost") server = HTTPServer(app) server.add_sockets(sockets) _, socket_port = sockets[0].getsockname() local_url = f"http://localhost:{socket_port}" log.info(f"Installer page ready on {local_url}") if not DEBUG: log.info("Should open automatically in browser...") recover_ld_library_env_path() webbrowser.open_new(local_url) tornado.ioloop.IOLoop.current().start()
def _run_launch(self, **kw): configuration_file_name = kw.get("configuration_file_name") configuration_file = RaidenConfigurationFile.get_by_filename( configuration_file_name) account = configuration_file.account try_unlock(account) if account.passphrase is None: self._send_error_message( "Failed to unlock account! Please reload page") return raiden_client = RaidenClient.get_client(self.installer_settings) if not raiden_client.is_installed: self._send_status_update( f"Downloading and installing raiden {raiden_client.release}") raiden_client.install() self._send_status_update("Installation complete") self._send_status_update( "Launching Raiden, this might take a couple of minutes, do not close the browser" ) with temporary_passphrase_file(get_passphrase()) as passphrase_file: if not raiden_client.is_running: raiden_client.launch(configuration_file, passphrase_file) try: raiden_client.wait_for_web_ui_ready( status_callback=lambda stat: log.info(str(stat))) self._send_task_complete("Raiden is ready!") self._send_redirect(RaidenClient.WEB_UI_INDEX_URL) except (RaidenClientError, RuntimeError) as exc: self._send_error_message( f"Raiden process failed to start: {exc}") raiden_client.kill()
def get(self, configuration_file_name): configuration_file = RaidenConfigurationFile.get_by_filename( configuration_file_name) keystore_path = configuration_file.configuration_data["keystore-path"] filename = "" for file in glob(f"{keystore_path}/UTC--*"): file_path = Path(file) if file_path.is_file(): keystore_content = json.loads(file_path.read_text()) if (to_checksum_address(keystore_content["address"]) == configuration_file.account.address): filename = os.path.basename(file) break w3 = make_web3_provider( configuration_file.ethereum_client_rpc_endpoint, configuration_file.account) required = RequiredAmounts.for_network(configuration_file.network.name) eth_balance = configuration_file.account.get_ethereum_balance(w3) log.info(f"Checking balance {eth_balance} > {required.eth}") if eth_balance < required.eth: log.info( f"funding tx {configuration_file._initial_funding_txhash}") if configuration_file._initial_funding_txhash is not None: return self.render( "account.html", configuration_file=configuration_file, keystore=filename, ) else: configuration_file._initial_funding_txhash = None configuration_file.save() if PASSPHRASE is not None: self.render("account.html", configuration_file=configuration_file, keystore=filename) else: self.render( "account_unlock.html", keystore_file_path=configuration_file.account. keystore_file_path, return_to=f"/account/{configuration_file_name}", )
def _run_launch(self, **kw): configuration_file_name = kw.get("configuration_file_name") configuration_file = RaidenConfigurationFile.get_by_filename( configuration_file_name) network_name = configuration_file.network.name raiden_client = RaidenClient.get_client(network_name) required = RequiredAmounts.for_network(network_name) if not raiden_client.is_installed: self._send_status_update( f"Downloading and installing raiden {raiden_client.release}") raiden_client.install() self._send_status_update("Installation complete") account = configuration_file.account w3 = make_web3_provider( configuration_file.ethereum_client_rpc_endpoint, account) service_token = Erc20Token.find_by_ticker( required.service_token.ticker, network_name) service_token_balance = get_token_balance(w3=w3, account=account, token=service_token) service_token_in_deposit = get_token_deposit(w3=w3, account=account, token=service_token) if service_token_balance.as_wei and service_token_in_deposit < required.service_token: self._send_status_update( f"Making deposit of {service_token_balance.formatted} for Raiden Services" ) deposit_service_tokens(w3=w3, account=account, token=service_token, amount=service_token_balance.as_wei) service_token_deposited = get_token_deposit(w3=w3, account=account, token=service_token) self._send_status_update( f"Amount deposited at UDC: {service_token_deposited.formatted}" ) self._send_status_update( "Launching Raiden, this might take a couple of minutes, do not close the browser" ) if not raiden_client.is_running: raiden_client.launch(configuration_file) try: raiden_client.wait_for_web_ui_ready( status_callback=lambda stat: log.info(str(stat))) self._send_task_complete("Raiden is ready!") self._send_redirect(raiden_client.WEB_UI_INDEX_URL) except (RaidenClientError, RuntimeError) as exc: self._send_error_message(f"Raiden process failed to start: {exc}") raiden_client.kill()
def check_status_api(self, status_callback: Callable = None): """ Params: status_callback: A function, that will receive the /status API responses before the status is `ready`. """ log.info("Checking /status endpoint") try: response = requests.get(RaidenClient.WEB_UI_INDEX_URL + RaidenClient.RAIDEN_API_STATUS_ENDPOINT) if response and response.status_code == 200: result = response.json() if result.get("status") == "ready": return True else: if status_callback is not None: status_callback(result) except ConnectionError: pass return False
def get(self, configuration_file_name): configuration_file = RaidenConfigurationFile.get_by_filename( configuration_file_name) if get_passphrase() is None: self.render( "account_unlock.html", keystore_file_path=configuration_file.account. keystore_file_path, return_to=f"/account/{configuration_file_name}", ) return keystore_path = configuration_file.configuration_data["keystore-path"] filename = "" for file in glob(f"{keystore_path}/UTC--*"): file_path = Path(file) if file_path.is_file(): keystore_content = json.loads(file_path.read_text()) if (to_canonical_address(keystore_content["address"]) == configuration_file.account.address): filename = os.path.basename(file) break w3 = make_web3_provider( configuration_file.ethereum_client_rpc_endpoint, configuration_file.account) required = RequiredAmounts.from_settings(self.installer_settings) eth_balance = configuration_file.account.get_ethereum_balance(w3) log.info(f"funding tx {configuration_file._initial_funding_txhash}") log.info(f"Checking balance {eth_balance} >= {required.eth}") if eth_balance >= required.eth: configuration_file._initial_funding_txhash = None configuration_file.save() self.render( "account.html", configuration_file=configuration_file, keystore=filename, ramp_api_key=RAMP_API_KEY, )
def wait_for_web_ui_ready(self): if not self.is_running: raise RuntimeError("Raiden is not running") uri = urlparse(self.WEB_UI_INDEX_URL) while True: self._process_id = self.get_process_id() if not self.is_running or self.is_zombie: raise RaidenClientError( "client process terminated while waiting for web ui") with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: log.info("Waiting for raiden to start...") try: connected = sock.connect_ex((uri.hostname, uri.port)) == 0 if connected: return except socket.gaierror: pass time.sleep(1)
def _run_launch(self, **kw): configuration_file_name = kw.get("configuration_file_name") configuration_file = RaidenConfigurationFile.get_by_filename( configuration_file_name) network_name = configuration_file.network.name raiden_client = RaidenClient.get_client(network_name) if not raiden_client.is_installed: self._send_status_update( f"Downloading and installing raiden {raiden_client.release}") raiden_client.install() self._send_status_update("Installation complete") account = configuration_file.account try_unlock(account) if account.passphrase is None: return self.render( "account_unlock.html", keystore_file_path=account.keystore_file_path, return_to=f"/launch/{configuration_file_name}", ) self._send_status_update( "Launching Raiden, this might take a couple of minutes, do not close the browser" ) with temporary_passphrase_file(PASSPHRASE) as passphrase_file: if not raiden_client.is_running: raiden_client.launch(configuration_file, passphrase_file) try: raiden_client.wait_for_web_ui_ready( status_callback=lambda stat: log.info(str(stat))) self._send_task_complete("Raiden is ready!") self._send_redirect(raiden_client.WEB_UI_INDEX_URL) except (RaidenClientError, RuntimeError) as exc: self._send_error_message( f"Raiden process failed to start: {exc}") raiden_client.kill()
def _send_txhash_message(self, text, tx_hash): if not isinstance(text, list): text = [text] message = {"type": "hash", "text": text, "tx_hash": tx_hash} self.write_message(message) log.info(f"{''.join(text)} {tx_hash}")
def _send_txhash_message(self, text, tx_hash): if not isinstance(text, list): text = [text] message = {"type": "hash", "text": text, "tx_hash": tx_hash} self.write_message(message) log.info(f"Waiting for confirmation of txhash {tx_hash}")
token_amount = TokenAmount(ex_currency_amt["target_amount"], currency) exchange_costs = exchange.calculate_transaction_costs( token_amount, account) total_cost = exchange_costs["total"] self.render_json({ "exchange": exchange.name, "currency": currency.ticker, "target_amount": ex_currency_amt["target_amount"], "as_wei": total_cost.as_wei, "formatted": total_cost.formatted, "utc_seconds": int(time.time()), }) if __name__ == "__main__": log.info("Starting web server") app = Application( [ url(r"/", IndexHandler, name="index"), url(r"/configurations", ConfigurationListHandler, name="configuration-list"), url(r"/setup/(mainnet|goerli)/(.*)", SetupHandler, name="setup"), url(r"/create_wallet/(mainnet|goerli)", WalletCreationHandler, name="create_wallet"), url(r"/account/(.*)", AccountDetailHandler, name="account"), url(r"/keystore/(.*)/(.*)", KeystoreHandler, name="keystore"), url(r"/launch/(.*)", LaunchHandler, name="launch"), url(r"/swap/(.*)/([A-Z]{3})", SwapHandler, name="swap"), url(r"/ws", AsyncTaskHandler, name="websocket"),
def make_by_tag(cls, release_tag): log.info("Getting list of all nightly releases") return {r.release: r for r in cls.get_available_releases()}.get(release_tag)
def _send_txhash_message(self, text, tx_hash): message = {"type": "hash", "text": text, "tx_hash": tx_hash} self.write_message(message) log.info(f"Waiting for confirmation of txhash {tx_hash}")