From 28ebdd8dfc27a90e0acd1abbbbddaf80ea20e62f Mon Sep 17 00:00:00 2001 From: miro Date: Mon, 30 Dec 2024 21:57:27 +0000 Subject: [PATCH] feat:tui --- MANIFEST.in | 2 + hivemind_plugin_manager/database.py | 15 ++- hivemind_plugin_manager/tui.py | 139 ++++++++++++++++++++++++++++ requirements.txt | 3 + setup.py | 8 +- 5 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 MANIFEST.in create mode 100644 hivemind_plugin_manager/tui.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..c1d65d6 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +include requirements.txt +include LICENSE.md diff --git a/hivemind_plugin_manager/database.py b/hivemind_plugin_manager/database.py index c00ce60..2826646 100644 --- a/hivemind_plugin_manager/database.py +++ b/hivemind_plugin_manager/database.py @@ -37,17 +37,24 @@ class Client: api_key: str name: str = "" description: str = "" - is_admin: bool = False + is_admin: bool = False # allowed to send ADMIN type messages last_seen: float = -1 + intent_blacklist: List[str] = field(default_factory=list) skill_blacklist: List[str] = field(default_factory=list) message_blacklist: List[str] = field(default_factory=list) allowed_types: List[str] = field(default_factory=list) + crypto_key: Optional[str] = None password: Optional[str] = None - can_broadcast: bool = True - can_escalate: bool = True - can_propagate: bool = True + + # TODO - expose all below to cli utils + can_broadcast: bool = True # allowed to send BROADCAST type messages + can_escalate: bool = True # allowed to send ESCALATE type messages + can_propagate: bool = True # allowed to send PROPAGATE type messages + + locked: bool = False # it's on database, but server wont allow to connect + can_send_binary: bool = True # if False all incoming binary payloads will be dropped def __post_init__(self): """ diff --git a/hivemind_plugin_manager/tui.py b/hivemind_plugin_manager/tui.py new file mode 100644 index 0000000..950bc1f --- /dev/null +++ b/hivemind_plugin_manager/tui.py @@ -0,0 +1,139 @@ +import json +import os.path +from typing import List + +import click +from hivemind_plugin_manager import find_plugins, HiveMindPluginTypes +from json_database import JsonStorageXDG +from ovos_utils.xdg_utils import xdg_config_home, xdg_data_home + +_DEFAULT = { + "agent_protocol": {"module": "hivemind-ovos-agent-plugin", + "hivemind-ovos-agent-plugin": { + "host": "127.0.0.1", + "port": 8181 + }}, + "binary_protocol": {"module": None}, + "network_protocol": {"module": "hivemind-websocket-plugin", + "hivemind-websocket-plugin": { + "host": "0.0.0.0", + "port": 5678, + "ssl": False, + "cert_dir": f"{xdg_data_home()}/hivemind", + "cert_name": "hivemind" + }}, + "database": {"module": "hivemind-json-db-plugin", + "hivemind-json-db-plugin": { + "name": "clients", + "subfolder": "hivemind-core" + }} +} + +mapping = { + HiveMindPluginTypes.BINARY_PROTOCOL: "binary_protocol", + HiveMindPluginTypes.AGENT_PROTOCOL: "agent_protocol", + HiveMindPluginTypes.NETWORK_PROTOCOL: "network_protocol", + HiveMindPluginTypes.DATABASE: "database" +} + + +def cast_to_enum(plugin_type: str) -> HiveMindPluginTypes: + if plugin_type == "network": + plugin_type = HiveMindPluginTypes.NETWORK_PROTOCOL + elif plugin_type == "agent": + plugin_type = HiveMindPluginTypes.AGENT_PROTOCOL + elif plugin_type == "binary": + plugin_type = HiveMindPluginTypes.BINARY_PROTOCOL + elif plugin_type == "database": + plugin_type = HiveMindPluginTypes.DATABASE + else: + raise ValueError("invalid plugin type") + return plugin_type + + +def get_server_config() -> JsonStorageXDG: + """from ~/.config/hivemind-core/server.json """ + db = JsonStorageXDG("server", + xdg_folder=xdg_config_home(), + subfolder="hivemind-core") + # create file if it doesnt exist + if not os.path.isfile(db.path): + db.merge(_DEFAULT) + db.store() + # ensure no missing top level values + for k in [_ for _ in _DEFAULT if _ not in db]: + db[k] = _DEFAULT[k] + return db + + +# Initialize the configuration +config = get_server_config() + + +def list_plugins(plugin_type: str) -> List[str]: + """Find all plugins of the specified type.""" + return list(find_plugins(HiveMindPluginTypes(plugin_type))) + + +@click.group() +def cli(): + """A TUI for managing HiveMind configuration.""" + pass + + +@cli.command("list") +@click.argument("plugin_type", type=click.Choice(["network", "agent", "binary", "database"])) +def list_plugins_command(plugin_type): + """List available plugins of the given type. Valid: "network", "agent", "binary", "database" """ + if plugin_type not in ["network", "agent", "binary", "database"]: + click.echo(f"Invalid plugin type: {plugin_type}", err=True) + return + plugin_type = cast_to_enum(plugin_type) + plugins = list_plugins(plugin_type) + click.echo(json.dumps(plugins, indent=2)) + + +@cli.command("set") +@click.argument("plugin_type", type=click.Choice(["network", "agent", "binary", "database"])) +@click.argument("plugin_name") +def set_plugin(plugin_type, plugin_name): + """Set the plugin for a specific type. Valid: "network", "agent", "binary", "database" """ + if plugin_type not in ["network", "agent", "binary", "database"]: + click.echo(f"Invalid plugin type: {plugin_type}", err=True) + return + + plugin_type = cast_to_enum(plugin_type) + + available_plugins = list_plugins(plugin_type) + if plugin_name not in available_plugins: + click.echo(f"Plugin '{plugin_name}' not available for '{plugin_type}'.", err=True) + return + + config[mapping[plugin_type]]["module"] = plugin_name + config.store() + click.echo(f"Set {plugin_type} to {plugin_name}.") + + +@cli.command("get") +@click.argument("plugin_type", type=click.Choice(["network", "agent", "binary", "database"])) +def get_plugin(plugin_type): + """Get the current plugin for a specific type. Valid: "network", "agent", "binary", "database" """ + if plugin_type not in ["network", "agent", "binary", "database"]: + click.echo(f"Invalid plugin type: {plugin_type}", err=True) + return + plugin_type = cast_to_enum(plugin_type) + key = mapping[plugin_type] + if key in config and "module" in config[key]: + click.echo(config[plugin_type]["module"]) + else: + click.echo(f"No plugin set for {plugin_type}.") + + +@cli.command("show-config") +def show_config(): + """Show the full configuration.""" + click.echo(json.dumps(config, indent=2, ensure_ascii=False, sort_keys=True)) + + +if __name__ == "__main__": + cli() diff --git a/requirements.txt b/requirements.txt index e69de29..bedcc6e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -0,0 +1,3 @@ +json_database +ovos-bus-client +ovos-utils \ No newline at end of file diff --git a/setup.py b/setup.py index 1e5e444..e485319 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,6 @@ def get_version(): """ Find the version of the package""" - version = None version_file = os.path.join(BASEDIR, 'hivemind_plugin_manager', 'version.py') major, minor, build, alpha = (None, None, None, None) with open(version_file) as f: @@ -48,7 +47,10 @@ def required(requirements_file): url='https://github.com/JarbasHiveMind/hivemind-plugin-manager', license='Apache-2.0', author='jarbasAi', - #install_requires=required("requirements.txt"), + install_requires=required("requirements.txt"), author_email='jarbasai@mailfence.com', - description='plugin manager for hivemind-core' + description='plugin manager for hivemind-core', + entry_points={ + "console_scripts": ["hpm=hivemind_plugin_manager.tui:cli"] + } )