2011-07-02 14:38:06 +00:00
/*****************************************************************************
* PokerTH - The open source texas holdem engine *
* Copyright (C) 2006-2011 Felix Hammer, Florian Thauer, Lothar May *
* *
* 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/>. *
*****************************************************************************/
2009-08-20 11:02:05 +00:00
2009-08-20 15:19:41 +00:00
#include <net/serveradminbot.h>
2009-08-20 11:02:05 +00:00
#include <net/ircthread.h>
#include <net/serverlobbythread.h>
#include <net/serverbanmanager.h>
#include <net/serverexception.h>
#include <net/socket_msg.h>
#include <net/socket_startup.h>
#include <core/loghelper.h>
2012-03-03 14:16:45 +00:00
#include <boost/filesystem.hpp>
2009-08-20 11:02:05 +00:00
#include <boost/bind.hpp>
#include <boost/algorithm/string/predicate.hpp>
#define SERVER_RESTART_IRC_BOT_INTERVAL_SEC 86400 // 1 day
2012-03-03 14:16:45 +00:00
#define SERVER_NOTIFY_IRC_BOT_INTERVAL_SEC 1
#define SERVER_CHECK_IRC_BOT_INTERVAL_SEC 60
2009-08-20 11:02:05 +00:00
using namespace std ;
2012-03-03 14:16:45 +00:00
using namespace boost :: filesystem ;
2009-08-20 11:02:05 +00:00
2012-03-03 14:16:45 +00:00
ServerAdminBot :: ServerAdminBot ( boost :: shared_ptr < boost :: asio :: io_service > ioService )
2011-02-11 20:02:08 +00:00
: m_notifyTimeoutMinutes ( 0 ), m_notifyIntervalMinutes ( 0 ), m_notifyCounter ( 0 ),
2012-03-03 14:16:45 +00:00
m_notifyTimer ( boost :: posix_time :: time_duration ( 0 , 0 , 0 ), boost :: timers :: portable :: second_timer :: manual_start ),
m_reconnectTimer ( * ioService ), m_notifyLoopTimer ( * ioService ), m_checkFileTimer ( * ioService )
2009-08-20 11:02:05 +00:00
{
}
2009-08-20 15:19:41 +00:00
ServerAdminBot ::~ ServerAdminBot ()
2009-08-20 11:02:05 +00:00
{
}
void
2012-03-03 14:16:45 +00:00
ServerAdminBot :: Init ( boost :: shared_ptr < ServerLobbyThread > lobbyThread , boost :: shared_ptr < IrcThread > ircAdminThread , const std :: string & cacheDir )
2009-08-20 11:02:05 +00:00
{
m_lobbyThread = lobbyThread ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread = ircAdminThread ;
2012-03-03 14:16:45 +00:00
m_cacheDir = cacheDir ;
2009-08-20 11:02:05 +00:00
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalIrcConnect ( const std :: string & server )
2009-08-20 11:02:05 +00:00
{
2009-08-20 15:19:41 +00:00
LOG_MSG ( "Admin bot: Connected to IRC server " << server << "." );
2009-08-20 11:02:05 +00:00
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalIrcSelfJoined ( const std :: string & nickName , const std :: string & channel )
2009-08-20 11:02:05 +00:00
{
2009-08-20 15:19:41 +00:00
LOG_MSG ( "Admin bot: Joined IRC channel " << channel << " as user " << nickName << "." );
2009-08-20 11:02:05 +00:00
m_ircNick = nickName ;
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalIrcChatMsg ( const std :: string & nickName , const std :: string & msg )
2009-08-20 11:02:05 +00:00
{
2011-02-11 20:02:08 +00:00
if ( m_ircAdminThread ) {
try {
2009-08-20 11:02:05 +00:00
istringstream msgStream ( msg );
string target ;
msgStream >> target ;
2011-02-11 20:02:08 +00:00
if ( boost :: algorithm :: iequals ( target , m_ircNick + ":" )) {
2009-08-20 11:02:05 +00:00
string command ;
msgStream >> command ;
2011-02-11 20:02:08 +00:00
if ( command == "kick" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string playerName ( msgStream . str (). substr ( msgStream . tellg ()));
2011-02-11 20:02:08 +00:00
if ( ! playerName . empty ()) {
2009-08-20 11:02:05 +00:00
if ( GetLobbyThread (). KickPlayerByName ( playerName ))
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Successfully kicked player \" " + playerName + " \" from the server." );
2009-08-20 11:02:05 +00:00
else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Player \" " + playerName + " \" was not found on the server." );
2009-08-20 11:02:05 +00:00
}
2012-02-13 20:28:55 +00:00
} else if ( command == "removegame" ) {
while ( msgStream . peek () == ' ' )
msgStream . get ();
string playerName ( msgStream . str (). substr ( msgStream . tellg ()));
if ( ! playerName . empty ()) {
if ( GetLobbyThread (). RemoveGameByPlayerName ( playerName ))
m_ircAdminThread -> SendChatMessage ( nickName + ": Successfully removed game of player \" " + playerName + " \" ." );
else
m_ircAdminThread -> SendChatMessage ( nickName + ": Player \" " + playerName + " \" is currently not playing a game." );
}
2011-02-11 20:02:08 +00:00
} else if ( command == "cleaner-reconnect" ) {
2009-08-20 11:02:05 +00:00
GetLobbyThread (). ReconnectChatBot ();
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Cleaner bot reconnect initiated." );
2011-02-11 20:02:08 +00:00
} else if ( command == "showip" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string playerName ( msgStream . str (). substr ( msgStream . tellg ()));
2011-02-11 20:02:08 +00:00
if ( ! playerName . empty ()) {
2009-08-20 11:02:05 +00:00
string ipAddress ( GetLobbyThread (). GetPlayerIPAddress ( playerName ));
if ( ! ipAddress . empty ())
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": The IP address of player \" " + playerName + " \" is: \" " + ipAddress + " \" " );
2009-08-20 11:02:05 +00:00
else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": The IP address of player \" " + playerName + " \" is unknown." );
2009-08-20 11:02:05 +00:00
}
2011-02-11 20:02:08 +00:00
} else if ( command == "bannick" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string playerRegex ( msgStream . str (). substr ( msgStream . tellg ()));
2011-02-11 20:02:08 +00:00
if ( ! playerRegex . empty ()) {
2009-08-20 11:02:05 +00:00
GetLobbyThread (). GetBanManager (). BanPlayerRegex ( playerRegex );
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": The regex \" " + playerRegex + " \" was added to the player ban list." );
2009-08-20 11:02:05 +00:00
}
2011-02-11 20:02:08 +00:00
} else if ( command == "banip" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string ipAddress ;
unsigned durationHours = 12 ;
msgStream >> ipAddress ;
while ( msgStream . peek () == ' ' )
msgStream . get ();
if ( ! msgStream . eof ())
msgStream >> durationHours ;
2011-02-11 20:02:08 +00:00
if ( ! ipAddress . empty ()) {
2009-08-20 11:02:05 +00:00
ostringstream durationStr ;
durationStr << durationHours ;
GetLobbyThread (). GetBanManager (). BanIPAddress ( ipAddress , durationHours );
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": The IP address \" " + ipAddress + " \" was added to the IP address ban list for " + durationStr . str () + ( durationHours == 1 ? " hour." : " hours." ));
2009-08-20 11:02:05 +00:00
}
2011-02-11 20:02:08 +00:00
} else if ( command == "listban" ) {
2009-08-20 11:02:05 +00:00
list < string > banList ;
GetLobbyThread (). GetBanManager (). GetBanList ( banList );
list < string >:: const_iterator i = banList . begin ();
list < string >:: const_iterator end = banList . end ();
2011-02-11 20:02:08 +00:00
while ( i != end ) {
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( * i );
2009-08-20 11:02:05 +00:00
++ i ;
}
ostringstream banListStream ;
banListStream
2011-02-11 20:02:08 +00:00
<< nickName << ": Total count of bans: " << banList . size ();
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( banListStream . str ());
2011-02-11 20:02:08 +00:00
} else if ( command == "removeban" ) {
2009-08-20 11:02:05 +00:00
unsigned banId = 0 ;
msgStream >> banId ;
if ( GetLobbyThread (). GetBanManager (). UnBan ( banId ))
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": The ban was successfully removed." );
2009-08-20 11:02:05 +00:00
else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": This ban does not exist." );
2011-02-11 20:02:08 +00:00
} else if ( command == "clearban" ) {
2009-08-20 11:02:05 +00:00
GetLobbyThread (). GetBanManager (). ClearBanList ();
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": All ban lists were cleared." );
2011-02-11 20:02:08 +00:00
} else if ( command == "stat" ) {
2009-08-20 11:02:05 +00:00
ServerStats tmpStats = GetLobbyThread (). GetStats ();
{
boost :: posix_time :: time_duration timeDiff ( boost :: posix_time :: second_clock :: local_time () - GetLobbyThread (). GetStartTime ());
ostringstream statStream ;
statStream
2011-02-11 20:02:08 +00:00
<< "Server uptime................ " << timeDiff . hours () / 24 << " days " << timeDiff . hours () % 24 << " hours " << timeDiff . minutes () << " minutes " << timeDiff . seconds () << " seconds" ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( statStream . str ());
2009-08-20 11:02:05 +00:00
}
{
ostringstream statStream ;
statStream
2011-02-11 20:02:08 +00:00
<< "Players currently on Server.. " << tmpStats . numberOfPlayersOnServer ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( statStream . str ());
2009-08-20 11:02:05 +00:00
}
{
ostringstream statStream ;
statStream
2011-02-11 20:02:08 +00:00
<< "Games currently open......... " << tmpStats . numberOfGamesOpen ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( statStream . str ());
2009-08-20 11:02:05 +00:00
}
{
ostringstream statStream ;
statStream
2011-02-11 20:02:08 +00:00
<< "Total players ever logged in. " << tmpStats . totalPlayersEverLoggedIn
<< " (Max at a time: " << tmpStats . maxPlayersLoggedIn << ")" ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( statStream . str ());
2009-08-20 11:02:05 +00:00
}
{
ostringstream statStream ;
statStream
2011-02-11 20:02:08 +00:00
<< "Total games ever open........ " << tmpStats . totalGamesEverCreated
<< " (Max at a time: " << tmpStats . maxGamesOpen << ")" ;
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( statStream . str ());
2009-08-20 11:02:05 +00:00
}
2011-02-11 20:02:08 +00:00
} else if ( command == "chat" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string chat ( msgStream . str (). substr ( msgStream . tellg ()));
2011-02-11 20:02:08 +00:00
if ( ! chat . empty () && chat . size () < MAX_CHAT_TEXT_SIZE ) {
2009-08-20 11:02:05 +00:00
GetLobbyThread (). SendGlobalChat ( chat );
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Global chat message sent." );
2011-02-11 20:02:08 +00:00
} else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Invalid message." );
2011-02-11 20:02:08 +00:00
} else if ( command == "msg" ) {
2009-08-20 11:02:05 +00:00
while ( msgStream . peek () == ' ' )
msgStream . get ();
string message ( msgStream . str (). substr ( msgStream . tellg ()));
2011-02-11 20:02:08 +00:00
if ( ! message . empty () && message . size () < MAX_CHAT_TEXT_SIZE ) {
2009-08-20 11:02:05 +00:00
GetLobbyThread (). SendGlobalMsgBox ( message );
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Global message box sent." );
2011-02-11 20:02:08 +00:00
} else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Invalid message." );
2011-02-11 20:02:08 +00:00
} else if ( command == "notify-restart" ) {
2011-02-10 22:16:36 +00:00
int timeoutMinutes = 0 ;
int intervalMinutes = 0 ;
msgStream >> timeoutMinutes ;
msgStream >> intervalMinutes ;
2011-02-11 20:02:08 +00:00
if ( timeoutMinutes && intervalMinutes ) {
2011-02-10 22:16:36 +00:00
ostringstream ack ;
ack << nickName << ": Restart planned in " << timeoutMinutes << " minutes, notifying every " << intervalMinutes << " minutes." ;
m_ircAdminThread -> SendChatMessage ( ack . str ());
boost :: mutex :: scoped_lock lock ( m_notifyMutex );
m_notifyTimeoutMinutes = timeoutMinutes ;
m_notifyIntervalMinutes = intervalMinutes ;
m_notifyCounter = 0 ;
m_notifyTimer . reset ();
m_notifyTimer . start ();
2011-02-11 20:02:08 +00:00
} else {
2011-02-10 22:16:36 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Invalid parameters." );
}
2011-02-11 20:02:08 +00:00
} else
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Invalid command \" " + command + " \" ." );
2009-08-20 11:02:05 +00:00
}
2011-02-11 20:02:08 +00:00
} catch (...) {
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> SendChatMessage ( nickName + ": Syntax error. Please check the command." );
2009-08-20 11:02:05 +00:00
}
}
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalIrcError ( int errorCode )
2009-08-20 11:02:05 +00:00
{
2009-08-20 15:19:41 +00:00
LOG_MSG ( "Admin bot: IRC error " << errorCode << "." );
2009-08-20 11:02:05 +00:00
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalIrcServerError ( int errorCode )
2009-08-20 11:02:05 +00:00
{
2009-08-20 15:19:41 +00:00
LOG_MSG ( "Admin bot: IRC server error " << errorCode << "." );
2009-08-20 11:02:05 +00:00
}
2009-08-20 11:42:13 +00:00
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: Run ()
2009-08-20 11:42:13 +00:00
{
2012-03-03 14:16:45 +00:00
if ( m_ircAdminThread ) {
// Initialise the timers.
m_reconnectTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_RESTART_IRC_BOT_INTERVAL_SEC ));
m_reconnectTimer . async_wait (
boost :: bind (
& ServerAdminBot :: ReconnectHandler , shared_from_this (), boost :: asio :: placeholders :: error ));
m_notifyLoopTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_NOTIFY_IRC_BOT_INTERVAL_SEC ));
m_notifyLoopTimer . async_wait (
boost :: bind (
& ServerAdminBot :: NotifyLoop , shared_from_this (), boost :: asio :: placeholders :: error ));
m_checkFileTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_CHECK_IRC_BOT_INTERVAL_SEC ));
m_checkFileTimer . async_wait (
boost :: bind (
& ServerAdminBot :: CheckFileHandler , shared_from_this (), boost :: asio :: placeholders :: error ));
2009-08-20 15:19:41 +00:00
m_ircAdminThread -> Run ();
2012-03-03 14:16:45 +00:00
}
2009-08-20 11:42:13 +00:00
}
2009-08-20 11:02:05 +00:00
void
2012-03-03 14:16:45 +00:00
ServerAdminBot :: ReconnectHandler ( const boost :: system :: error_code & ec )
2009-08-20 11:02:05 +00:00
{
2012-03-03 14:16:45 +00:00
if ( ! ec ) {
Reconnect ();
m_reconnectTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_RESTART_IRC_BOT_INTERVAL_SEC ));
m_reconnectTimer . async_wait (
boost :: bind (
& ServerAdminBot :: ReconnectHandler , shared_from_this (), boost :: asio :: placeholders :: error ));
2009-08-20 11:02:05 +00:00
}
2012-03-03 14:16:45 +00:00
}
void
ServerAdminBot :: Reconnect ()
{
if ( m_ircAdminThread ) {
m_ircAdminThread -> SignalTermination ();
if ( m_ircAdminThread -> Join ( NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC )) {
boost :: shared_ptr < IrcThread > tmpIrcThread ( new IrcThread ( * m_ircAdminThread ));
tmpIrcThread -> Run ();
m_ircAdminThread = tmpIrcThread ;
}
}
}
void
ServerAdminBot :: CheckFileHandler ( const boost :: system :: error_code & ec )
{
if ( ! ec ) {
// Reconnect the irc bot if a signal file exists.
path cachePath ( m_cacheDir );
cachePath /= "SignalAdminReconnect" ;
if ( exists ( cachePath )) {
remove ( cachePath );
Reconnect ();
}
m_checkFileTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_CHECK_IRC_BOT_INTERVAL_SEC ));
m_checkFileTimer . async_wait (
boost :: bind (
& ServerAdminBot :: CheckFileHandler , shared_from_this (), boost :: asio :: placeholders :: error ));
}
}
void
ServerAdminBot :: NotifyLoop ( const boost :: system :: error_code & ec )
{
if ( ! ec ) {
2011-02-10 22:16:36 +00:00
boost :: mutex :: scoped_lock lock ( m_notifyMutex );
2011-02-11 20:02:08 +00:00
if ( m_notifyTimeoutMinutes && m_notifyTimer . elapsed (). total_seconds () >= m_notifyCounter * m_notifyIntervalMinutes * 60 ) {
2011-02-10 22:16:36 +00:00
int remainingMinutes = m_notifyTimeoutMinutes - m_notifyCounter * m_notifyIntervalMinutes ;
++ m_notifyCounter ;
2011-02-11 20:02:08 +00:00
if ( remainingMinutes > 1 ) {
2011-02-10 22:16:36 +00:00
ostringstream notifyStream ;
notifyStream << "The server will be restarted in " << remainingMinutes << " minutes." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Der Server wird in " << remainingMinutes << " Minuten neu gestartet werden." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Le serveur va être redémarré dans " << remainingMinutes << " minutes." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Il server verrà riavviato in " << remainingMinutes << " minuti." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "El servidor se reiniciará en " << remainingMinutes << " minutos." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
2011-02-11 20:02:08 +00:00
} else if ( remainingMinutes == 1 ) {
2011-02-10 22:16:36 +00:00
ostringstream notifyStream ;
notifyStream << "The server will be restarted in " << remainingMinutes << " minute." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Der Server wird in " << remainingMinutes << " Minute neu gestartet werden." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Le serveur va être redémarré dans " << remainingMinutes << " minute." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "Il server verrà riavviato in " << remainingMinutes << " minuto." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
notifyStream . str ( "" );
notifyStream << "El servidor se reiniciará en " << remainingMinutes << " minuto." ;
GetLobbyThread (). SendGlobalChat ( notifyStream . str ());
2011-02-11 20:02:08 +00:00
} else {
2011-02-10 22:16:36 +00:00
GetLobbyThread (). SendGlobalChat ( "The server will be restarted NOW." );
GetLobbyThread (). SendGlobalMsgBox ( "The server will be restarted NOW." );
m_notifyTimeoutMinutes = m_notifyCounter = m_notifyIntervalMinutes = 0 ;
m_notifyTimer . reset ();
}
}
2012-03-03 14:16:45 +00:00
m_notifyLoopTimer . expires_from_now (
boost :: posix_time :: seconds ( SERVER_NOTIFY_IRC_BOT_INTERVAL_SEC ));
m_notifyLoopTimer . async_wait (
boost :: bind (
& ServerAdminBot :: NotifyLoop , shared_from_this (), boost :: asio :: placeholders :: error ));
2011-02-10 22:16:36 +00:00
}
2009-08-20 11:02:05 +00:00
}
void
2009-08-20 15:19:41 +00:00
ServerAdminBot :: SignalTermination ()
2009-08-20 11:02:05 +00:00
{
2009-08-20 15:19:41 +00:00
if ( m_ircAdminThread )
m_ircAdminThread -> SignalTermination ();
2012-03-03 14:16:45 +00:00
// Terminated the timers.
m_notifyLoopTimer . cancel ();
m_reconnectTimer . cancel ();
m_checkFileTimer . cancel ();
2009-08-20 11:02:05 +00:00
}
bool
2009-08-20 15:19:41 +00:00
ServerAdminBot :: Join ( bool wait )
2009-08-20 11:02:05 +00:00
{
bool terminated = true ;
2009-08-20 15:19:41 +00:00
if ( m_ircAdminThread )
terminated = m_ircAdminThread -> Join ( wait ? NET_ADMIN_IRC_TERMINATE_TIMEOUT_MSEC : 0 );
2009-08-20 11:02:05 +00:00
return terminated ;
}
ServerLobbyThread &
2009-08-20 15:19:41 +00:00
ServerAdminBot :: GetLobbyThread ()
2009-08-20 11:02:05 +00:00
{
assert ( m_lobbyThread . get ());
return * m_lobbyThread ;
}