PK!(fr'create_tomochain_masternode/__init__.py__version__ = '1.0.0' PK!#create_tomochain_masternode/envs.pymainnet = { 'metrics_endpoint': 'https://metrics.tomochain.com', 'network_id': '88', 'ws_secret': 'getty-site-pablo-auger-room-sos-blair-shin-whiz-delhi', 'bootnodes': ( 'enode://97f0ca95a653e3c44d5df2674e19e9324ea4bf4d47a46b1d8560f3ed' '4ea328f725acec3fcfcb37eb11706cf07da669e9688b091f1543f89b2425700a' '68bc8876@104.248.98.78:30301,enode://b72927f349f3a27b789d0ca615f' 'fe3526f361665b496c80e7cc19dace78bd94785fdadc270054ab727dbb172d9e' '3113694600dd31b2558dd77ad85a869032dea@188.166.207.189:30301,enod' 'e://c8f2f0643527d4efffb8cb10ef9b6da4310c5ac9f2e988a7f85363e81d42' 'f1793f64a9aa127dbaff56b1e8011f90fe9ff57fa02a36f73220da5ff81d8b8d' 'f351@104.248.98.60:30301' ) } testnet = { 'metrics_endpoint': 'https://metrics.testnet.tomochain.com', 'network_id': '89', 'ws_secret': 'anna-coal-flee-carrie-zip-hhhh-tarry-laue-felon-rhine', 'bootnodes': ( 'enode://4d3c2cc0ce7135c1778c6f1cfda623ab44b4b6db55289543d48ecfde' '7d7111fd420c42174a9f2fea511a04cf6eac4ec69b4456bfaaae0e5bd236107d' '3172b013@52.221.28.223:30301,enode://298780104303fcdb37a84c5702e' 'bd9ec660971629f68a933fd91f7350c54eea0e294b0857f1fd2e8dba2869fcc3' '6b83e6de553c386cf4ff26f19672955d9f312@13.251.101.216:30301,enode' '://46dba3a8721c589bede3c134d755eb1a38ae7c5a4c69249b8317c55adc8d4' '6a369f98b06514ecec4b4ff150712085176818d18f59a9e6311a52dbe68cff5b' '2ae@13.250.94.232:30301' ) } PK! None: """Command line interface entrypoint""" env = envs.testnet if testnet else envs.mainnet masternode_path = name masternode_name = os.path.basename(os.path.normpath(name)) if not is_folder_empty(masternode_path): error('Folder is not empty.') sys.exit(1) display( 'Creating a new masternode in ' f'{click.style(masternode_path, fg="green")}.', spacing=1 ) preflight() answers = ask() compose_template = Template(templates.compose) compose_content = compose_template.render(**answers, **env) env_template = Template(templates.env) env_content = env_template.render(name=masternode_name, **answers, **env) try: if not os.path.exists(masternode_path): os.makedirs(masternode_path) with open(f'{masternode_path}/docker-compose.yml', 'w') as file: print(compose_content, file=file) with open(f'{masternode_path}/.env', 'w') as file: print(env_content, file=file) except Exception: error('Could not create files.') success(masternode_name, masternode_path) def is_folder_empty(path: str) -> bool: """Check if folder is empty or not""" try: return False if os.listdir(path) else True except FileNotFoundError: return True def display( message: str, spacing_top: int = 0, spacing_bottom: int = 0, spacing: int = 0, padding: int = 0, ) -> None: """Printing helper function""" newlines_top = '\n' * spacing_top if not spacing else '\n' * spacing newlines_bottom = '\n' * spacing_bottom if not spacing else '\n' * spacing leftpad = ' ' * padding click.echo(f'{newlines_top}{leftpad}{message}{newlines_bottom}') def error(message: str) -> None: """Error helper function""" display( f'{click.style("! ", fg="red")}{message}', spacing=1 ) def preflight() -> None: """Display errors if preflight checks are missing""" if not shutil.which('docker'): error('Docker not found on your system.') if not shutil.which('docker-compose'): error('Docker-compose not found on your system.') def ask() -> Dict[str, str]: """Prompt users for parameters""" answers = {} bullet = f'{click.style("?", fg="cyan")}' answers['private_key'] = click.prompt( f'{bullet} Coinbase private key', hide_input=True, ) answers['storage'] = click.prompt( f'{bullet} Storage', type=click.Choice(['docker volume', 'host directory']), default='host directory', ) answers['data'] = click.prompt( f'{bullet} Chaindata {answers["storage"]}', type=click.Path( exists=True, file_okay=False, resolve_path=True, ) if answers["storage"] == 'host directory' else click.STRING ) answers['expose_rpc'] = click.confirm( f'{bullet} Expose RPC', ) answers['expose_ws'] = click.confirm( f'{bullet} Expose WebSocket', ) answers['logging_level'] = click.prompt( f'{bullet} Logging level', type=click.Choice(['error', 'info', 'debug']), default='info', value_proc=logging_name_to_int, ) return answers def success(name: str, masternode_path: str) -> None: """Display instruction text when finished with success""" display( f'Success! Created {name} at {masternode_path}\n' 'Inside that directory you can run several commands:', spacing_top=1 ) display( f'{click.style("docker-compose up|down", fg="cyan")}', spacing_top=1, padding=2 ) display( f'Create|remove your masternode', padding=2 ) display( f'{click.style("docker-compose ps", fg="cyan")}', spacing_top=1, padding=2 ) display( f'Check if your masternode is running', padding=2 ) display( f'{click.style("docker-compose stop|start [SERVICE...]", fg="cyan")}', spacing_top=1, padding=2 ) display( f'Stop|start your masternode', padding=2 ) display( f'{click.style("docker-compose logs [SERVICES...]", fg="cyan")}', spacing_top=1, padding=2 ) display( f'View your masternode logs', padding=2 ) display( f'{click.style("docker-compose --help", fg="cyan")}', spacing_top=1, padding=2 ) display( f'View all the possible docker-compose commands', padding=2 ) display( f'We suggest that you begin by typing:', spacing_top=1, ) display( f'{click.style("cd", fg="cyan")} {name}', spacing_top=1, padding=2 ) display( f'{click.style("docker-compose up -d", fg="cyan")}', padding=2 ) display( f'May the rewards be with you!', spacing=1 ) def logging_name_to_int(name: str) -> int: """Transform logging name to numerical level for tomo client""" if name == 'error': return 2 elif name == 'info': return 3 elif name == 'debug': return 4 else: return 5 if __name__ == '__main__': # frozen app fix if getattr(sys, 'frozen', False): entrypoint(sys.argv[1:]) PK!'PP1create_tomochain_masternode/templates/__init__.pyfrom .compose import compose from .env import env __all__ = ['compose', 'env'] PK!*0create_tomochain_masternode/templates/compose.pycompose = """version: "3.4" services: masternode: image: tomochain/node:stable environment: IDENTITY: $IDENTITY PRIVATE_KEY: $PRIVATE_KEY BOOTNODES: {{ bootnodes }} NETWORK_ID: {{ network_id }} VERBOSITY: {{ logging_level }} NETSTATS_HOST: stats.tomochain.com NETSTATS_PORT: 443 WS_SECRET: {{ ws_secret }} volumes: - $DATA:/tomochain/data ports: - 30303:30303/tcp - 30303:30303/udp {%- if expose_rpc %} - 8545:8545 {%- endif %} {%- if expose_ws %} - 8546:8546 {%- endif %} restart: always {% if storage == "docker volume" -%} volumes: {{ data }}: {%- endif %} """ PK!IvPP,create_tomochain_masternode/templates/env.pyenv = """IDENTITY={{ name }} PRIVATE_KEY={{ private_key }} DATA={{ data }} """ PK!H6F[<create_tomochain_masternode-1.0.0.dist-info/entry_points.txtEA @YLHH]K/8Jn'cRȨ܀{q+W5Y;/wߤgkXPK!HڽTU1create_tomochain_masternode-1.0.0.dist-info/WHEEL A н#Z;/"d&F[xzw@Zpy3Fv]\fi4WZ^EgM_-]#0(q7PK!HB04create_tomochain_masternode-1.0.0.dist-info/METADATAV[OH~8*/@c6Fm]`Y"BwUU2O{Ɲ'x3n$xZ9|6ЉD8J2z\CsB0֡Q:EGsa!AY[:a-XiS*%B5i$ 9ԹkDRQY>]y'VKm;N7t|_WN{ҥ D0T&\Ȭu ~/A*?Dǽw(LX+gzC_Ǣ0z ~Qi&Nz1m # S #F9v)Լ$fOGǏxh7+NuTQ=x&:{lKIu'^! ~"ST3D/> ؅o.piSKSN窶Jmld*VקzORNyZG{{p!:AThCHj0&bL&;M`ft.EhPXTۯ-P8d*lix|5}jumבBjK{.5 , kr! KK} Nc>[qo&ǝ^n/㧳 'ڗ ,6)zF$.yE=k> rޚg`," wƽj-UҬ*,3/1W&d>vX>R#]gYR#LIDB,:of^?|/OT0rANC⸕qK,2kZLKC`fJ; Ou0J/9+Ub#sLcQ#;#5I:+saY 6U4Zz:y K@! 4cbd"yʗ/?j\k6(b)2#cBpԉ0nAnMjڝ"m%%wnF'5͠&Bķǯ' A5[\#aS]f ǣ5Em0iM餢$f5E~ipTry2s/ZK+{ up4Ӗ5X QR;k1g=[LuF|m"|:kz&3\`V3cݗFXzjmzdz3|8{%mșkZ>X~f ^Mh}8/QǤg=ե+JFQgͤ6FPiP ?YG>뛔'泵YK] &lTiKm`)c? i'Lǜ+~]vZ]_\'ykB%Ҷ>V'ۈ5B eޤmX室A 5on9nYDԛ oAE"==WE'- [;PK!Hc 2create_tomochain_masternode-1.0.0.dist-info/RECORDn0{:CeZD\xɥHe:ɲw88MYD갊zI0$5a܎\E v9Qi ;X :r$q0[Nu\,T[\J-=-;rrU03AijtPOӖ2M%pT g ?MVdr86U[VO)lC,#qh9 G[ڧAsP7UynKYL.G΄.ג("T$+s&йȝf=$/Y8k3ހ|i< "I-w%خy'QN\,HGn~oݝqOPK!(fr'create_tomochain_masternode/__init__.pyPK!#[create_tomochain_masternode/envs.pyPK!