import random import time import numpy as np from coapthon import defines class SupervisorError(Exception): def __init__(self, *args: object) -> None: super().__init__(*args) class NoRttError(SupervisorError): def __init__(self, *args: object) -> None: super().__init__(*args) class SuperviseurLocalPlaceHolder(): """Class de base pour le superviseur """ N_MESURE = 0 def __init__(self, client_CoAP) -> None: client_CoAP.superviseur = self self.client = client_CoAP self._RTTs = [] self._taux_retransmition = 0 self._RTO = defines.ACK_TIMEOUT def envoie_message(self, message) -> None: self.envoie_token(message.token) def reception_message(self, message) -> None: self.reception_token(message.token) def envoie_token(self, token) -> None: pass def reception_token(self, tokken) -> None: pass def failed_request(self): pass @property def RTTs(self): return self._RTTs @property def taux_retransmission(self): return self._taux_retransmition @property def min_RTT(self): """Valeur minimum du RTT""" if len(self.RTTs): return min(self.RTTs) raise NoRttError @property def avg_RTT(self): """Moyenne du RTT.""" if len(self.RTTs): return sum(self.RTTs)/len(self.RTTs) raise NoRttError @property def RTO(self): return self._RTO return random.uniform(self._RTO, (self._RTO * defines.ACK_RANDOM_FACTOR)) class SuperviseurLocal(SuperviseurLocalPlaceHolder): """ Class implementant la supervision local de chaque client. """ N_MESURE = 2 def __init__(self, client_CoAP) -> None: super().__init__(client_CoAP) self._dict_envoie = {} self._n_envoie = 0 self._n_token = 0 self._n_echec = 0 def envoie_token(self, token) -> None: """Enregistre l'envoie d'un token Args: token (int): Token à enregistrer """ self._n_envoie += 1 self._n_token += not(token in self._dict_envoie) self._dict_envoie[token] = time.time() self._taux_retransmition = 1 - self._n_token/self._n_envoie def reception_token(self, token) -> None: """Enregistre l'arrivée d'un token Args: token (int): Token à enregister """ if token in self._dict_envoie: rtt = time.time() - self._dict_envoie[token] self._RTTs.append(time.time() - self._dict_envoie[token]) # del self._dict_envoie[token] self.callback_new_rtt(rtt) else: pass # raise ValueError("Tokken inconnue") def failed_request(self): self._n_echec += 1 return super().failed_request() def callback_new_rtt(self, rtt): pass def reset(self): self._dict_envoie = {} self._n_envoie = 0 self._n_token = 0 self._n_echec = 0 self._RTTs = [] class SuperviseurLocalFiltre(SuperviseurLocal): N_MESURE = 3 def __init__(self, client_CoAP, rtt_init=0.01, alpha_l=0.01, alpha_s=0.1) -> None: super().__init__(client_CoAP) self.alpha_l = alpha_l self.alpha_s = alpha_s self._RTT_L = rtt_init self._RTT_S = rtt_init def callback_new_rtt(self, rtt): self._RTT_L = rtt*self.alpha_l + (1 - self.alpha_l) * self._RTT_L self._RTT_S = rtt*self.alpha_s + (1 - self.alpha_s) * self._RTT_S return super().callback_new_rtt(rtt) @property def RTT_L(self): return self._RTT_L @property def RTT_S(self): return self._RTT_S class SuperviseurGlobal(): nombre_mesure = 3 def __init__(self, clients, superviseur_type, *superviseur_args) -> None: """Genère un superviseur global pour la liste de client donnée Args: clients (List(HelperClient)): Liste des clients à supervisé superviseur_type (Type): Type de superviseur à utilisé """ self.clients = clients self.superviseurs = [superviseur_type( client, *superviseur_args) for client in clients] self._last_state = np.zeros((superviseur_type.N_MESURE, len(clients))) @property def state(self): """[summary] Returns: [type]: [description] """ """ taux_retransmissions = np.array( [superviseur.taux_retransmission for superviseur in self.superviseurs]) min_rtts = np.array( [superviseur.min_RTT for superviseur in self.superviseurs]) avg_rtts = np.array( [superviseur.avg_RTT for superviseur in self.superviseurs]) ratio_rtts = np.array(min_rtts/avg_rtts) if isinstance(self.superviseurs[0], SuperviseurLocalFiltre): rtt_ls = np.array( [superviseur.RTT_L for superviseur in self.superviseurs]) rtt_ss = np.array( [superviseur.RTT_S for superviseur in self.superviseurs]) ratio_filtres = rtt_ss/rtt_ls representation_etat = np.array( [taux_retransmissions, ratio_rtts, ratio_filtres]) else: representation_etat = np.array([taux_retransmissions, ratio_rtts]) return representation_etat """ vecteurs = [] for n, superviseur in enumerate(self.superviseurs): if isinstance(superviseur, SuperviseurLocalFiltre): try : vecteurs.append(np.array([[superviseur.taux_retransmission, superviseur.min_RTT/superviseur.avg_RTT, superviseur.RTT_S/superviseur.RTT_L]], dtype=np.float32)) except NoRttError: vecteurs.append(self._last_state[:,n]) return np.concatenate(vecteurs, axis=0).T def application_action(self, actions): for n, alpha in enumerate(actions): if alpha >= 0: g = 1 + alpha else: g = 1/(1-alpha) self.superviseurs[n]._RTO *= g self.superviseurs[n]._RTO = min([self.superviseurs[n]._RTO, 2]) def reset(self): [superviseur.reset() for superviseur in self.superviseurs] def qualite(self, n_request, beta_retransmission, beta_equite, beta_RTO): n_envoies = np.array([ superviseur._n_envoie for superviseur in self.superviseurs]) n_tokens = np.array([superviseur._n_token for superviseur in self.superviseurs]) RTOs = np.array([superviseur.RTO for superviseur in self.superviseurs]) qualite = 0 qualite -= beta_retransmission * sum(n_tokens)/sum(n_envoies) qualite += beta_equite * \ (sum(n_envoies/n_tokens))**2 / \ (len(n_envoies) * sum((n_envoies/n_tokens)**2)) qualite -= beta_RTO * np.max(RTOs) return qualite