[docs]asyncdefsort_key_nodes(node:Node,region:str=None)->float:"""The sort key for nodes."""returnawaitnode.penalty_with_region(region)
[docs]classPenalty:"""Represents the penalty of the stats of a Node"""__slots__=("_stats",)def__init__(self,stats:Stats)->None:self._stats=stats@propertydefplayer_penalty(self)->int:"""The penalty of the players playing on the node. This is the number of players playing in the node. """returnself._stats.playing_players@propertydefcpu_penalty(self)->float:"""The penalty of the cpu load of the node"""return1.05**(100*self._stats.system_load)*10-10@propertydefnull_frame_penalty(self)->float|int:"""The penalty of the nulled frames of the node"""null_frame_penalty=0ifself._stats.frames_nulled!=-1:null_frame_penalty=(1.03**(500*(self._stats.frames_nulled/3000)))*300-300null_frame_penalty*=2returnnull_frame_penalty@propertydefdeficit_frame_penalty(self)->float|int:"""The penalty of the deficit frames of the node"""return(1.03**(500*(self._stats.frames_deficit/3000))*600-600ifself._stats.frames_deficit!=-1else0)# noinspection PyProtectedMember@propertydefspecial_handling(self)->float:"""The special handling penalty of the node."""# Node connection isn't ready yetifnotself._stats._node.is_ready:return1000000# Ws connection isn't available yetifnotself._stats._node.available:return1000000matchself._stats._node.identifier:# PyLav external are feature full nodes and will usually be better than the other external nodescase1|2:return-50# If the node is a lava.link node then lets penalise it heavilycase1001:return2000# EnvVar nodes are always the second best nodes as they are explicitly setcase31415:return-1500# Bundled nodes are always the best nodesifself._stats._node.managed:# These are nodes already in the same machine using the config port - they are considered good but since they aren't fully managed they are not the bestifself._stats._node.name.startswith("PyLavPortConflictRecovery"):return-500# This is a fully managed bundled node - it is the bestreturn-2000# Reduce the penalty of the node based on how many features it hasreturn-1*len(self._stats._node._capabilities)@propertydeftotal(self)->float:"""The total penalty of the node. This is the sum of the penalties of the node. """# noinspection PyProtectedMemberreturn(self.player_penalty+self.cpu_penalty+self.null_frame_penalty+self.deficit_frame_penalty+self._stats._node.down_votes*100+self.special_handling)def__repr__(self)->str:# noinspection PyProtectedMemberreturn(f"<Penalty player={self.player_penalty} "f"cpu={self.cpu_penalty} "f"null_frame={self.null_frame_penalty} "f"deficit_frame={self.deficit_frame_penalty} "f"votes={self._stats._node.down_votes*100} "f"feature_weighting={self.special_handling} "f"total={self.total}>")
[docs]classStats:"""Represents the stats of Lavalink node"""__slots__=("_node","_data","_penalty","_memory","_cpu","_frame_stats",)def__init__(self,node:Node,data:StatsMessage)->None:self._node=nodeself._data=dataself._memory=data.memoryself._cpu=data.cpuself._frame_stats=data.frameStatsself._penalty=Penalty(self)@propertydefuptime(self)->int:"""How long the node has been running for in milliseconds"""returnself._data.uptime@propertydefuptime_seconds(self)->float:"""How long the node has been running for in seconds"""returnself.uptime/1000@propertydefplayers(self)->int:"""The amount of players connected to the node"""returnself._data.playersorself._node.connected_count@propertydefplaying_players(self)->int:"""The amount of players that are playing in the node"""returnself._data.playingPlayersorself._node.playing_count@propertydefmemory_free(self)->int:"""The amount of memory free to the node"""returnself._memory.free@propertydefmemory_used(self)->int:"""The amount of memory that is used by the node"""returnself._memory.used@propertydefmemory_allocated(self)->int:"""The amount of memory allocated to the node"""returnself._memory.allocated@propertydefmemory_reservable(self)->int:"""The amount of memory reservable to the node"""returnself._memory.reservable@propertydefcpu_cores(self)->int:"""The amount of cpu cores the system of the node has"""returnself._cpu.cores@propertydefsystem_load(self)->float:"""The overall CPU load of the system"""returnself._cpu.systemLoad@propertydeflavalink_load(self)->float:"""The CPU load generated by Lavalink"""returnself._cpu.lavalinkLoad@propertydefframes_sent(self)->int:"""The number of frames sent to Discord. Warning ------- Given that audio packets are sent via UDP, this number may not be 100% accurate due to dropped packets. """returnself._frame_stats.sentifself._frame_statselse-1@propertydefframes_nulled(self)->int:"""The number of frames that yielded null, rather than actual data"""returnself._frame_stats.nulledifself._frame_statselse-1@propertydefframes_deficit(self)->int:"""The number of missing frames. Lavalink generates this figure by calculating how many packets to expect per minute, and deducting ``frames_sent``. Deficit frames could mean the CPU is overloaded, and isn't generating frames as quickly as it should be. """returnself._frame_stats.deficitifself._frame_statselse-1@propertydefpenalty(self)->Penalty:"""The penalty for the node"""returnself._penaltydef__repr__(self)->str:return(f"<Stats node_id={self._node.identifier} "f"uptime={self.uptime} "f"players={self.players} "f"playing_players={self.playing_players} "f"memory_free={self.memory_free} "f"memory_used={self.memory_used} "f"memory_allocated={self.memory_allocated} "f"memory_reservable={self.memory_reservable} "f"cpu_cores={self.cpu_cores} "f"system_load={self.system_load} "f"lavalink_load={self.lavalink_load} "f"frames_sent={self.frames_sent} "f"frames_nulled={self.frames_nulled} "f"frames_deficit={self.frames_deficit}> "f"penalty={self.penalty}>")