2015-07-03 00:10:01 -04:00
using System ;
using System.Collections.Generic ;
using System.Linq ;
using System.Threading ;
2017-05-26 18:49:27 -04:00
using System.IO ;
using System.Threading.Tasks ;
2015-07-03 00:10:01 -04:00
2017-06-19 13:58:01 -04:00
using SharedLibrary ;
using SharedLibrary.Interfaces ;
using SharedLibrary.Commands ;
using SharedLibrary.Helpers ;
2017-06-19 16:46:31 -04:00
using SharedLibrary.Exceptions ;
2017-06-19 13:58:01 -04:00
2015-07-03 00:10:01 -04:00
namespace IW4MAdmin
{
2017-06-19 13:58:01 -04:00
class ApplicationManager : IManager
2015-07-03 00:10:01 -04:00
{
2017-10-04 19:01:04 -04:00
private List < Server > _servers ;
public List < Server > Servers = > _servers . OrderByDescending ( s = > s . ClientNum ) . ToList ( ) ;
2017-06-19 13:58:01 -04:00
public ILogger Logger { get ; private set ; }
public bool Running { get ; private set ; }
static ApplicationManager Instance ;
List < AsyncStatus > TaskStatuses ;
2017-05-27 18:08:04 -04:00
Database ClientDatabase ;
2017-05-28 21:54:46 -04:00
Database AliasesDatabase ;
2017-06-19 13:58:01 -04:00
IPenaltyList ClientPenalties ;
2017-05-26 18:49:27 -04:00
List < Command > Commands ;
2017-06-19 13:58:01 -04:00
List < MessageToken > MessageTokens ;
2017-05-26 18:49:27 -04:00
Kayak . IScheduler webServiceTask ;
Thread WebThread ;
2017-09-27 16:07:43 -04:00
List < Player > PrivilegedClients ;
2017-05-26 18:49:27 -04:00
#if FTP_LOG
2017-05-28 16:47:21 -04:00
const int UPDATE_FREQUENCY = 15000 ;
2017-05-26 18:49:27 -04:00
#else
2017-05-28 16:47:21 -04:00
const int UPDATE_FREQUENCY = 300 ;
2017-05-26 18:49:27 -04:00
#endif
2017-06-19 13:58:01 -04:00
private ApplicationManager ( )
2015-07-03 00:10:01 -04:00
{
2017-05-27 19:29:20 -04:00
Logger = new Logger ( "Logs/IW4MAdmin.log" ) ;
2017-10-04 19:01:04 -04:00
_servers = new List < Server > ( ) ;
2017-05-26 18:49:27 -04:00
Commands = new List < Command > ( ) ;
2017-06-19 13:58:01 -04:00
TaskStatuses = new List < AsyncStatus > ( ) ;
MessageTokens = new List < MessageToken > ( ) ;
2017-05-28 16:47:21 -04:00
2017-11-14 16:36:55 -05:00
ClientDatabase = new ClientsDB ( "Database/clients.rm" , Logger ) ;
AliasesDatabase = new AliasesDB ( "Database/aliases.rm" , Logger ) ;
2017-05-27 18:08:04 -04:00
ClientPenalties = new PenaltyList ( ) ;
2015-07-03 00:10:01 -04:00
}
2017-09-29 22:42:24 -04:00
public IList < Server > GetServers ( )
2015-07-03 00:10:01 -04:00
{
2017-05-26 18:49:27 -04:00
return Servers ;
2015-07-03 00:10:01 -04:00
}
2017-09-29 22:42:24 -04:00
public IList < Command > GetCommands ( )
2015-08-17 16:38:42 -04:00
{
2017-05-26 18:49:27 -04:00
return Commands ;
2015-08-17 16:38:42 -04:00
}
2017-06-19 13:58:01 -04:00
public static ApplicationManager GetInstance ( )
2015-08-22 02:04:30 -04:00
{
2017-06-19 13:58:01 -04:00
return Instance ? ? ( Instance = new ApplicationManager ( ) ) ;
2015-08-22 02:04:30 -04:00
}
2017-05-26 18:49:27 -04:00
public void Init ( )
2015-07-06 13:13:42 -04:00
{
2017-09-29 22:42:24 -04:00
#region WEBSERVICE
SharedLibrary . WebService . Init ( ) ;
webServiceTask = WebService . GetScheduler ( ) ;
WebThread = new Thread ( webServiceTask . Start )
{
Name = "Web Thread"
} ;
WebThread . Start ( ) ;
#endregion
2017-08-09 00:35:23 -04:00
#region PLUGINS
SharedLibrary . Plugins . PluginImporter . Load ( this ) ;
foreach ( var Plugin in SharedLibrary . Plugins . PluginImporter . ActivePlugins )
{
try
{
2017-10-16 23:47:41 -04:00
Plugin . OnLoadAsync ( this ) ;
2017-08-09 00:35:23 -04:00
}
catch ( Exception e )
{
Logger . WriteError ( $"An error occured loading plugin {Plugin.Name}" ) ;
Logger . WriteDebug ( $"Exception: {e.Message}" ) ;
Logger . WriteDebug ( $"Stack Trace: {e.StackTrace}" ) ;
}
}
#endregion
2017-06-19 13:58:01 -04:00
#region CONFIG
2017-05-26 18:49:27 -04:00
var Configs = Directory . EnumerateFiles ( "config/servers" ) . Where ( x = > x . Contains ( ".cfg" ) ) ;
2015-07-06 13:13:42 -04:00
2017-05-26 18:49:27 -04:00
if ( Configs . Count ( ) = = 0 )
2017-06-19 13:58:01 -04:00
ServerConfigurationGenerator . Generate ( ) ;
2015-08-17 16:38:42 -04:00
2017-05-26 18:49:27 -04:00
foreach ( var file in Configs )
2015-07-03 00:10:01 -04:00
{
2017-06-19 13:58:01 -04:00
var Conf = ServerConfiguration . Read ( file ) ;
2015-08-17 16:38:42 -04:00
2017-05-26 18:49:27 -04:00
Task . Run ( async ( ) = >
2015-07-03 00:10:01 -04:00
{
2017-05-26 18:49:27 -04:00
try
2015-07-06 13:13:42 -04:00
{
2017-08-09 00:35:23 -04:00
var ServerInstance = new IW4MServer ( this , Conf ) ;
2017-05-26 18:49:27 -04:00
await ServerInstance . Initialize ( ) ;
2017-05-28 16:47:21 -04:00
2017-10-04 19:01:04 -04:00
lock ( _servers )
2017-08-09 00:35:23 -04:00
{
2017-10-04 19:01:04 -04:00
_servers . Add ( ServerInstance ) ;
2017-08-09 00:35:23 -04:00
}
2017-05-28 16:47:21 -04:00
2017-05-27 19:29:20 -04:00
Logger . WriteVerbose ( $"Now monitoring {ServerInstance.Hostname}" ) ;
2017-08-09 00:35:23 -04:00
// this way we can keep track of execution time and see if problems arise.
var Status = new AsyncStatus ( ServerInstance , UPDATE_FREQUENCY ) ;
lock ( TaskStatuses )
{
TaskStatuses . Add ( Status ) ;
}
2015-07-06 13:13:42 -04:00
}
2015-08-28 00:39:36 -04:00
2017-06-19 16:46:31 -04:00
catch ( ServerException e )
2017-05-26 18:49:27 -04:00
{
2017-11-13 16:58:23 -05:00
Logger . WriteError ( $"Not monitoring server {Conf.IP}:{Conf.Port} due to uncorrectable errors" ) ;
2017-06-19 16:46:31 -04:00
if ( e . GetType ( ) = = typeof ( DvarException ) )
2017-11-13 16:58:23 -05:00
Logger . WriteDebug ( $"Could not get the dvar value for {(e as DvarException).Data[" dvar_name "]} (ensure the server has a map loaded)" ) ;
2017-06-19 16:46:31 -04:00
else if ( e . GetType ( ) = = typeof ( NetworkException ) )
2017-11-13 16:58:23 -05:00
{
Logger . WriteDebug ( e . Message ) ;
Logger . WriteDebug ( $"Internal Exception: {e.Data[" internal_exception "]}" ) ;
}
2017-05-26 18:49:27 -04:00
}
} ) ;
2015-07-03 00:10:01 -04:00
}
2017-06-19 13:58:01 -04:00
#endregion
#region COMMANDS
2017-08-08 22:44:52 -04:00
if ( ( ClientDatabase as ClientsDB ) . GetOwner ( ) = = null )
2017-11-13 18:17:10 -05:00
Commands . Add ( new COwner ( "owner" , "claim ownership of the server" , "o" , Player . Permission . User , 0 , false ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CQuit ( "quit" , "quit IW4MAdmin" , "q" , Player . Permission . Owner , 0 , false ) ) ;
Commands . Add ( new CKick ( "kick" , "kick a player by name. syntax: !kick <player> <reason>." , "k" , Player . Permission . Trusted , 2 , true ) ) ;
Commands . Add ( new CSay ( "say" , "broadcast message to all players. syntax: !say <message>." , "s" , Player . Permission . Moderator , 1 , false ) ) ;
2017-11-13 16:58:23 -05:00
Commands . Add ( new CTempBan ( "tempban" , "temporarily ban a player for for specified time (defaults to 1 hour). syntax: !tempban <player> <time>(m|h|d|w|y) <reason>." , "tb" , Player . Permission . Moderator , 2 , true ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CBan ( "ban" , "permanently ban a player from the server. syntax: !ban <player> <reason>" , "b" , Player . Permission . SeniorAdmin , 2 , true ) ) ;
Commands . Add ( new CWhoAmI ( "whoami" , "give information about yourself. syntax: !whoami." , "who" , Player . Permission . User , 0 , false ) ) ;
2017-11-13 18:17:10 -05:00
Commands . Add ( new CList ( "list" , "list active clients. syntax: !list." , "l" , Player . Permission . Moderator , 0 , false ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CHelp ( "help" , "list all available commands. syntax: !help." , "h" , Player . Permission . User , 0 , false ) ) ;
Commands . Add ( new CFastRestart ( "fastrestart" , "fast restart current map. syntax: !fastrestart." , "fr" , Player . Permission . Moderator , 0 , false ) ) ;
Commands . Add ( new CMapRotate ( "maprotate" , "cycle to the next map in rotation. syntax: !maprotate." , "mr" , Player . Permission . Administrator , 0 , false ) ) ;
Commands . Add ( new CSetLevel ( "setlevel" , "set player to specified administration level. syntax: !setlevel <player> <level>." , "sl" , Player . Permission . Owner , 2 , true ) ) ;
Commands . Add ( new CUsage ( "usage" , "get current application memory usage. syntax: !usage." , "us" , Player . Permission . Moderator , 0 , false ) ) ;
Commands . Add ( new CUptime ( "uptime" , "get current application running time. syntax: !uptime." , "up" , Player . Permission . Moderator , 0 , false ) ) ;
2017-11-13 18:17:10 -05:00
Commands . Add ( new CWarn ( "warn" , "warn player for infringing rules. syntax: !warn <player> <reason>." , "w" , Player . Permission . Trusted , 2 , true ) ) ;
Commands . Add ( new CWarnClear ( "warnclear" , "remove all warning for a player. syntax: !warnclear <player>." , "wc" , Player . Permission . Trusted , 1 , true ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CUnban ( "unban" , "unban player by database id. syntax: !unban @<id>." , "ub" , Player . Permission . SeniorAdmin , 1 , true ) ) ;
Commands . Add ( new CListAdmins ( "admins" , "list currently connected admins. syntax: !admins." , "a" , Player . Permission . User , 0 , false ) ) ;
Commands . Add ( new CLoadMap ( "map" , "change to specified map. syntax: !map" , "m" , Player . Permission . Administrator , 1 , false ) ) ;
Commands . Add ( new CFindPlayer ( "find" , "find player in database. syntax: !find <player>" , "f" , Player . Permission . SeniorAdmin , 1 , false ) ) ;
Commands . Add ( new CListRules ( "rules" , "list server rules. syntax: !rules" , "r" , Player . Permission . User , 0 , false ) ) ;
Commands . Add ( new CPrivateMessage ( "privatemessage" , "send message to other player. syntax: !pm <player> <message>" , "pm" , Player . Permission . User , 2 , true ) ) ;
2017-11-13 18:17:10 -05:00
Commands . Add ( new CFlag ( "flag" , "flag a suspicious player and announce to admins on join. syntax !flag <player> <reason>:" , "fp" , Player . Permission . Moderator , 2 , true ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CReport ( "report" , "report a player for suspicious behaivor. syntax !report <player> <reason>" , "rep" , Player . Permission . User , 2 , true ) ) ;
2017-11-13 18:17:10 -05:00
Commands . Add ( new CListReports ( "reports" , "get most recent reports. syntax !reports" , "reps" , Player . Permission . Moderator , 0 , false ) ) ;
Commands . Add ( new CMask ( "mask" , "hide your online presence from online admin list. syntax: !mask" , "hide" , Player . Permission . Administrator , 0 , false ) ) ;
2017-06-19 13:58:01 -04:00
Commands . Add ( new CListBanInfo ( "baninfo" , "get information about a ban for a player. syntax: !baninfo <player>" , "bi" , Player . Permission . Moderator , 1 , true ) ) ;
Commands . Add ( new CListAlias ( "alias" , "get past aliases and ips of a player. syntax: !alias <player>" , "known" , Player . Permission . Moderator , 1 , true ) ) ;
Commands . Add ( new CExecuteRCON ( "rcon" , "send rcon command to server. syntax: !rcon <command>" , "rcon" , Player . Permission . Owner , 1 , false ) ) ;
Commands . Add ( new CFindAllPlayers ( "findall" , "find a player by their aliase(s). syntax: !findall <player>" , "fa" , Player . Permission . Moderator , 1 , false ) ) ;
Commands . Add ( new CPlugins ( "plugins" , "view all loaded plugins. syntax: !plugins" , "p" , Player . Permission . Administrator , 0 , false ) ) ;
2017-11-13 18:17:10 -05:00
Commands . Add ( new CIP ( "getexternalip" , "view your external IP address. syntax: !ip" , "ip" , Player . Permission . User , 0 , false ) ) ;
2017-06-19 13:58:01 -04:00
foreach ( Command C in SharedLibrary . Plugins . PluginImporter . ActiveCommands )
Commands . Add ( C ) ;
#endregion
2017-09-27 16:07:43 -04:00
#region ADMINS
PrivilegedClients = GetClientDatabase ( ) . GetAdmins ( ) ;
#endregion
2017-05-26 18:49:27 -04:00
Running = true ;
2015-07-03 00:10:01 -04:00
}
2017-08-09 00:35:23 -04:00
2017-05-26 18:49:27 -04:00
public void Start ( )
2015-07-03 00:10:01 -04:00
{
2017-05-28 16:47:21 -04:00
while ( Running )
2015-07-03 00:10:01 -04:00
{
2017-08-09 00:35:23 -04:00
for ( int i = 0 ; i < TaskStatuses . Count ; i + + )
2015-07-03 00:10:01 -04:00
{
2017-08-09 00:35:23 -04:00
var Status = TaskStatuses [ i ] ;
2017-05-28 16:47:21 -04:00
if ( Status . RequestedTask = = null | | Status . RequestedTask . IsCompleted )
{
Status . Update ( new Task ( ( ) = > ( Status . Dependant as Server ) . ProcessUpdatesAsync ( Status . GetToken ( ) ) ) ) ;
2017-11-13 16:58:23 -05:00
if ( Status . RunAverage > 1000 + UPDATE_FREQUENCY )
2017-06-12 13:50:00 -04:00
Logger . WriteWarning ( $"Update task average execution is longer than desired for {(Status.Dependant as Server).GetIP()}::{(Status.Dependant as Server).GetPort()} [{Status.RunAverage}ms]" ) ;
2017-05-28 16:47:21 -04:00
}
2015-07-03 00:10:01 -04:00
}
2017-05-28 16:47:21 -04:00
2017-09-27 16:07:43 -04:00
Thread . Sleep ( UPDATE_FREQUENCY ) ;
2015-07-03 00:10:01 -04:00
}
2017-05-26 18:49:27 -04:00
#if ! DEBUG
foreach ( var S in Servers )
S . Broadcast ( "^1IW4MAdmin going offline!" ) ;
#endif
2017-10-04 19:01:04 -04:00
_servers . Clear ( ) ;
2017-05-26 18:49:27 -04:00
WebThread . Abort ( ) ;
webServiceTask . Stop ( ) ;
2015-07-03 00:10:01 -04:00
}
2015-07-06 15:51:08 -04:00
2017-08-09 00:35:23 -04:00
2017-05-26 18:49:27 -04:00
public void Stop ( )
2015-07-06 15:51:08 -04:00
{
2017-05-26 18:49:27 -04:00
Running = false ;
2015-07-06 15:51:08 -04:00
}
2017-05-27 18:08:04 -04:00
public ClientsDB GetClientDatabase ( )
{
return ClientDatabase as ClientsDB ;
}
2017-05-28 21:54:46 -04:00
public AliasesDB GetAliasesDatabase ( )
{
return AliasesDatabase as AliasesDB ;
}
2017-06-19 13:58:01 -04:00
public IPenaltyList GetClientPenalties ( )
2017-05-27 18:08:04 -04:00
{
return ClientPenalties ;
}
2017-05-27 19:29:20 -04:00
2017-06-19 13:58:01 -04:00
public ILogger GetLogger ( )
2017-05-27 19:29:20 -04:00
{
return Logger ;
}
2017-05-31 01:31:56 -04:00
2017-06-19 13:58:01 -04:00
public IList < MessageToken > GetMessageTokens ( )
2017-05-31 01:31:56 -04:00
{
return MessageTokens ;
}
2017-06-12 13:50:00 -04:00
public IList < Player > GetActiveClients ( )
{
var ActiveClients = new List < Player > ( ) ;
2017-10-04 19:01:04 -04:00
foreach ( var server in _servers )
2017-06-12 13:50:00 -04:00
ActiveClients . AddRange ( server . Players . Where ( p = > p ! = null ) ) ;
return ActiveClients ;
}
2017-08-17 19:28:08 -04:00
public IList < Player > GetAliasClients ( Player Origin )
{
List < int > databaseIDs = new List < int > ( ) ;
foreach ( Aliases A in GetAliases ( Origin ) )
databaseIDs . Add ( A . Number ) ;
return GetClientDatabase ( ) . GetPlayers ( databaseIDs ) ;
}
public IList < Aliases > GetAliases ( Player Origin )
{
List < Aliases > allAliases = new List < Aliases > ( ) ;
if ( Origin = = null )
return allAliases ;
Aliases currentIdentityAliases = GetAliasesDatabase ( ) . GetPlayerAliases ( Origin . DatabaseID ) ;
if ( currentIdentityAliases = = null )
return allAliases ;
GetAliases ( allAliases , currentIdentityAliases ) ;
if ( Origin . Alias ! = null )
allAliases . Add ( Origin . Alias ) ;
return allAliases ;
}
2017-09-27 16:07:43 -04:00
public IList < Player > GetPrivilegedClients ( )
{
return PrivilegedClients ;
}
2017-08-17 19:28:08 -04:00
private void GetAliases ( List < Aliases > returnAliases , Aliases currentAlias )
{
foreach ( String IP in currentAlias . IPS )
{
List < Aliases > Matching = GetAliasesDatabase ( ) . GetPlayerAliases ( IP ) ;
foreach ( Aliases I in Matching )
{
if ( ! returnAliases . Contains ( I ) & & returnAliases . Find ( x = > x . Number = = I . Number ) = = null )
{
returnAliases . Add ( I ) ;
GetAliases ( returnAliases , I ) ;
}
}
}
}
2015-07-03 00:10:01 -04:00
}
}