from typing import Dict, List, Optional, Any from libs.fspn.utils.sha256_util import hash_string from libs.app.common.store import DataStore from libs.app.common.logging import get_logger from libs.noSys.noSysModule import NoSysModule from libs.noSys.peers import Peer from .networksApiBlueprint import Blueprint logger = get_logger("networks") class Networks(NoSysModule): def __init__(self, nosys_core): super().__init__(nosys_core) self.store = DataStore(path="p2private/networkData.json", default_data={"networks":[], "messages":[]}) self.network_states = {} def setup(self): self.nosys_core.modules.api.register_blueprint(Blueprint(self).blueprint) from .p2private import P2private self.p2private_module:P2private = self.nosys_core.modules.get("p2private", "p2private") from libs.p2post.p2post import P2post self.p2post_module:P2post = self.nosys_core.modules.get("p2post", "p2post") def on_nosys_ready(self, event): for network in self.networks: if not self.get_network(network["id"]): self.add_network(network["id"]) def on_module_message(self, event): handler_action = getattr(self, 'on_'+event.data.get("action")) handler_action(event) def post_network_message(self, message, networks=[]): for network_id in networks: if not self.get_message(message["hash"]): self.add_message(message["hash"], message["from"], message["to"], message["content"], message["timestamp"], message["signature"]) self.add_message_to_network(network_id, message["hash"]) state = self.network_states.get(network_id, []) for peer in state.get("peers", []): self.send_network_message(network_id, message["hash"], peer) def on_network_connection(self, event): network_id = event.network_id peer_id = event.peer.id if network_id not in self.network_states: self.network_states[network_id] = {"peers":[], "status":0} # TODO ENUM status self.network_states[network_id]["peers"].append(peer_id) self.send_network_hash(network_id, peer_id) def send_network_hash(self, network_id:str, peer_id:str): hash = self.get_network_hash(network_id) self.nosys_core.dispatcher.send_message({'action':'network_hash','network':network_id, "hash":hash}, peer_id, self.id) def on_network_hash(self, event): peer: Peer = event.peer data = event.data network_id = data["network"] if data["hash"] != self.get_network_hash(network_id): self.send_network_messages(network_id, peer.id) def send_network_messages(self, network_id, peer_id): messages = self.get_network(network_id)["messages"] self.nosys_core.dispatcher.send_message({'action':'network_messages','network':network_id, "messages":messages}, peer_id, self.id) def on_network_messages(self, event): peer: Peer = event.peer data = event.data network_id = data["network"] messages = data["messages"] for hash in messages: if not self.get_message(hash): self.send_get_network_message(network_id, hash, peer.id) def send_get_network_message(self, network_id, message_id, peer_id): self.nosys_core.dispatcher.send_message({'action':'get_network_message', "network":network_id, "message":message_id}, peer_id, self.id) def on_get_network_message(self, event): peer: Peer = event.peer data = event.data self.send_network_message(data["network"], data["message"], peer.id) def send_network_message(self, network_id, message_id, peer_id): message = self.get_message(message_id) self.nosys_core.dispatcher.send_message({'action':'network_message', "network":network_id, "message":message}, peer_id, self.id) def on_network_message(self, event): data = event.data network_id = data["network"] message = data["message"] if not self.get_message(message["hash"]): self.add_message(message["hash"], message["from"], message["to"], message["content"], message["timestamp"], message["signature"]) # TODO Check if not in network messages self.add_message_to_network(network_id, message["hash"]) self.post_network_message(message, [network_id]) self.check_message_to_me(message) def check_message_to_me(self, message): if self.p2post_module.data.get_user(message["to"]): self.p2private_module.data.add_message(message) # TODO SEND RECEIVED SIGNATURE TO THE NETWORKS IF USER LOGGED def get_network_hash(self, network_id: str) -> str: network = self.get_network(network_id) if not network: return "" combined = ''.join(sorted(network["messages"])) return hash_string(combined) # ------------------- MESSAGE CRUD ------------------- def add_message(self, hash: str, from_id:str, to_id:str, content:str, timestamp, signature:str): if self.get_message(hash): raise ValueError(f"Message {hash} already exists") message = {"hash": hash, "from": from_id, "to":to_id, "content":content, "timestamp":timestamp, "signature":signature} self.store.add_item("messages", message, unique=True, id_field="hash", id=hash) return message def get_message(self, hash: str): return self.store.get_item("messages", "hash", hash) def delete_message(self, hash: str) -> bool: return self.store.remove_item("messages", "hash", hash) def list_messages(self): return self.store.list_items("messages") def update_message(self, hash: str, updates: Dict[str, Any]) -> bool: return self.store.update_item("messages", "hash", hash, updates) # ------------------- NETWORK CRUD ------------------- def add_network(self, network_id: str): if self.get_network(network_id): raise ValueError(f"Network {network_id} already exists") network = {"id": network_id, "messages": []} self.store.add_item("networks", network, unique=True, id_field="id", id=network_id) return network def get_network(self, network_id: str): return self.store.get_item("networks", "id", network_id) def delete_network(self, network_id: str) -> bool: return self.store.remove_item("networks", "id", network_id) def list_networks(self): return self.store.list_items("networks") def update_network(self, network_id: str, updates: Dict[str, Any]) -> bool: return self.store.update_item("networks", "id", network_id, updates) def add_message_to_network(self, network_id:str, message_id:str): network = self.get_network(network_id) if network and message_id not in network["messages"]: network["messages"].append(message_id) self.update_network(network_id, network) return True return False