2021-09-21 21:49:05 +00:00
# Any alerts produced by the player.py instances.
import json
from typing import Any , Dict , List , Optional
from datetime import datetime , timedelta
from helpers . os_environment import resolve_external_file_path
from helpers . alert_manager import AlertProvider
from baps_types . alert import CRITICAL , WARNING , Alert
2021-09-21 23:57:51 +00:00
from baps_types . happytime import happytime
2021-09-21 21:49:05 +00:00
2021-09-22 18:49:24 +00:00
MODULE = " Player " # This should match the log file, so the UI will link to the logs page.
2021-09-21 21:49:05 +00:00
class PlayerAlertProvider ( AlertProvider ) :
2021-09-22 18:49:24 +00:00
_server_state : Dict [ str , Any ]
_states : List [ Optional [ Dict [ str , Any ] ] ] = [ ]
_player_count : int
def __init__ ( self ) :
# Player count only changes after server restart, may as well just load this once.
with open ( resolve_external_file_path ( " state/BAPSicleServer.json " ) ) as file :
self . _server_state = json . loads ( file . read ( ) )
self . _player_count = int ( self . _server_state [ " num_channels " ] )
self . _states = [ None ] * self . _player_count
# To simplify monitoring (and allow detection of things going super
# weird), we are going to read from the state file to work out the alerts.
def get_alerts ( self ) :
for channel in range ( self . _player_count ) :
with open ( resolve_external_file_path ( " state/Player {} .json " . format ( channel ) ) ) as file :
self . _states [ channel ] = json . loads ( file . read ( ) )
funcs = [ self . _channel_count , self . _initialised , self . _start_time ]
alerts : List [ Alert ] = [ ]
for func in funcs :
func_alerts = func ( )
if func_alerts :
alerts . extend ( func_alerts )
return alerts
def _channel_count ( self ) :
if self . _player_count < = 0 :
return [ Alert ( {
" start_time " : - 1 , # Now
" id " : " no_channels " ,
" title " : " There are no players configured. " ,
" description " : " The number of channels configured is {} . Please set to at least 1 on the ' Server Config ' page. " . format ( self . _player_count ) ,
" module " : MODULE + " Handler " ,
" severity " : CRITICAL
} ) ]
def _initialised ( self ) :
alerts : List [ Alert ] = [ ]
for channel in range ( self . _player_count ) :
if self . _states [ channel ] and not self . _states [ channel ] [ " initialised " ] :
alerts . append ( Alert ( {
" start_time " : - 1 , # Now
" id " : " player_ {} _not_initialised " . format ( channel ) ,
" title " : " Player {} is not initialised. " . format ( channel ) ,
" description " : " This typically means the player channel was not able find the configured sound output on the system. Please check the ' Player Config ' and Player logs to determine the cause. " ,
" module " : MODULE + str ( channel ) ,
" severity " : CRITICAL
} ) )
return alerts
def _start_time ( self ) :
server_start_time = self . _server_state [ " start_time " ]
server_start_time = datetime . fromtimestamp ( server_start_time )
delta = timedelta (
seconds = 30 ,
)
alerts : List [ Alert ] = [ ]
for channel in range ( self . _player_count ) :
start_time = self . _states [ channel ] [ " start_time " ]
start_time = datetime . fromtimestamp ( start_time )
if ( start_time > server_start_time + delta ) :
alerts . append ( Alert ( {
" start_time " : - 1 ,
" id " : " player_ {} _restarted " . format ( channel ) ,
" title " : " Player {} restarted after the server started. " . format ( channel ) ,
" description " :
""" Player {} last restarted at {} , after the server first started at {} , suggesting a failure.
2021-09-21 21:49:05 +00:00
This likely means there was an unhandled exception in the player code , causing the server to restart the player .
Please check player logs to investigate the cause . Please restart the server to clear this warning . """
2021-09-22 18:49:24 +00:00
. format ( channel , happytime ( start_time ) , happytime ( server_start_time ) ) ,
" module " : MODULE + str ( channel ) ,
" severity " : WARNING
} ) )
return alerts