2012-05-29 13:31:11 +00:00
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# error DERPRECATED
# include "stdpch.h"
# include "shutdown_handler.h"
# include "nel/net/service.h"
# include "nel/net/message.h"
# include "nel/net/unified_network.h"
# include "player_manager/player_manager.h"
# include "player_manager/player.h"
using namespace std ;
using namespace NLMISC ;
using namespace NLNET ;
// Shutdown State
CShutdownHandler : : TState CShutdownHandler : : _State = CShutdownHandler : : Running ;
// Shutdown Timeout
NLMISC : : TTime CShutdownHandler : : _ShutdownTimeout = 0 ;
// Shutdown Timeout
NLMISC : : TTime CShutdownHandler : : _NextBroadcastMessage ;
// ShardOpen has been closed
bool CShutdownHandler : : _ShardClosed = false ;
// Broadcast Message Rate
uint CShutdownHandler : : _BroadcastMessageRate = 0 ;
// Game cycle of last config file check
NLMISC : : TGameCycle CAutomaticShutdownHandler : : _LastGCChecked = 0 ;
static const TSecTime MaxTime = ~ 0 ; //std::numeric_limits<TSecTime>::max()
// Time of next planned shutdown sequence start
TSecTime CAutomaticShutdownHandler : : _NextPlannedShutdownStartTime = MaxTime ;
// Time of next planned shutdown sequence end
TSecTime CAutomaticShutdownHandler : : _NextPlannedShutdownEndTime = MaxTime ;
/**
* Shutdown Counter , in minutes
*/
CVariable < uint > ShutdownCounter ( " egs " , " ShutdownCounter " , " Time to shutdown in minutes " , 5 , 0 , true ) ;
/**
* Broadcast shutdown message rate in seconds
*/
CVariable < uint > BroadcastShutdownMessageRate ( " egs " , " BroadcastShutdownMessageRate " , " Number of seconds between 2 shutdown message in seconds " , 30 , 0 , true ) ;
/**
* Close shard Access at
*/
CVariable < uint > CloseShardAccessAt ( " egs " , " CloseShardAccessAt " , " Time to shutdown to close shard access, in seconds " , 60 , 0 , true ) ;
// Callback for DailyShutdownSequenceTime
void cbChangeDailyShutdownSequenceTime ( IVariable & var )
{
CAutomaticShutdownHandler : : computePlannedShutdownTimes ( ) ;
}
/**
* DailyShutdownSequenceTime
*/
CVariable < string > DailyShutdownSequenceTime ( " egs " , " DailyShutdownSequenceTime " , " Time of day when the service will start a shutdown sequence (ex: \" 20:55 \" ). Set \" \" or -1 to disable) " , string ( ) , 0 , true , cbChangeDailyShutdownSequenceTime , true ) ;
/**
* Daily Shutdown Counter , in minutes
*/
CVariable < uint > DailyShutdownCounterMinutes ( " egs " , " DailyShutdownCounterMinutes " , " Time to shutdown in minutes " , 1 , 0 , true ) ;
/**
* DailyShutdownBroadcastMessage
*/
CVariable < string > DailyShutdownBroadcastMessage ( " egs " , " DailyShutdownBroadcastMessage " , " Message to broadcast before daily shutdown " , string ( " The shard will be shut down in 1 minute " ) , 0 , true ) ;
/**
* CheckShutdownPeriodGC
*/
CVariable < uint > CheckShutdownPeriodGC ( " egs " , " CheckShutdownPeriodGC " , " Automatic shutdown sequence is tested every CheckShutdownPeriodGC game cycles " , 50 , 0 , true ) ;
/*
* Inits Handler
*/
void CShutdownHandler : : init ( )
{
_State = Running ;
_ShutdownTimeout = NLMISC : : CTime : : getLocalTime ( ) ;
_NextBroadcastMessage = NLMISC : : CTime : : getLocalTime ( ) ;
_ShardClosed = false ;
}
/*
* Update Handler
*/
void CShutdownHandler : : update ( )
{
if ( _State = = ShuttingDown )
{
NLMISC : : TTime now = NLMISC : : CTime : : getLocalTime ( ) ;
// time to shutdown?
if ( _ShutdownTimeout < = now )
{
nlinfo ( " CShutdownHandler::update(): disconnect all players from shard " ) ;
disconnectPlayers ( ) ;
_State = Closed ;
return ;
}
// time to close shard access?
if ( _ShutdownTimeout - ( CloseShardAccessAt * 60 * 1000 ) < = now & & ! _ShardClosed )
{
nlinfo ( " CShutdownHandler::update(): close access to shard, SET_SHARD_OPEN sent to WS " ) ;
// send WS setShardOpen message
CMessage msgShardOpen ( " SET_SHARD_OPEN " ) ;
uint8 close = 0 ;
msgShardOpen . serial ( close ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " WS " , msgShardOpen ) ;
_ShardClosed = true ;
}
// time to broadcast message?
if ( _NextBroadcastMessage < = now )
{
broadcastShutdownMessage ( ) ;
}
}
}
/*
* Release Handler
*/
void CShutdownHandler : : release ( )
{
}
/*
* Start Shutdown Counter
*/
void CShutdownHandler : : startShutdown ( sint shutdownCounter , sint broadcastMessageRate )
{
nlinfo ( " CShutdownHandler::startShutdown(): starting count down to shutdown " ) ;
if ( _State ! = Running )
{
nlinfo ( " CShutdownHandler::startShutdown(): shutdown already started, left as is " ) ;
return ;
}
NLMISC : : TTime now = NLMISC : : CTime : : getLocalTime ( ) ;
nlinfo ( " CShutdownHandler::startShutdown(): counter set to %u seconds " , ShutdownCounter . get ( ) ) ;
// time in ms
_State = ShuttingDown ;
_ShutdownTimeout = now + ( shutdownCounter > 0 ? shutdownCounter : ShutdownCounter ) * 60 * 1000 ;
_BroadcastMessageRate = ( broadcastMessageRate > 0 ? broadcastMessageRate : BroadcastShutdownMessageRate ) ;
_NextBroadcastMessage = now ;
_ShardClosed = false ;
}
/*
* Cancel Shutdown
*/
void CShutdownHandler : : cancelShutdown ( )
{
nlinfo ( " CShutdownHandler::cancelShutdown(): cancelling shard shutdown " ) ;
if ( _State ! = ShuttingDown )
{
nlinfo ( " CShutdownHandler::cancelShutdown(): shard is not currently shutting down, shard left as is " ) ;
return ;
}
_State = Running ;
broadcastMessage ( std : : string ( " Shutting down cancelled " ) ) ;
if ( _ShardClosed )
{
nlinfo ( " CShutdownHandler::cancelShutdown(): WS ShardOpen state modified, sending restore request " ) ;
CMessage msgShardOpen ( " RESTORE_SHARD_OPEN " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " WS " , msgShardOpen ) ;
}
}
/*
* Restart shard
* Actually reset WS ShardOpen variable to OpenForAll
*/
void CShutdownHandler : : restartShard ( )
{
nlinfo ( " CShutdownHandler::restartShard(): restarting shard after shutdown " ) ;
if ( _State ! = Closed )
{
nlinfo ( " CShutdownHandler::restartShard(): shard is not closed " ) ;
return ;
}
_State = Running ;
broadcastMessage ( std : : string ( " Shard is now restarted and open to public. " ) ) ;
// send SET_SHARD_OPEN to WS
nlinfo ( " CShutdownHandler::restartShard(): WS ShardOpen state modified, sending restore request " ) ;
CMessage msgShardOpen ( " RESTORE_SHARD_OPEN " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " WS " , msgShardOpen ) ;
}
/*
* Get current shard state
*/
std : : string CShutdownHandler : : getState ( )
{
if ( _State = = Running )
{
return " Running " ;
}
else if ( _State = = ShuttingDown )
{
sint shutdown = ( sint ) ( ( _ShutdownTimeout - NLMISC : : CTime : : getLocalTime ( ) ) / 1000 ) ;
if ( _ShardClosed )
{
return NLMISC : : toString ( " Shutdown in %d seconds, shard access closed " , shutdown ) ;
}
else
{
return NLMISC : : toString ( " Shutdown in %d seconds " , shutdown ) ;
}
}
else
{
return " Closed, ready to restart " ;
}
}
/*
* Broadcast message
*/
void CShutdownHandler : : broadcastMessage ( const ucstring & message )
{
_NextBroadcastMessage = NLMISC : : CTime : : getLocalTime ( ) + _BroadcastMessageRate * 1000 ;
/// \todo handle ucstring somewhere here...
PlayerManager . broadcastMessage ( 1 , 0 , 0 , message . toString ( ) ) ;
}
/*
* Broadcast Shutdown message
*/
void CShutdownHandler : : broadcastShutdownMessage ( )
{
nlinfo ( " CShutdownHandler::broadcastShutdownMessage(): broadcasting shutdown message " ) ;
std : : string shutdownMessage ;
const sint timeAccuracy = 10 ;
sint shutdown = ( sint ) ( ( _ShutdownTimeout - NLMISC : : CTime : : getLocalTime ( ) ) / 1000 ) ;
shutdown + = ( timeAccuracy / 2 ) ;
// clamp to 0
if ( shutdown < 0 )
shutdown = 0 ;
shutdown = shutdown - ( shutdown % timeAccuracy ) ;
if ( shutdown < timeAccuracy )
{
broadcastMessage ( std : : string ( " Shutting down... " ) ) ;
}
else
{
if ( shutdown < 60 )
{
broadcastMessage ( NLMISC : : toString ( " Shard shuts down in %d seconds " , shutdown ) ) ;
}
else
{
uint min = shutdown / 60 ;
uint sec = shutdown % 60 ;
broadcastMessage ( NLMISC : : toString ( " Shard shuts down in %dmn %ds " , min , sec ) ) ;
}
}
}
/*
* Disconnect all players
*/
void CShutdownHandler : : disconnectPlayers ( )
{
nlinfo ( " CShutdownHandler::disconnectPlayers(): disconnecting all players " ) ;
CMessage msgout ( " DISCONNECT_ALL_CLIENTS " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " FS " , msgout ) ;
/*
const CPlayerManager : : TMapPlayers & playerMap = PlayerManager . getPlayers ( ) ;
// browse through all players to disconnect them
CPlayerManager : : TMapPlayers : : const_iterator it ;
for ( it = playerMap . begin ( ) ; it ! = playerMap . end ( ) ; )
{
const CPlayerManager : : SCPlayer & player = ( * it ) . second ;
+ + it ;
if ( player . Player ! = NULL )
{
uint32 userId = player . Player - > getUserId ( ) ;
PlayerManager . savePlayer ( userId ) ;
PlayerManager . disconnectPlayer ( userId ) ;
}
}
*/
}
/*
* Update .
* If the shutdown sequence is started , it can be canceled by changing DailyShutdownSequenceTime .
*/
void CAutomaticShutdownHandler : : update ( )
{
if ( CTickEventHandler : : getGameCycle ( ) - _LastGCChecked > = CheckShutdownPeriodGC )
{
_LastGCChecked = CTickEventHandler : : getGameCycle ( ) ;
TSecTime nowSec = NLMISC : : CTime : : getSecondsSince1970 ( ) ;
// Time to start an automatic shutdown sequence?
if ( nowSec > = _NextPlannedShutdownStartTime )
{
string msg = DailyShutdownBroadcastMessage . get ( ) ;
PlayerManager . broadcastMessage ( 1 , 0 , 0 , msg ) ;
nlinfo ( msg . c_str ( ) ) ;
_NextPlannedShutdownEndTime = _NextPlannedShutdownStartTime + ( DailyShutdownCounterMinutes . get ( ) * 60 ) ;
_NextPlannedShutdownStartTime = MaxTime ;
}
// Time to shutdown?
else if ( nowSec > = _NextPlannedShutdownEndTime )
{
_NextPlannedShutdownEndTime = MaxTime ;
IService : : getInstance ( ) - > exit ( ) ;
}
}
}
/*
* Use daily shutdown sequence time to compute next time
*/
void CAutomaticShutdownHandler : : computePlannedShutdownTimes ( NLMISC : : CLog * log )
{
string dailyTimeStr = DailyShutdownSequenceTime . get ( ) ;
if ( dailyTimeStr . empty ( ) | | ( dailyTimeStr = = " -1 " ) )
{
// No automatic shutdown sequence
_NextPlannedShutdownStartTime = MaxTime ;
_NextPlannedShutdownEndTime = MaxTime ;
if ( log )
log - > displayNL ( " Automatic shutdown sequence disabled " ) ;
}
else
{
// Setup next automatic shutdown sequence
time_t currentTime = time ( NULL ) ;
struct tm * localTime = localtime ( & currentTime ) ;
struct tm shutdownTime = * localTime ;
string : : size_type cp = dailyTimeStr . find ( ' : ' ) ;
shutdownTime . tm_hour = atoi ( dailyTimeStr . substr ( 0 , cp ) . c_str ( ) ) ;
shutdownTime . tm_min = 0 ;
if ( cp ! = string : : npos )
shutdownTime . tm_min = atoi ( dailyTimeStr . substr ( cp + 1 ) . c_str ( ) ) ;
shutdownTime . tm_sec = 0 ;
shutdownTime . tm_isdst = - 1 ;
_NextPlannedShutdownStartTime = nl_mktime ( & shutdownTime ) ;
char * dayWhenStr ;
if ( _NextPlannedShutdownStartTime > ( TSecTime ) currentTime )
{
dayWhenStr = " today " ;
}
else
{
dayWhenStr = " tomorrow " ;
+ + shutdownTime . tm_mday ;
_NextPlannedShutdownStartTime = nl_mktime ( & shutdownTime ) ;
}
_NextPlannedShutdownEndTime = _NextPlannedShutdownStartTime + ( DailyShutdownCounterMinutes . get ( ) * 60 ) ;
if ( log )
log - > displayNL ( " Next automatic shutdown sequence will begin %s at %02u:%02u with %u-minute delay " , dayWhenStr , shutdownTime . tm_hour , shutdownTime . tm_min , DailyShutdownCounterMinutes . get ( ) ) ;
}
}
NLMISC_DYNVARIABLE ( std : : string , ShutdownState , " Current shutdown state of the shard, as a string (Read only) " )
{
// read or write the variable
if ( get )
* pointer = CShutdownHandler : : getState ( ) ;
}
// Commands
NLMISC_COMMAND ( startShutdown , " Ask the EGS to shutdown the whole shard " , " [time to shutdown, minutes] [time between 2 messages, seconds] " )
{
if ( args . size ( ) > 2 )
return false ;
sint counter = - 1 ;
sint msgRate = - 1 ;
if ( args . size ( ) > = 1 )
counter = atoi ( args [ 0 ] . c_str ( ) ) ;
if ( args . size ( ) > = 2 )
msgRate = atoi ( args [ 1 ] . c_str ( ) ) ;
CShutdownHandler : : startShutdown ( counter , msgRate ) ;
return true ;
}
NLMISC_COMMAND ( cancelShutdown , " Cancel current shutdown in progress " , " " )
{
CShutdownHandler : : cancelShutdown ( ) ;
return true ;
}
NLMISC_COMMAND ( restartShard , " Restart the shard after a shutdown " , " " )
{
CShutdownHandler : : restartShard ( ) ;
return true ;
}