Пример #1
0
def main():
    enforce_requirements()
    setup_windows_console()

    # The hook will only be used in the Qt GUI right now
    setup_thread_excepthook()

    # on osx, delete Process Serial Number arg generated for apps launched in Finder
    sys.argv = [x for x in sys.argv if not x.startswith('-psn')]

    # old 'help' syntax
    if len(sys.argv) > 1 and sys.argv[1] == 'help':
        sys.argv.remove('help')
        sys.argv.append('-h')

    # read arguments from stdin pipe and prompt
    for i, arg in enumerate(sys.argv):
        if arg == '-':
            if not sys.stdin.isatty():
                sys.argv[i] = sys.stdin.read()
                break
            else:
                raise Exception('Cannot get argument from stdin')
        elif arg == '?':
            sys.argv[i] = input("Enter argument:")
        elif arg == ':':
            sys.argv[i] = prompt_password('Enter argument (will not echo):',
                                          False)

    # parse command line
    parser = get_parser()
    args = parser.parse_args()

    # config is an object passed to various constructors
    config_options = args.__dict__
    config_options = {
        key: value
        for key, value in config_options.items()
        if value is not None and key not in config_variables.get(args.cmd, {})
    }

    logs.set_level(config_options['verbose'])

    if config_options.get('server'):
        config_options['auto_connect'] = False
    config_options['cwd'] = os.getcwd()

    # fixme: this can probably be achieved with a runtime hook (pyinstaller)
    portable_base_path = None
    try:
        if startup.is_bundle and os.path.exists(
                os.path.join(sys._MEIPASS, 'is_portable')):
            config_options['portable'] = True
            # Ensure the wallet data is stored in the same directory as the executable.
            portable_base_path = os.path.dirname(sys.executable)
    except AttributeError:
        config_options['portable'] = False

    if config_options.get('portable'):
        if portable_base_path is None:
            # Default to the same directory the 'electrum-sv' script is in.
            portable_base_path = os.path.dirname(os.path.realpath(sys.argv[0]))
        config_options['electrum_sv_path'] = os.path.join(
            portable_base_path, 'electrum_sv_data')

    if config_options.get('file_logging'):
        if config_options.get('portable'):
            log_path = os.path.join(config_options['electrum_sv_path'], "logs")
        else:
            log_path = os.path.join(platform.user_dir(prefer_local=True),
                                    "logs")
        os.makedirs(log_path, exist_ok=True)
        log_path = os.path.join(log_path,
                                time.strftime("%Y%m%d-%H%M%S") + ".log")
        logs.add_file_output(log_path)

    if config_options.get('testnet'):
        Net.set_to(SVTestnet)
    elif config_options.get('scalingtestnet'):
        Net.set_to(SVScalingTestnet)

    # check uri
    uri = config_options.get('url')
    if uri:
        if not web.is_URI(uri):
            print('unknown command:', uri, file=sys.stderr)
            sys.exit(1)
        config_options['url'] = uri

    # todo: defer this to gui
    config = SimpleConfig(config_options)
    cmdname = config.get('cmd')

    # Set the app state proxy
    if cmdname == 'gui':
        try:
            from electrumsv.gui.qt.app_state import QtAppStateProxy
        except ImportError as e:
            platform.missing_import(e)
        QtAppStateProxy(config, 'qt')
    elif cmdname == 'daemon' and 'daemon_app_module' in config_options:
        load_app_module(config_options['daemon_app_module'], config)
    else:
        AppStateProxy(config, 'cmdline')
        app_state.set_app(DefaultApp())

    # run non-RPC commands separately
    if cmdname in ['create', 'restore']:
        run_non_RPC(config)
        sys.exit(0)

    if cmdname == 'gui':
        fd, server = daemon.get_fd_or_server(config)
        if fd is not None:
            run_app_with_daemon(fd, True, config_options)
        else:
            result = server.gui(config_options)

    elif cmdname == 'daemon':
        subcommand = config.get('subcommand')
        if subcommand in ['load_wallet']:
            init_daemon(config_options)

        if subcommand in [None, 'start']:
            fd, server = daemon.get_fd_or_server(config)
            if fd is not None:
                if not app_state.has_app():
                    print("No application present to run.")
                    sys.exit(0)

                if subcommand == 'start':
                    if not hasattr(os, "fork"):
                        print(
                            f"Starting the daemon is not supported on {sys.platform}."
                        )
                        sys.exit(0)
                    pid = os.fork()
                    if pid:
                        print("Starting daemon (PID %d)" % pid,
                              file=sys.stderr)
                        sys.exit(0)

                run_app_with_daemon(fd, False, config_options)
            else:
                result = server.daemon(config_options)
        else:
            server = daemon.get_server(config)
            if server is not None:
                result = server.daemon(config_options)
            else:
                print("Daemon not running")
                sys.exit(1)
    else:
        # command line
        server = daemon.get_server(config)
        init_cmdline(config_options, server)
        if server is not None:
            result = server.run_cmdline(config_options)
        else:
            cmd = known_commands[cmdname]
            if cmd.requires_network:
                print("Daemon not running; try 'electrum-sv daemon start'")
                sys.exit(1)
            else:
                result = run_offline_command(config, config_options)
                # print result
    if isinstance(result, str):
        print(result)
    elif type(result) is dict and result.get('error'):
        print(result.get('error'), file=sys.stderr)
    elif result is not None:
        print(json_encode(result))
    sys.exit(0)
Пример #2
0
def main():
    # The hook will only be used in the Qt GUI right now
    setup_thread_excepthook()
    # on osx, delete Process Serial Number arg generated for apps launched in Finder
    sys.argv = [x for x in sys.argv if not x.startswith('-psn')]

    # old 'help' syntax
    if len(sys.argv) > 1 and sys.argv[1] == 'help':
        sys.argv.remove('help')
        sys.argv.append('-h')

    # read arguments from stdin pipe and prompt
    for i, arg in enumerate(sys.argv):
        if arg == '-':
            if not sys.stdin.isatty():
                sys.argv[i] = sys.stdin.read()
                break
            else:
                raise Exception('Cannot get argument from stdin')
        elif arg == '?':
            sys.argv[i] = input("Enter argument:")
        elif arg == ':':
            sys.argv[i] = prompt_password('Enter argument (will not echo):',
                                          False)

    # parse command line
    parser = get_parser()
    args = parser.parse_args()

    # config is an object passed to the various constructors (wallet, interface, gui)
    config_options = args.__dict__
    config_options = {
        key: value
        for key, value in config_options.items()
        if value is not None and key not in config_variables.get(args.cmd, {})
    }

    logs.set_level(config_options['verbose'])

    if config_options.get('server'):
        config_options['auto_connect'] = False
    config_options['cwd'] = os.getcwd()

    # fixme: this can probably be achieved with a runtime hook (pyinstaller)
    try:
        if is_bundle and os.path.exists(
                os.path.join(sys._MEIPASS, 'is_portable')):
            config_options['portable'] = True
    except AttributeError:
        config_options['portable'] = False

    if config_options.get('portable'):
        config_options['electrum_sv_path'] = os.path.join(
            os.path.dirname(os.path.realpath(__file__)), 'electrum_sv_data')

    if config_options.get('file_logging'):
        log_path = os.path.join(platform.user_dir(prefer_local=True), "logs")
        os.makedirs(log_path, exist_ok=True)
        log_path = os.path.join(log_path,
                                time.strftime("%Y%m%d-%H%M%S") + ".log")
        logs.add_file_output(log_path)

    if config_options.get('testnet'):
        Net.set_to(SVTestnet)

    # check uri
    uri = config_options.get('url')
    if uri:
        if not web.is_URI(uri):
            print('unknown command:', uri, file=sys.stderr)
            sys.exit(1)
        config_options['url'] = uri

    # todo: defer this to gui
    config = SimpleConfig(config_options)
    cmdname = config.get('cmd')

    # Set the app state proxy
    if cmdname == 'gui':
        try:
            from electrumsv.gui.qt.app_state import QtAppStateProxy
        except ImportError as e:
            platform.missing_import(e)
        QtAppStateProxy(config, 'qt')
    else:
        AppStateProxy(config, 'cmdline')

    # run non-RPC commands separately
    if cmdname in ['create', 'restore']:
        run_non_RPC(config)
        sys.exit(0)

    if cmdname == 'gui':
        fd, server = daemon.get_fd_or_server(config)
        if fd is not None:
            d = daemon.Daemon(fd, True)
            d.start()
            app_state.app.run_gui()
            sys.exit(0)
        else:
            result = server.gui(config_options)

    elif cmdname == 'daemon':
        subcommand = config.get('subcommand')
        if subcommand in ['load_wallet']:
            init_daemon(config_options)

        if subcommand in [None, 'start']:
            fd, server = daemon.get_fd_or_server(config)
            if fd is not None:
                if subcommand == 'start':
                    pid = os.fork()
                    if pid:
                        print("starting daemon (PID %d)" % pid,
                              file=sys.stderr)
                        sys.exit(0)
                d = daemon.Daemon(fd, False)
                d.start()
                if config.get('websocket_server'):
                    try:
                        from electrumsv import websockets
                    except ImportError as e:
                        platform.missing_import(e)
                    websockets.WebSocketServer(config, d.network).start()
                if config.get('requests_dir'):
                    path = os.path.join(config.get('requests_dir'),
                                        'index.html')
                    if not os.path.exists(path):
                        print("Requests directory not configured.")
                        print("You can configure it using "
                              "https://github.com/spesmilo/electrum-merchant")
                        sys.exit(1)
                d.join()
                sys.exit(0)
            else:
                result = server.daemon(config_options)
        else:
            server = daemon.get_server(config)
            if server is not None:
                result = server.daemon(config_options)
            else:
                print("Daemon not running")
                sys.exit(1)
    else:
        # command line
        server = daemon.get_server(config)
        init_cmdline(config_options, server)
        if server is not None:
            result = server.run_cmdline(config_options)
        else:
            cmd = known_commands[cmdname]
            if cmd.requires_network:
                print("Daemon not running; try 'electrum-sv daemon start'")
                sys.exit(1)
            else:
                result = run_offline_command(config, config_options)
                # print result
    if isinstance(result, str):
        print(result)
    elif type(result) is dict and result.get('error'):
        print(result.get('error'), file=sys.stderr)
    elif result is not None:
        print(json_encode(result))
    sys.exit(0)
Пример #3
0
    def _copy_electron_cash_wallets(self):
        """
        Work out whether we should show UI to offer to copy the user's
        Electron Cash wallets to their ElectrumSV wallet directory, and
        if so, show it and give them the chance.
        """
        def ignore_wallet_file(wallet_path):
            if os.path.isdir(wallet_path):
                return True
            if wallet_path.startswith("."):
                return True
            return False

        def count_user_wallets(wallets_path):
            if os.path.exists(wallets_path):
                filenames = [
                    filename for filename in os.listdir(wallets_path)
                    if not ignore_wallet_file(
                        os.path.join(wallets_path, filename))
                ]
                return len(filenames)
            return 0

        # If the user has ElectrumSV wallets already, we do not offer to copy the one's
        # Electron Cash has.
        esv_wallets_dir = os.path.join(platform.user_dir(), "wallets")
        if count_user_wallets(esv_wallets_dir) > 0:
            return
        ec_wallets_dir = get_electron_cash_user_dir(esv_wallets_dir)
        ec_wallet_count = count_user_wallets(ec_wallets_dir)
        # If the user does not have Electron Cash wallets to copy, there's no point in offering.
        if ec_wallet_count == 0:
            return

        def update_summary_label():
            selection_count = len(file_list.selectedItems())
            if selection_count == 0:
                summary_label.setText(
                    _("No wallets are selected / will be copied."))
            elif selection_count == 1:
                summary_label.setText(
                    _("1 wallet is selected / will be copied."))
            else:
                summary_label.setText(
                    _("%d wallets are selected / will be copied.") %
                    selection_count)

        wallet_filenames = sorted(os.listdir(ec_wallets_dir),
                                  key=lambda s: s.lower())

        file_list = QListWidget()
        file_list.setSelectionMode(QAbstractItemView.ExtendedSelection)
        for filename in wallet_filenames:
            if not ignore_wallet_file(os.path.join(ec_wallets_dir, filename)):
                file_list.addItem(QListWidgetItem(filename))
        file_list.itemSelectionChanged.connect(update_summary_label)

        vbox = QVBoxLayout()
        introduction_label = QLabel(
            _("Your Electron Cash wallet directory was found. If you want ElectrumSV to import "
              "any of them on your behalf, select the ones you want copied from the list below "
              "before clicking the Next button."))
        introduction_label.setWordWrap(True)
        vbox.setSpacing(20)
        vbox.addWidget(introduction_label)
        vbox.addWidget(file_list)
        summary_label = QLabel()
        update_summary_label()
        vbox.addWidget(summary_label)
        self._set_standard_layout(vbox,
                                  title=_('Import Electron Cash wallets'))

        v = self.loop.exec_()
        # Cancel, exit application.
        if v == -1:
            raise UserCancelled()
        if v != 2:
            raise GoBack()

        # If the user selected any files, then we copy them before exiting to the next page.
        for item in file_list.selectedItems():
            filename = item.text()
            source_path = os.path.join(ec_wallets_dir, filename)
            target_path = os.path.join(esv_wallets_dir, filename)
            try:
                shutil.copyfile(source_path, target_path)
            except shutil.Error:
                # For now we ignore copy errors.
                pass