import sys, os import math from enum import Enum, auto from pathlib import Path import time import json from datetime import datetime, timezone from libs.noSys.noSysModule import NoSysModule from libs.noSys.events import Events as NoSysEvents, DynamicEvents as NoSysDynamicEvents from libs.noSys.networks import Networks from libs.noSys.peers import Peer from libs.app.common.logging import get_logger from libs.app.common.paths import ROOT_DIR, FILES_DIR from libs.fspn.utils.sha256_util import hash_file, hash_bytes from libs.app.common.store import DataStore from libs.p2post.p2postApiBlueprint import Blueprint from libs.p2post.p2postSocketio import HandlerSocketio from libs.fileTransfer.fileTransfer import FileTransfer, File, FileEvents from .dataManager import DataManager logger = get_logger() class P2postEvents(Enum): ON_RECEIVING_ = auto() class P2post(NoSysModule): def __init__(self, nosys_core): super().__init__(nosys_core) self.data = DataManager() self.file_transfer:FileTransfer = None self.requested_signatures = {} def setup(self): self.nosys_core.subscribe_event(NoSysEvents.USER_ADDED, self.on_user_added) self.nosys_core.modules.api.register_blueprint(Blueprint(self).blueprint) self.nosys_core.modules.api.register_socketio(HandlerSocketio(self)) self.networks_module:Networks = self.nosys_core.modules.get("noSys", "networks") self.file_transfer = self.nosys_core.modules.get("fileTransfer", "fileTransfer") self.file_transfer.subscribe_module_file_events(self.id, self.on_file_event) def on_nosys_ready(self, event): pass def on_user_added(self, event): user_id = event.user_id if not self.data.get_user(user_id): temp_nickname = user_id[:4] + "..." + user_id[-4:] self.data.add_user(user_id, temp_nickname) def on_file_event(self, event): file:File = event.file file.subscribe_event(FileEvents.ON_FILE_COMPLETED.name, self.on_file_done) file.subscribe_event(FileEvents.ON_FILE_ERROR.name, self.on_file_done) file.subscribe_event(FileEvents.ON_FILE_UPDATE.name, self.on_file_update) logger.error(f"{file.status} {file.id}") file.approve_transfer(True) # TODO Check configuration def on_file_done(self, event): logger.info(f"File Done {event.source.status} {event.source.hash}") self.data.add_media(event.source.hash, event.final_path) def on_file_update(self, event): pass def on_module_connection(self, event): pass # self.send_networks(event.connection.id) def on_module_message(self, event): action = event.data['action'] handler_action = getattr(self, 'on_'+action) handler_action(event) def on_network_connection(self, event): network_id:str = event.network_id peer:Peer = event.peer self.send_network_post(network_id, peer.id) def send_network_post(self, network_id, peer_id): network = self.data.get_network(network_id) if network: body = {"action":"network_posts", "hash":network["hash"], "posts":network["posts"]} self.nosys_core.dispatcher.send_message(body, peer_id, self.id) def on_network_posts(self, event): payload = event.data network = self.data.get_network(payload["hash"]) if network: for post in payload["posts"]: if not self.data.get_post(post): self.send_get_post(post, network, event.peer.id) def send_get_post(self, hash, network, peer_id): body = {"action":"get_post", "hash":hash, "network":network} self.nosys_core.dispatcher.send_message(body, peer_id, self.id) def on_get_post(self, event): payload = event.data self.send_post(payload["hash"], payload["network"], event.peer.id) def send_post(self, hash, network, peer_id): post = self.data.get_post(hash) body = {"action":"post", "post":post, "network":network} self.nosys_core.dispatcher.send_message(body, peer_id, self.id) def on_post(self, event): payload = event.data post = payload["post"] network = payload["network"] # TODO VERIFY POST if not self.data.get_post(post["hash"]): self.data.add_post(post["hash"], post["timestamp"], post["author"], post["content"], post["signature"], post["medias"]) for media in post["medias"]: if media["type"] == "local" and (not self.data.get_media(media["hash"])): self.send_get_media(media["hash"], event.peer.id) self.data.get_network(network)["posts"].append(post["hash"]) if not self.data.get_user(post["author"]): author_key = post["author"] temp_nickname = author_key[:4] + "..." + author_key[-4:] self.data.add_user(author_key, temp_nickname) self.data.store.save() elif post["hash"] not in self.data.get_network(network)["posts"]: self.data.get_network(network)["posts"].append(post["hash"]) self.data.store.save() def send_get_media(self, hash, peer_id): body = {"action":"get_media", "hash":hash} self.nosys_core.dispatcher.send_message(body, peer_id, self.id) def on_get_media(self, event): payload = event.data media = self.data.get_media(payload["hash"]) self.file_transfer.send_file(media["file_path"], event.peer.id, self.id) def create_post(self, author, content, medias, networks:list[str]): # TODO File server to respond frontend requests medias_data = [] for media in medias: if media["type"] == "local": file_hash = os.path.splitext(os.path.basename(media["file_path"]))[0] medias_data.append({"type":"local", "hash":file_hash}) self.data.add_media(file_hash, media["file_path"]) else: medias_data.append({"type":media["type"], "url":media["url"]}) current_utc_datetime = datetime.now(timezone.utc) utc_timestamp = current_utc_datetime.timestamp() post = { "timestamp": utc_timestamp, "author": author, "content": content, "medias": medias_data } post_serialized = json.dumps(post, sort_keys=True, separators=(",", ":")) post["hash"] = hash_bytes(post_serialized.encode('utf-8')) request_id = self.nosys_core.modules.pmc.sign(post["hash"], author, self.signature_callback, f"New Post {post}") self.requested_signatures[request_id] = (post, networks) logger.debug(f"Post waiting signature {request_id}: {post}") return post["hash"] def signature_callback(self, request_id, signature): post, networks = self.requested_signatures[request_id] if signature: self.data.add_post(post["hash"], post["timestamp"], post["author"], post["content"], signature, post["medias"]) for network in networks: self.data.get_network(network)["posts"].append(post["hash"]) network_state = self.networks_module.network_states.get(network) for peer in network_state["peers"]: self.send_post(post["hash"], network, peer) self.data.store.save() def test(self): file_path = r"C:\Workspace\libs\noSys\index.html" file_url = "https://pbs.twimg.com/media/GwvwQamW4AAQYiD?format=jpg&name=small" medias = [] medias.append({ "type":"local", "file_path": file_path }) medias.append({ "type":"external", "url": file_url }) self.create_post("A4DZSk+TlR+4w39MbiIAQbti+N0H1QlJEhRH2DI6Iubj", "ContentTest", medias, ["629985fd999a675072a2e3f22f74e60c62e8c5b8efb21478c9b04e7ff2fe9779",])