Skip to content

Commit

Permalink
Merge pull request #48 from JarbasHiveMind/release-3.2.1a1
Browse files Browse the repository at this point in the history
Release 3.2.1a1
  • Loading branch information
JarbasAl authored Jan 8, 2025
2 parents 387ea72 + f384932 commit 7748a1d
Show file tree
Hide file tree
Showing 6 changed files with 138 additions and 26 deletions.
14 changes: 11 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# Changelog

## [3.1.1a1](https://github.com/JarbasHiveMind/HiveMind-core/tree/3.1.1a1) (2025-01-03)
## [3.2.1a1](https://github.com/JarbasHiveMind/HiveMind-core/tree/3.2.1a1) (2025-01-07)

[Full Changelog](https://github.com/JarbasHiveMind/HiveMind-core/compare/3.1.0...3.1.1a1)
[Full Changelog](https://github.com/JarbasHiveMind/HiveMind-core/compare/3.2.0a1...3.2.1a1)

**Merged pull requests:**

- fix:binarization\_protocol [\#42](https://github.com/JarbasHiveMind/HiveMind-core/pull/42) ([JarbasAl](https://github.com/JarbasAl))
- fix: track last\_seen , add missing cli permission management scripts … [\#44](https://github.com/JarbasHiveMind/HiveMind-core/pull/44) ([JarbasAl](https://github.com/JarbasAl))

## [3.2.0a1](https://github.com/JarbasHiveMind/HiveMind-core/tree/3.2.0a1) (2025-01-07)

[Full Changelog](https://github.com/JarbasHiveMind/HiveMind-core/compare/3.1.1...3.2.0a1)

**Merged pull requests:**

- feat:multiple\_net\_protos [\#46](https://github.com/JarbasHiveMind/HiveMind-core/pull/46) ([JarbasAl](https://github.com/JarbasAl))



Expand Down
16 changes: 13 additions & 3 deletions hivemind_core/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@
"binarize": False, # default False because of a bug in old hivemind-bus-client versions

# sort encodings by order of preference
"allowed_encodings": ["JSON-Z85B", "JSON-B64", "JSON-HEX"],
"allowed_encodings": ["JSON-B64", "JSON-URLSAFE-B64",
"JSON-B91",
"JSON-Z85B", "JSON-Z85P",
"JSON-B32", "JSON-HEX"],
"allowed_ciphers": ["CHACHA20-POLY1305", 'AES-GCM'],

# configure various plugins
Expand All @@ -19,13 +22,19 @@
"port": 8181
}},
"binary_protocol": {"module": None},
"network_protocol": {"module": "hivemind-websocket-plugin",
"hivemind-websocket-plugin": {
"network_protocol": {"hivemind-websocket-plugin": {
"host": "0.0.0.0",
"port": 5678,
"ssl": False,
"cert_dir": f"{xdg_data_home()}/hivemind",
"cert_name": "hivemind"
},
"hivemind-http-plugin": {
"host": "0.0.0.0",
"port": 5679,
"ssl": False,
"cert_dir": f"{xdg_data_home()}/hivemind",
"cert_name": "hivemind"
}},
"database": {"module": "hivemind-json-db-plugin",
"hivemind-json-db-plugin": {
Expand All @@ -41,6 +50,7 @@ def get_server_config() -> JsonStorageXDG:
if not os.path.isfile(db.path):
db.merge(_DEFAULT)
db.store()
# ensure all top level keys are present
for k, v in _DEFAULT.items():
if k not in db:
db[k] = v
Expand Down
16 changes: 14 additions & 2 deletions hivemind_core/protocol.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import dataclasses
import json
import time
import uuid
from dataclasses import dataclass, field
from enum import Enum, IntEnum
Expand Down Expand Up @@ -80,9 +81,10 @@ class HiveMindClientConnection:
) # list of ovos message_type to allow to be sent from this client
binarize: bool = False
site_id: str = "unknown"
can_broadcast: bool = True
can_escalate: bool = True
can_propagate: bool = True
is_admin: bool = False
last_seen: float = -1

hm_protocol: Optional['HiveMindListenerProtocol'] = None

Expand Down Expand Up @@ -285,6 +287,14 @@ def handle_new_client(self, client: HiveMindClientConnection):
# if client is in protocol V1 -> self.handle_handshake_message
# clients can rotate their pubkey or session_key by sending a new handshake

def update_last_seen(self, client: HiveMindClientConnection):
"""track timestamps of last client interaction"""
with self.db:
user = self.db.get_client_by_api_key(client.key)
user.last_seen = time.time()
LOG.debug(f"updated last seen timestamp: {client.key} - {user.last_seen}")
self.db.update_item(user)

def handle_client_disconnected(self, client: HiveMindClientConnection):
try:
self.callbacks.on_disconnect(client)
Expand Down Expand Up @@ -399,6 +409,8 @@ def handle_message(self, message: HiveMessage, client: HiveMindClientConnection)
else:
self.handle_unknown_message(message, client)

self.update_last_seen(client)

# HiveMind protocol messages - from slave -> master
def handle_unknown_message(
self, message: HiveMessage, client: HiveMindClientConnection
Expand Down Expand Up @@ -568,7 +580,7 @@ def handle_broadcast_message(
"""
payload = self._unpack_message(message, client)

if not client.can_broadcast:
if not client.is_admin:
LOG.warning("Received broadcast message from downstream, illegal action")
if self.illegal_callback:
self.illegal_callback(payload)
Expand Down
85 changes: 80 additions & 5 deletions hivemind_core/scripts.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ def hmcore_cmds():
pass


##############$
# launch server
@hmcore_cmds.command(help="start listening for HiveMind connections", name="listen")
def listen():
service = HiveMindService()
service.run()


################
# Database management

@hmcore_cmds.command(help="add credentials for a client", name="add-client")
@click.option("--name", required=False, type=str)
@click.option("--access-key", required=False, type=str)
Expand Down Expand Up @@ -156,11 +167,8 @@ def list_clients():
console.print(table)


@hmcore_cmds.command(help="start listening for HiveMind connections", name="listen")
def listen():
service = HiveMindService()
service.run()

########################
# Message Permissions

@hmcore_cmds.command(help="allow message types to be sent from a client", name="allow-msg")
@click.argument("msg_type", required=True, type=str)
Expand Down Expand Up @@ -196,6 +204,73 @@ def blacklist_msg(msg_type, node_id):
break


@hmcore_cmds.command(help="allow 'ESCALATE' messages to be sent from a client", name="allow-escalate")
@click.argument("node_id", required=False, type=int)
def allow_escalate(node_id):
with ClientDatabase() as db:
node_id = node_id or prompt_node_id(db)
for client in db:
if client.client_id == int(node_id):
if client.can_escalate:
print(f"Client {client.name} already allowed to send 'ESCALATE' messages")
exit()
client.can_escalate = True
db.update_item(client)
print(f"Allowed 'ESCALATE' messages for {client.name}")
break


@hmcore_cmds.command(help="blacklist 'ESCALATE' messages from being sent by a client", name="blacklist-escalate")
@click.argument("node_id", required=False, type=int)
def blacklist_escalate(node_id):
with ClientDatabase() as db:
node_id = node_id or prompt_node_id(db)
for client in db:
if client.client_id == int(node_id):
if client.can_escalate:
client.can_escalate = False
db.update_item(client)
print(f"Blacklisted 'ESCALATE' messages for {client.name}")
return
print(f"Client '{client.name}' 'ESCALATE' messages already blacklisted")
break


@hmcore_cmds.command(help="allow 'PROPAGATE' messages to be sent from a client", name="allow-propagate")
@click.argument("node_id", required=False, type=int)
def allow_propagate(node_id):
with ClientDatabase() as db:
node_id = node_id or prompt_node_id(db)
for client in db:
if client.client_id == int(node_id):
if client.can_propagate:
print(f"Client {client.name} already allowed to send 'PROPAGATE' messages")
exit()
client.can_propagate = True
db.update_item(client)
print(f"Allowed 'PROPAGATE' messages for {client.name}")
break


@hmcore_cmds.command(help="blacklist 'PROPAGATE' messages from being sent by a client", name="blacklist-propagate")
@click.argument("node_id", required=False, type=int)
def blacklist_propagate(node_id):
with ClientDatabase() as db:
node_id = node_id or prompt_node_id(db)
for client in db:
if client.client_id == int(node_id):
if client.can_propagate:
client.can_propagate = False
db.update_item(client)
print(f"Blacklisted 'PROPAGATE' messages for {client.name}")
return
print(f"Client '{client.name}' 'PROPAGATE' messages already blacklisted")
break


##########################
# skill/intent permissions

@hmcore_cmds.command(help="blacklist skills from being triggered by a client", name="blacklist-skill")
@click.argument("skill_id", required=True, type=str)
@click.argument("node_id", required=False, type=int)
Expand Down
29 changes: 18 additions & 11 deletions hivemind_core/service.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import dataclasses
from typing import Callable, Optional, Type

from ovos_utils import create_daemon, wait_for_exit_signal
from ovos_utils.log import LOG
from ovos_utils.process_utils import ProcessStatus, StatusCallbackMap

Expand All @@ -17,12 +18,6 @@ def get_agent_protocol():
return AgentProtocolFactory.get_class(name), config.get(name, {})


def get_network_protocol():
config = get_server_config()["network_protocol"]
name = config["module"]
return NetworkProtocolFactory.get_class(name), config.get(name, {})


def get_binary_protocol():
config = get_server_config()["binary_protocol"]
name = config["module"]
Expand Down Expand Up @@ -121,14 +116,26 @@ def run(self):
binary_data_protocol=bin_protocol,
agent_protocol=agent_protocol)

# start network protocol that will deliver HiveMessages
network_class, net_config = get_network_protocol()
LOG.info(f"Network protocol: {network_class.__name__}")
# start network protocols that will carry HiveMessages
protos = []
for plug_name, plug_conf in get_server_config()["network_protocol"].items():
try:
network_class = NetworkProtocolFactory.get_class(plug_name)
LOG.info(f"Network protocol: {network_class.__name__}")
protos.append(network_class(hm_protocol=hm_protocol, config=plug_conf))
except:
LOG.exception(f"Failed to load plugin '{plug_name}'")

if not protos:
LOG.error("No network protocols were loaded. Exiting service.")
self._status.set_stopping()
return

network_protocol = network_class(hm_protocol=hm_protocol, config=net_config)
for network_protocol in protos:
create_daemon(network_protocol.run)

self._status.set_ready()

network_protocol.run() # blocking
wait_for_exit_signal() # block until ctrl+c

self._status.set_stopping()
4 changes: 2 additions & 2 deletions hivemind_core/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# START_VERSION_BLOCK
VERSION_MAJOR = 3
VERSION_MINOR = 1
VERSION_MINOR = 2
VERSION_BUILD = 1
VERSION_ALPHA = 0
VERSION_ALPHA = 1
# END_VERSION_BLOCK

0 comments on commit 7748a1d

Please sign in to comment.