mirror of
https://github.com/RaidMax/IW4M-Admin.git
synced 2025-06-10 15:20:48 -05:00
Stats thread safe
Cleaned up WebService class and shutdown reimped stats and topstats moved things out of stats into main code
This commit is contained in:
@ -7,7 +7,9 @@ using System.Threading.Tasks;
|
||||
using SharedLibrary.Network;
|
||||
using SharedLibrary.Helpers;
|
||||
using SharedLibrary.Objects;
|
||||
|
||||
using SharedLibrary.Database;
|
||||
using System.Data.Entity;
|
||||
using SharedLibrary.Database.Models;
|
||||
|
||||
namespace SharedLibrary.Commands
|
||||
{
|
||||
@ -917,4 +919,56 @@ namespace SharedLibrary.Commands
|
||||
await E.Origin.Tell($"Your external IP is ^5{E.Origin.IPAddress}");
|
||||
}
|
||||
}
|
||||
|
||||
public class CPruneAdmins : Command
|
||||
{
|
||||
public CPruneAdmins() : base("prune", "demote any admins that have not connected recently (defaults to 30 days)", "p", Player.Permission.Owner, false, new CommandArgument[]
|
||||
{
|
||||
new CommandArgument()
|
||||
{
|
||||
Name = "inactive days",
|
||||
Required = false
|
||||
}
|
||||
})
|
||||
{ }
|
||||
|
||||
public override async Task ExecuteAsync(Event E)
|
||||
{
|
||||
int inactiveDays = 30;
|
||||
|
||||
try
|
||||
{
|
||||
if (E.Data.Length > 0)
|
||||
{
|
||||
inactiveDays = Int32.Parse(E.Data);
|
||||
if (inactiveDays < 1)
|
||||
throw new FormatException();
|
||||
}
|
||||
}
|
||||
|
||||
catch (FormatException)
|
||||
{
|
||||
await E.Origin.Tell("Invalid number of inactive days");
|
||||
return;
|
||||
}
|
||||
|
||||
List<EFClient> inactiveUsers = null;
|
||||
|
||||
// update user roles
|
||||
using (var context = new DatabaseContext())
|
||||
{
|
||||
var lastActive = DateTime.UtcNow.AddDays(-inactiveDays);
|
||||
inactiveUsers = await context.Clients
|
||||
.Where(c => c.Level > Player.Permission.Flagged && c.Level <= Player.Permission.Moderator)
|
||||
.Where(c => c.LastConnection < lastActive)
|
||||
.ToListAsync();
|
||||
inactiveUsers.ForEach(c => c.Level = Player.Permission.User);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
await E.Origin.Tell($"Pruned inactive {inactiveUsers.Count} privileged users");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@ namespace SharedLibrary.Database
|
||||
public DatabaseContext() : base("DefaultConnection")
|
||||
{
|
||||
System.Data.Entity.Database.SetInitializer(new Initializer());
|
||||
Configuration.LazyLoadingEnabled = false;
|
||||
Configuration.LazyLoadingEnabled = true;
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(DbModelBuilder modelBuilder)
|
||||
|
@ -9,17 +9,17 @@ namespace SharedLibrary.Helpers
|
||||
{
|
||||
public sealed class AsyncStatus
|
||||
{
|
||||
CancellationToken Token;
|
||||
DateTime StartTime;
|
||||
int TimesRun;
|
||||
int UpdateFrequency;
|
||||
public double RunAverage { get; private set; }
|
||||
public object Dependant { get; private set; }
|
||||
public Task RequestedTask { get; private set; }
|
||||
public CancellationTokenSource TokenSrc { get; private set; }
|
||||
|
||||
public AsyncStatus(object dependant, int frequency)
|
||||
{
|
||||
Token = new CancellationToken();
|
||||
TokenSrc = new CancellationTokenSource();
|
||||
StartTime = DateTime.Now;
|
||||
Dependant = dependant;
|
||||
UpdateFrequency = frequency;
|
||||
@ -29,7 +29,7 @@ namespace SharedLibrary.Helpers
|
||||
|
||||
public CancellationToken GetToken()
|
||||
{
|
||||
return Token;
|
||||
return TokenSrc.Token;
|
||||
}
|
||||
|
||||
public double ElapsedMillisecondsTime()
|
||||
@ -39,6 +39,10 @@ namespace SharedLibrary.Helpers
|
||||
|
||||
public void Update(Task<bool> T)
|
||||
{
|
||||
// reset the token source
|
||||
TokenSrc.Dispose();
|
||||
TokenSrc = new CancellationTokenSource();
|
||||
|
||||
RequestedTask = T;
|
||||
// Console.WriteLine($"Starting Task {T.Id} ");
|
||||
RequestedTask.Start();
|
||||
|
@ -26,77 +26,78 @@ namespace SharedLibrary.Network
|
||||
|
||||
static string[] SendQuery(QueryType Type, Server QueryServer, string Parameters = "")
|
||||
{
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 300)
|
||||
Task.Delay(300).Wait();
|
||||
LastQuery = DateTime.Now;
|
||||
var ServerOOBConnection = new UdpClient();
|
||||
ServerOOBConnection.Client.SendTimeout = 1000;
|
||||
ServerOOBConnection.Client.ReceiveTimeout = 1000;
|
||||
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort());
|
||||
|
||||
string QueryString = String.Empty;
|
||||
|
||||
switch (Type)
|
||||
using (var ServerOOBConnection = new UdpClient())
|
||||
{
|
||||
case QueryType.DVAR:
|
||||
case QueryType.COMMAND:
|
||||
QueryString = $"ÿÿÿÿrcon {QueryServer.Password} {Parameters}";
|
||||
break;
|
||||
case QueryType.GET_STATUS:
|
||||
QueryString = "ÿÿÿÿ getstatus";
|
||||
break;
|
||||
}
|
||||
// prevent flooding
|
||||
if ((DateTime.Now - LastQuery).TotalMilliseconds < 300)
|
||||
Task.Delay(300).Wait();
|
||||
LastQuery = DateTime.Now;
|
||||
|
||||
byte[] Payload = GetRequestBytes(QueryString);
|
||||
ServerOOBConnection.Client.SendTimeout = 1000;
|
||||
ServerOOBConnection.Client.ReceiveTimeout = 1000;
|
||||
var Endpoint = new IPEndPoint(IPAddress.Parse(QueryServer.GetIP()), QueryServer.GetPort());
|
||||
|
||||
int attempts = 0;
|
||||
retry:
|
||||
string QueryString = String.Empty;
|
||||
|
||||
try
|
||||
{
|
||||
ServerOOBConnection.Connect(Endpoint);
|
||||
ServerOOBConnection.Send(Payload, Payload.Length);
|
||||
|
||||
byte[] ReceiveBuffer = new byte[8192];
|
||||
StringBuilder QueryResponseString = new StringBuilder();
|
||||
|
||||
do
|
||||
switch (Type)
|
||||
{
|
||||
ReceiveBuffer = ServerOOBConnection.Receive(ref Endpoint);
|
||||
QueryResponseString.Append(Encoding.ASCII.GetString(ReceiveBuffer).TrimEnd('\0'));
|
||||
} while (ServerOOBConnection.Available > 0 && ServerOOBConnection.Client.Connected);
|
||||
|
||||
ServerOOBConnection.Close();
|
||||
|
||||
if (QueryResponseString.ToString().Contains("Invalid password"))
|
||||
throw new Exceptions.NetworkException("RCON password is invalid");
|
||||
if (QueryResponseString.ToString().Contains("rcon_password"))
|
||||
throw new Exceptions.NetworkException("RCON password has not been set");
|
||||
|
||||
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return SplitResponse;
|
||||
}
|
||||
|
||||
catch (Exceptions.NetworkException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
attempts++;
|
||||
if (attempts > 2)
|
||||
{
|
||||
var ne = new Exceptions.NetworkException("Could not communicate with the server");
|
||||
ne.Data["internal_exception"] = e.Message;
|
||||
ne.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
|
||||
ServerOOBConnection.Close();
|
||||
throw ne;
|
||||
case QueryType.DVAR:
|
||||
case QueryType.COMMAND:
|
||||
QueryString = $"ÿÿÿÿrcon {QueryServer.Password} {Parameters}";
|
||||
break;
|
||||
case QueryType.GET_STATUS:
|
||||
QueryString = "ÿÿÿÿ getstatus";
|
||||
break;
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
goto retry;
|
||||
byte[] Payload = GetRequestBytes(QueryString);
|
||||
|
||||
int attempts = 0;
|
||||
retry:
|
||||
|
||||
try
|
||||
{
|
||||
ServerOOBConnection.Connect(Endpoint);
|
||||
ServerOOBConnection.Send(Payload, Payload.Length);
|
||||
|
||||
byte[] ReceiveBuffer = new byte[8192];
|
||||
StringBuilder QueryResponseString = new StringBuilder();
|
||||
|
||||
do
|
||||
{
|
||||
ReceiveBuffer = ServerOOBConnection.Receive(ref Endpoint);
|
||||
QueryResponseString.Append(Encoding.ASCII.GetString(ReceiveBuffer).TrimEnd('\0'));
|
||||
} while (ServerOOBConnection.Available > 0 && ServerOOBConnection.Client.Connected);
|
||||
|
||||
if (QueryResponseString.ToString().Contains("Invalid password"))
|
||||
throw new Exceptions.NetworkException("RCON password is invalid");
|
||||
if (QueryResponseString.ToString().Contains("rcon_password"))
|
||||
throw new Exceptions.NetworkException("RCON password has not been set");
|
||||
|
||||
int num = int.Parse("0a", System.Globalization.NumberStyles.AllowHexSpecifier);
|
||||
string[] SplitResponse = QueryResponseString.ToString().Split(new char[] { (char)num }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return SplitResponse;
|
||||
}
|
||||
|
||||
catch (Exceptions.NetworkException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
|
||||
catch (Exception e)
|
||||
{
|
||||
attempts++;
|
||||
if (attempts > 2)
|
||||
{
|
||||
var ne = new Exceptions.NetworkException("Could not communicate with the server");
|
||||
ne.Data["internal_exception"] = e.Message;
|
||||
ne.Data["server_address"] = ServerOOBConnection.Client.RemoteEndPoint.ToString();
|
||||
throw ne;
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ namespace SharedLibrary
|
||||
public string Password;
|
||||
public string FtpPrefix;
|
||||
public bool AllowMultipleOwners;
|
||||
public bool AllowTrustedRank;
|
||||
|
||||
public override string Filename()
|
||||
{
|
||||
|
@ -41,11 +41,17 @@ namespace SharedLibrary.Services
|
||||
}
|
||||
}
|
||||
|
||||
public virtual async Task<IList<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
|
||||
{
|
||||
return await this.GetQuery(predicate, orderExpression).ToListAsync();
|
||||
}
|
||||
|
||||
public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> predicate, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
|
||||
{
|
||||
return this.GetQuery(predicate, orderExpression).AsEnumerable();
|
||||
}
|
||||
|
||||
|
||||
public virtual IQueryable<TEntity> GetQuery(Expression<Func<TEntity, bool>> predicate = null, Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderExpression = null)
|
||||
{
|
||||
IQueryable<TEntity> qry = this.DBSet;
|
||||
@ -131,16 +137,10 @@ namespace SharedLibrary.Services
|
||||
this.Context.SaveChanges();
|
||||
}
|
||||
|
||||
public virtual async Task SaveChangesAsync()
|
||||
public virtual Task SaveChangesAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await this.Context.SaveChangesAsync();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
return this.Context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -87,8 +87,8 @@ namespace SharedLibrary
|
||||
{
|
||||
return new Dictionary<string, string>();
|
||||
}
|
||||
|
||||
abstract public string GetContent(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers);
|
||||
|
||||
|
||||
public async Task<HttpResponse> GetPage(System.Collections.Specialized.NameValueCollection querySet, IDictionary<string, string> headers)
|
||||
{
|
||||
|
Reference in New Issue
Block a user