コード例 #1
0
def add_account(whiptail, bitshares_instance):
    """ "Add account" dialog

        :param whiptail.Whiptail whiptail: instance of Whiptail or NoWhiptail
        :param bitshares.BitShares bitshares_instance: an instance of BitShares class
        :return str: user-supplied account name
    """
    validator = ConfigValidator(bitshares_instance)

    account = whiptail.prompt("Your Account Name")
    private_key = whiptail.prompt("Your Private Key", password=True)

    if not validator.validate_account_name(account):
        whiptail.alert("Account name does not exist.")
        return False
    if not validator.validate_private_key(account, private_key):
        whiptail.alert("Private key is invalid")
        return False
    if private_key and not validator.validate_private_key_type(
            account, private_key):
        whiptail.alert("Please use active private key.")
        return False

    # User can supply empty private key if it was added earlier
    if private_key:
        validator.add_private_key(private_key)
        whiptail.alert("Private Key added successfully.")

    return account
コード例 #2
0
ファイル: worker_controller.py プロジェクト: tryiou/DEXBot
 def __init__(self, view, bitshares_instance, mode):
     self.view = view
     self.mode = mode
     self.validator = ConfigValidator(Config(), bitshares_instance or shared_bitshares_instance())
コード例 #3
0
def configure_dexbot(config, ctx):
    """ Main `cli configure` entrypoint

        :param dexbot.config.Config config: dexbot config
    """
    whiptail = get_whiptail('DEXBot configure')
    workers = config.get('workers', {})
    bitshares_instance = ctx.bitshares
    validator = ConfigValidator(bitshares_instance)

    if not workers:
        while True:
            txt = whiptail.prompt("Your name for the worker")
            if len(txt) == 0:
                whiptail.alert("Worker name cannot be blank. ")
            else:
                config['workers'] = {
                    txt: configure_worker(whiptail, {}, bitshares_instance)
                }
                if not whiptail.confirm(
                        "Set up another worker?\n(DEXBot can run multiple workers in one instance)"
                ):
                    break
        setup_systemd(whiptail, config)
    else:
        while True:
            action = whiptail.menu(
                "You have an existing configuration.\nSelect an action:",
                [('LIST', 'List your workers'), ('NEW', 'Create a new worker'),
                 ('EDIT', 'Edit a worker'), ('DEL_WORKER', 'Delete a worker'),
                 ('ADD', 'Add a bitshares account'),
                 ('DEL_ACCOUNT', 'Delete a bitshares account'),
                 ('SHOW', 'Show bitshares accounts'),
                 ('NODES', 'Edit Node Selection'),
                 ('ADD_NODE', 'Add Your Node'), ('HELP', 'Where to get help'),
                 ('EXIT', 'Quit this application')])

            my_workers = [(index, index) for index in workers]

            if action == 'EXIT':
                # Cancel will also exit the application. but this is a clearer label
                # Todo: modify cancel to be "Quit" or "Exit" for the whiptail menu item.
                break
            elif action == 'LIST':
                if len(my_workers):
                    # List workers, then provide option to list config of workers
                    worker_name = whiptail.menu(
                        "List of Your Workers. Select to view Configuration.",
                        my_workers)
                    content = config['workers'][worker_name]
                    text = '\n'
                    for key, value in content.items():
                        text += '{}: {}\n'.format(key, value)
                    whiptail.view_text(text, pager=False)
                else:
                    whiptail.alert('No workers to view.')
            elif action == 'EDIT':
                if len(my_workers):
                    worker_name = whiptail.menu("Select worker to edit",
                                                my_workers)
                    config['workers'][worker_name] = configure_worker(
                        whiptail, config['workers'][worker_name],
                        bitshares_instance)
                else:
                    whiptail.alert('No workers to edit.')
            elif action == 'DEL_WORKER':
                if len(my_workers):
                    worker_name = whiptail.menu("Select worker to delete",
                                                my_workers)
                    del config['workers'][worker_name]
                    # Pass ctx.config which is a loaded config (see ui.py configfile()), while `config` in a Config()
                    # instance, which is empty dict, but capable of returning keys via __getitem__(). We need to pass
                    # loaded config into StrategyBase to avoid loading a default config and preserve `--configfile`
                    # option
                    strategy = StrategyBase(
                        worker_name,
                        bitshares_instance=bitshares_instance,
                        config=ctx.config)
                    strategy.clear_all_worker_data()
                else:
                    whiptail.alert('No workers to delete.')
            elif action == 'NEW':
                worker_name = whiptail.prompt("Your name for the new worker. ")
                if not worker_name:
                    whiptail.alert("Worker name cannot be blank. ")
                elif not validator.validate_worker_name(worker_name):
                    whiptail.alert(
                        'Worker name needs to be unique. "{}" is already in use.'
                        .format(worker_name))
                else:
                    config['workers'][worker_name] = configure_worker(
                        whiptail, {}, bitshares_instance)
            elif action == 'ADD':
                add_account(whiptail, bitshares_instance)
            elif action == 'DEL_ACCOUNT':
                del_account(whiptail, bitshares_instance)
            elif action == 'SHOW':
                account_list = list_accounts(bitshares_instance)
                if account_list:
                    action = whiptail.menu(
                        "Bitshares Account List (Name - Type)", account_list)
                else:
                    whiptail.alert(
                        'You do not have any bitshares accounts in the wallet')
            elif action == 'ADD_NODE':
                txt = whiptail.prompt(
                    "Your name for the new node: e.g. wss://dexnode.net/ws")
                # Insert new node on top of the list
                config['node'].insert(0, txt)
            elif action == 'NODES':
                choice = whiptail.node_radiolist(
                    msg="Choose your preferred node",
                    items=select_choice(config['node'][0],
                                        [(index, index)
                                         for index in config['node']]))
                # Move selected node as first item in the config file's node list
                config['node'].remove(choice)
                config['node'].insert(0, choice)
                setup_systemd(whiptail, config)
            elif action == 'HELP':
                whiptail.alert(
                    "Please see https://github.com/Codaone/DEXBot/wiki")

    whiptail.clear()
    return config
コード例 #4
0
ファイル: worker_controller.py プロジェクト: tryiou/DEXBot
class WorkerController:
    def __init__(self, view, bitshares_instance, mode):
        self.view = view
        self.mode = mode
        self.validator = ConfigValidator(Config(), bitshares_instance or shared_bitshares_instance())

    @property
    def strategies(self):
        """
        Defines strategies that are configurable from the GUI.

        key: Strategy location in the project
        name: The name that is shown in the GUI for user
        form_module: If there is custom form module created with QTDesigner

        :return: List of strategies
        """
        strategies = collections.OrderedDict()
        strategies['dexbot.strategies.relative_orders'] = {
            'name': 'Relative Orders',
            'form_module': 'dexbot.views.ui.forms.relative_orders_widget_ui',
        }
        strategies['dexbot.strategies.staggered_orders'] = {'name': 'Staggered Orders', 'form_module': ''}
        strategies['dexbot.strategies.king_of_the_hill'] = {'name': 'King of the Hill', 'form_module': ''}
        for desc, module in find_external_strategies():
            strategies[module] = {'name': desc, 'form_module': module}
            # if there is no UI form in the module then GUI will gracefully revert to auto-ui
        return strategies

    @classmethod
    def get_strategies(cls):
        """Class method for getting the strategies."""
        return cls(None, None, None).strategies

    @staticmethod
    def get_unique_worker_name():
        """
        Returns unique worker name "Worker %n".

        %n is the next available index
        """
        index = 1
        workers = Config().workers_data.keys()
        worker_name = "Worker {0}".format(index)
        while worker_name in workers:
            worker_name = "Worker {0}".format(index)
            index += 1

        return worker_name

    @staticmethod
    def get_strategy_module(worker_data):
        return worker_data['module']

    @staticmethod
    def get_strategy_mode(worker_data):
        return worker_data['mode']

    @staticmethod
    def get_allow_instant_fill(worker_data):
        return worker_data['allow_instant_fill']

    @staticmethod
    def get_assets(worker_data):
        return re.split("[/:]", worker_data['market'])

    def get_base_asset(self, worker_data):
        return self.get_assets(worker_data)[1]

    def get_quote_asset(self, worker_data):
        return self.get_assets(worker_data)[0]

    @staticmethod
    def get_account(worker_data):
        return worker_data['account']

    @staticmethod
    def handle_save_dialog():
        dialog = ConfirmationDialog(
            'Saving the worker will cancel all the current orders.\n' 'Are you sure you want to do this?'
        )
        return dialog.exec_()

    @gui_error
    def change_strategy_form(self, worker_data=None):
        # Make sure the container is empty
        for index in reversed(range(self.view.strategy_container.count())):
            self.view.strategy_container.itemAt(index).widget().setParent(None)

        strategy_module = self.view.strategy_input.currentData()
        self.view.strategy_widget = StrategyFormWidget(self, strategy_module, worker_data)
        self.view.strategy_container.addWidget(self.view.strategy_widget)

        # Resize the dialog to be minimum possible height
        width = self.view.geometry().width()
        self.view.setMinimumHeight(0)
        self.view.resize(width, 1)

    @gui_error
    def validate_form(self):
        error_texts = []
        base_asset = self.view.base_asset_input.text()
        quote_asset = self.view.quote_asset_input.text()
        fee_asset = self.view.fee_asset_input.text()
        worker_name = self.view.worker_name_input.text()
        old_worker_name = None if self.mode == 'add' else self.view.worker_name

        if not self.validator.validate_worker_name(worker_name, old_worker_name):
            error_texts.append('Worker name needs to be unique. "{}" is already in use.'.format(worker_name))
        if not self.validator.validate_asset(base_asset):
            error_texts.append('Field "Base Asset" does not have a valid asset.')
        if not self.validator.validate_asset(quote_asset):
            error_texts.append('Field "Quote Asset" does not have a valid asset.')
        if not self.validator.validate_asset(fee_asset):
            error_texts.append('Field "Fee Asset" does not have a valid asset.')
        if not self.validator.validate_market(base_asset, quote_asset):
            error_texts.append("Market {}/{} doesn't exist.".format(base_asset, quote_asset))
        if self.mode == 'add':
            account = self.view.account_input.text()
            private_key = self.view.private_key_input.text()
            if not self.validator.validate_account_name(account):
                error_texts.append("Account doesn't exist.")
            if not self.validator.validate_private_key(account, private_key):
                error_texts.append('Private key is invalid.')
            elif private_key and not self.validator.validate_private_key_type(account, private_key):
                error_texts.append('Please use active private key.')

        error_texts.extend(self.view.strategy_widget.strategy_controller.validation_errors())
        error_text = '\n'.join(error_texts)

        if error_text:
            dialog = NoticeDialog(error_text)
            dialog.exec_()
            return False
        else:
            return True

    @gui_error
    def handle_save(self):
        if not self.validate_form():
            return

        if self.mode == 'add':
            # Add the private key to the database
            private_key = self.view.private_key_input.text()

            if private_key:
                self.validator.add_private_key(private_key)

            account = self.view.account_input.text()
        else:  # Edit
            account = self.view.account_name.text()

        base_asset = self.view.base_asset_input.text()
        quote_asset = self.view.quote_asset_input.text()
        fee_asset = self.view.fee_asset_input.text()
        operational_percent_quote = self.view.operational_percent_quote_input.value()
        operational_percent_base = self.view.operational_percent_base_input.value()
        strategy_module = self.view.strategy_input.currentData()

        self.view.worker_data = {
            'account': account,
            'market': '{}/{}'.format(quote_asset, base_asset),
            'module': strategy_module,
            'fee_asset': fee_asset,
            'operational_percent_quote': operational_percent_quote,
            'operational_percent_base': operational_percent_base,
            **self.view.strategy_widget.values,
        }
        self.view.worker_name = self.view.worker_name_input.text()
        self.view.accept()