Skip to content
This repository has been archived by the owner on Dec 22, 2024. It is now read-only.

Commit

Permalink
feat/json_redis_sqlite_db_options (#90)
Browse files Browse the repository at this point in the history
* feat!:configurable_database_backend

allow several database backends

Update test/unittests/test_db.py

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update hivemind_core/service.py

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* add sqlite support

Update README.md

* @coderabbitai review

* Update README.md

* improve redis search

* ensure typing in sqlite

* fix db paths

* fix

* redis password

* redis password

* reset version to 0.1.0

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
  • Loading branch information
JarbasAl and coderabbitai[bot] authored Dec 20, 2024
1 parent aa4d0ff commit 79a3ceb
Show file tree
Hide file tree
Showing 8 changed files with 1,401 additions and 448 deletions.
339 changes: 272 additions & 67 deletions README.md

Large diffs are not rendered by default.

817 changes: 627 additions & 190 deletions hivemind_core/database.py

Large diffs are not rendered by default.

12 changes: 7 additions & 5 deletions hivemind_core/protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ class HiveMindListenerProtocol:
require_crypto: bool = True # throw error if crypto key not available
handshake_enabled: bool = True # generate a key per session if not pre-shared
identity: Optional[NodeIdentity] = None
db: Optional[ClientDatabase] = None
# below are optional callbacks to handle payloads
# receives the payload + HiveMindClient that sent it
escalate_callback = None # slave asked to escalate payload
Expand All @@ -262,8 +263,9 @@ class HiveMindListenerProtocol:
mycroft_bus_callback = None # slave asked to inject payload into mycroft bus
shared_bus_callback = None # passive sharing of slave device bus (info)

def bind(self, websocket, bus, identity):
def bind(self, websocket, bus, identity, db: ClientDatabase):
self.identity = identity
self.db = db
websocket.protocol = self
self.internal_protocol = HiveMindListenerInternalProtocol(bus)
self.internal_protocol.register_bus_handlers()
Expand Down Expand Up @@ -755,10 +757,10 @@ def _update_blacklist(self, message: Message, client: HiveMindClientConnection):
message.context["session"] = client.sess.serialize()

# update blacklist from db, to account for changes without requiring a restart
with ClientDatabase() as users:
user = users.get_client_by_api_key(client.key)
client.skill_blacklist = user.blacklist.get("skills", [])
client.intent_blacklist = user.blacklist.get("intents", [])
user = self.db.get_client_by_api_key(client.key)
client.skill_blacklist = user.skill_blacklist or []
client.intent_blacklist = user.intent_blacklist or []
client.msg_blacklist = user.message_blacklist or []

# inject client specific blacklist into session
if "blacklisted_skills" not in message.context["session"]:
Expand Down
324 changes: 214 additions & 110 deletions hivemind_core/scripts.py

Large diffs are not rendered by default.

80 changes: 44 additions & 36 deletions hivemind_core/service.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,42 +134,48 @@ def open(self):
handshake=handshake,
loop=self.protocol.loop,
)
if self.protocol.db is None:
# should never happen, but double check!
LOG.error("Database connection not initialized. Please ensure database configuration is correct.")
LOG.exception(f"Client {self.client.peer} connection attempt failed due to missing database connection")
self.close()
raise RuntimeError("Database was not initialized!") # let it propagate, this is developer error most likely

user = self.protocol.db.get_client_by_api_key(key)

if not user:
LOG.error("Client provided an invalid api key")
self.protocol.handle_invalid_key_connected(self.client)
self.close()
return

self.client.crypto_key = user.crypto_key
self.client.msg_blacklist = user.message_blacklist or []
self.client.skill_blacklist = user.skill_blacklist or []
self.client.intent_blacklist = user.intent_blacklist or []
self.client.allowed_types = user.allowed_types
self.client.can_broadcast = user.can_broadcast
self.client.can_propagate = user.can_propagate
self.client.can_escalate = user.can_escalate
if user.password:
# pre-shared password to derive aes_key
self.client.pswd_handshake = PasswordHandShake(user.password)

self.client.node_type = HiveMindNodeType.NODE # TODO . placeholder

with ClientDatabase() as users:
user = users.get_client_by_api_key(key)
if not user:
LOG.error("Client provided an invalid api key")
self.protocol.handle_invalid_key_connected(self.client)
self.close()
return

self.client.crypto_key = user.crypto_key
self.client.msg_blacklist = user.blacklist.get("messages", [])
self.client.skill_blacklist = user.blacklist.get("skills", [])
self.client.intent_blacklist = user.blacklist.get("intents", [])
self.client.allowed_types = user.allowed_types
self.client.can_broadcast = user.can_broadcast
self.client.can_propagate = user.can_propagate
self.client.can_escalate = user.can_escalate
if user.password:
# pre-shared password to derive aes_key
self.client.pswd_handshake = PasswordHandShake(user.password)

self.client.node_type = HiveMindNodeType.NODE # TODO . placeholder

if (
not self.client.crypto_key
and not self.protocol.handshake_enabled
and self.protocol.require_crypto
):
LOG.error(
"No pre-shared crypto key for client and handshake disabled, "
"but configured to require crypto!"
)
# clients requiring handshake support might fail here
self.protocol.handle_invalid_protocol_version(self.client)
self.close()
return
if (
not self.client.crypto_key
and not self.protocol.handshake_enabled
and self.protocol.require_crypto
):
LOG.error(
"No pre-shared crypto key for client and handshake disabled, "
"but configured to require crypto!"
)
# clients requiring handshake support might fail here
self.protocol.handle_invalid_protocol_version(self.client)
self.close()
return

self.protocol.handle_new_client(self.client)
# self.write_message(Message("connected").serialize())
Expand Down Expand Up @@ -197,6 +203,7 @@ def __init__(
protocol=HiveMindListenerProtocol,
bus=None,
ws_handler=MessageBusEventHandler,
db: ClientDatabase = None
):
websocket_config = websocket_config or Configuration().get(
"hivemind_websocket", {}
Expand All @@ -208,6 +215,7 @@ def __init__(
on_error=error_hook,
on_stopping=stopping_hook,
)
self.db = db or ClientDatabase()
self._proto = protocol
self._ws_handler = ws_handler
if bus:
Expand Down Expand Up @@ -256,7 +264,7 @@ def run(self):
loop = ioloop.IOLoop.current()

self.protocol = self._proto(loop=loop)
self.protocol.bind(self._ws_handler, self.bus, self.identity)
self.protocol.bind(self._ws_handler, self.bus, self.identity, self.db)
self.status.bind(self.bus)
self.status.set_started()

Expand Down
6 changes: 3 additions & 3 deletions hivemind_core/version.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# START_VERSION_BLOCK
VERSION_MAJOR = 0
VERSION_MINOR = 14
VERSION_BUILD = 1
VERSION_ALPHA = 0
VERSION_MINOR = 1
VERSION_BUILD = 0
VERSION_ALPHA = 1
# END_VERSION_BLOCK
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def required(requirements_file):


setup(
name="jarbas_hive_mind",
name="hivemind-core",
version=get_version(),
packages=["hivemind_core"],
include_package_data=True,
Expand Down
Loading

0 comments on commit 79a3ceb

Please sign in to comment.