Added libs
This commit is contained in:
217
noSys/networks.py
Normal file
217
noSys/networks.py
Normal file
@@ -0,0 +1,217 @@
|
||||
from typing import Dict, List, Optional, Any
|
||||
import time
|
||||
import random
|
||||
import threading
|
||||
|
||||
from libs.fspn.utils.wrapper_util import threaded
|
||||
from .noSysModule import NoSysModule
|
||||
from libs.app.common.store import DataStore
|
||||
from libs.app.common.logging import get_logger
|
||||
from libs.fspn.utils.sha256_util import hash_string
|
||||
from libs.rendezvous.rendezvousClient import RendezvousClient, RendezvousClientEvents as RendezvousEvents
|
||||
from .peers import Peer
|
||||
from .events import Events, DynamicEvents
|
||||
from .networksApiBlueprint import Blueprint
|
||||
|
||||
from enum import Enum
|
||||
|
||||
class NetworkStatus(Enum):
|
||||
IDLE = "idle"
|
||||
CONNECTING = "connecting"
|
||||
HEALTHY = "healthy"
|
||||
DEGRADED = "degraded"
|
||||
FAILED = "failed"
|
||||
|
||||
logger = get_logger("networks")
|
||||
|
||||
class Networks(NoSysModule):
|
||||
""" SOMETHING HERE."""
|
||||
|
||||
def __init__(self, nosys_core):
|
||||
super().__init__(nosys_core)
|
||||
|
||||
self.nosys_core.subscribe_event(Events.USER_ADDED, self.on_user_added)
|
||||
# self.nosys_core.subscribe_event(Events.PEER_CONNECTED, self.on_peer_connected)
|
||||
# self.nosys_core.subscribe_event(Events.PEER_DISCONNECTED, self.on_peer_disconnected)
|
||||
# self.nosys_core.subscribe_event(Events.PEER_CONNECTION_ERROR, self.on_peer_connection_error)
|
||||
|
||||
self.network_states = {}
|
||||
|
||||
def setup(self):
|
||||
self.rendezvous_client:RendezvousClient = self.nosys_core.modules.get("rendezvous", "rendezvousClient")
|
||||
self.rendezvous_client.subscribe_event(RendezvousEvents.SERVER_CONNECTED, self.on_server_connected)
|
||||
self.rendezvous_client.subscribe_event(RendezvousEvents.SERVER_DISCONNECTED, self.on_server_disconnected)
|
||||
self.rendezvous_client.subscribe_event(RendezvousEvents.SERVER_CONNECTION_ERROR, self.on_server_connection_error)
|
||||
self.nosys_core.modules.api.register_blueprint(Blueprint(self).blueprint)
|
||||
# self.socketio = HandlerSocketio(self)
|
||||
# self.nosys_core.modules.api.register_socketio(self.socketio)
|
||||
|
||||
def user_add_network(self, user_id, network_id):
|
||||
self.nosys_core.data.user_add_network(user_id, network_id)
|
||||
|
||||
def user_remove_network(self, user_id, network_id):
|
||||
self.nosys_core.data.user_remove_network(user_id, network_id)
|
||||
|
||||
def on_user_added(self, event):
|
||||
user_id:str = event.user_id
|
||||
user_data = self.nosys_core.data.get_user(user_id)
|
||||
for network_id in user_data.get("networks", []):
|
||||
self.network_states.get(network_id)["users"].append(user_id)
|
||||
|
||||
def on_nosys_ready(self, event):
|
||||
self.manage_networks()
|
||||
|
||||
def set_network(self, network):
|
||||
network_id = network["id"]
|
||||
if not network:
|
||||
raise ValueError(f"Network {network_id} not found")
|
||||
|
||||
if network_id not in self.network_states:
|
||||
self.nosys_core.subscribe_event(DynamicEvents.network_connection(network_id), self.on_network_connection)
|
||||
self.nosys_core.subscribe_event(DynamicEvents.network_disconnection(network_id), self.on_network_disconnection)
|
||||
|
||||
self.network_states[network_id] = {
|
||||
"id": network_id,
|
||||
"users" : [],
|
||||
"peers": [],
|
||||
"rendezvous": [],
|
||||
"status": NetworkStatus.IDLE.value,
|
||||
"managed": self.is_network_auto_start(network_id),
|
||||
"tries": 0
|
||||
}
|
||||
return self.network_states[network_id]
|
||||
|
||||
def is_network_auto_start(self, network_id):
|
||||
network = self.nosys_core.data.get_network(network_id)
|
||||
return network.get("config", {}).get("auto_connect", False)
|
||||
|
||||
def set_managed(self, network_id, value:bool):
|
||||
state = self.network_states[network_id]
|
||||
state["managed"] = value
|
||||
|
||||
@threaded
|
||||
def manage_networks(self):
|
||||
for network in self.networks:
|
||||
self.set_network(network)
|
||||
|
||||
while True:
|
||||
for network_id, state in self.network_states.items():
|
||||
if state["managed"]:
|
||||
self.manage_network(network_id)
|
||||
time.sleep(30)
|
||||
|
||||
def manage_network(self, network_id):
|
||||
state = self.network_states[network_id]
|
||||
network = self.nosys_core.data.get_network(network_id)
|
||||
|
||||
if state["status"] == NetworkStatus.IDLE.value:
|
||||
print(NetworkStatus.IDLE.value)
|
||||
self.connect_network_rendezvous_servers(network)
|
||||
|
||||
elif state["status"] == NetworkStatus.CONNECTING.value:
|
||||
print(NetworkStatus.CONNECTING.value)
|
||||
|
||||
elif state["status"] == NetworkStatus.DEGRADED.value:
|
||||
print(NetworkStatus.DEGRADED.value)
|
||||
self.request_new_peer(network_id=network_id)
|
||||
|
||||
elif state["status"] == NetworkStatus.HEALTHY.value:
|
||||
print(NetworkStatus.HEALTHY.value)
|
||||
|
||||
elif state["status"] == NetworkStatus.FAILED.value:
|
||||
print(NetworkStatus.FAILED.value)
|
||||
self.set_managed(network_id, False)
|
||||
|
||||
def connect_network_rendezvous_servers(self, network):
|
||||
network_id = network.get("id")
|
||||
state = self.network_states.get(network_id)
|
||||
if state["users"]:
|
||||
for rendezvous_id in network.get("rendezvous"):
|
||||
rendezvous = self.nosys_core.data.get_rendezvous(rendezvous_id)
|
||||
host_port = rendezvous.get("address").split(':')
|
||||
address = (host_port[0], int(host_port[1])) if len(host_port) > 1 else (host_port[0], 0)
|
||||
|
||||
peer = self.rendezvous_client.connect_to_server(address, random.choice(state["users"]))
|
||||
state["rendezvous"].append(peer.id)
|
||||
else:
|
||||
logger.debug(f"User missing to connect to the rendezvous servers of network {network_id}")
|
||||
|
||||
def on_server_connected(self, event):
|
||||
peer:Peer = event.peer
|
||||
peer_id = peer.id
|
||||
for network_id, state in self.network_states.items():
|
||||
if peer_id in state["rendezvous"]:
|
||||
print(f"Rendezvous {peer_id} connected for network {network_id}")
|
||||
|
||||
def on_server_connection_error(self, event):
|
||||
peer:Peer = event.peer
|
||||
peer_id = peer.id
|
||||
for network_id, state in self.network_states.items():
|
||||
if peer_id in state["rendezvous"]:
|
||||
state["rendezvous"].remove(peer_id)
|
||||
print(f"Rendezvous {peer_id} error for network {network_id}")
|
||||
|
||||
if not state["rendezvous"]:
|
||||
print(f"All rendezvous failed")
|
||||
state["tries"]+=1
|
||||
|
||||
self._recalc_network_status(network_id)
|
||||
|
||||
def on_server_disconnected(self, event):
|
||||
peer:Peer = event.peer
|
||||
peer_id = peer.id
|
||||
for network_id, state in self.network_states.items():
|
||||
if peer_id in state["rendezvous"]:
|
||||
state["rendezvous"].remove(peer_id)
|
||||
print(f"Rendezvous {peer_id} disconnected for network {network_id}")
|
||||
|
||||
def on_network_connection(self, event):
|
||||
network_id:str = event.network_id
|
||||
peer:Peer = event.peer
|
||||
|
||||
self.network_states[network_id]["peers"].append(peer.id)
|
||||
self._recalc_network_status(network_id)
|
||||
|
||||
def on_network_disconnection(self, event):
|
||||
network_id:str = event.network_id
|
||||
peer:Peer = event.peer
|
||||
|
||||
network_states = self.network_states.get(network_id)
|
||||
network_states["peers"].remove(peer.id)
|
||||
self._recalc_network_status(network_id)
|
||||
|
||||
def request_new_peer(self, network_id, peer_id=None):
|
||||
network_states = self.network_states[network_id]
|
||||
if not peer_id:
|
||||
peer_id = random.choice(network_states["peers"])
|
||||
|
||||
self.rendezvous_client.send_get_random_peer(peer_id, network_id)
|
||||
|
||||
def _set_status(self, network_id, status: NetworkStatus, details=None):
|
||||
state = self.network_states.get(network_id, {})
|
||||
state["status"] = status.value
|
||||
if details:
|
||||
state.update(details)
|
||||
|
||||
def _recalc_network_status(self, network_id):
|
||||
state = self.network_states.get(network_id)
|
||||
peers = state.get("peers", [])
|
||||
network = self.nosys_core.data.get_network(network_id)
|
||||
min_conn = network["config"]["min_connections"]
|
||||
|
||||
if len(peers) >= min_conn:
|
||||
self._set_status(network_id, NetworkStatus.HEALTHY)
|
||||
elif peers:
|
||||
self._set_status(network_id, NetworkStatus.DEGRADED)
|
||||
elif state["rendezvous"]:
|
||||
self._set_status(network_id, NetworkStatus.CONNECTING)
|
||||
elif state["tries"]>=3:
|
||||
self._set_status(network_id, NetworkStatus.FAILED)
|
||||
else:
|
||||
self._set_status(network_id, NetworkStatus.IDLE)
|
||||
|
||||
if state["managed"] == True:
|
||||
self.manage_network(network_id)
|
||||
|
||||
def is_network_healthy(self, network_id):
|
||||
return self.network_states.get(network_id, {}).get("status") == NetworkStatus.HEALTHY.value
|
||||
Reference in New Issue
Block a user