mirror of
https://github.com/LBPUnion/ProjectLighthouse.git
synced 2025-05-16 14:42:28 +00:00
Implement cuddle logger
This commit is contained in:
parent
9c57d15671
commit
9fa4ffbc90
41 changed files with 508 additions and 317 deletions
|
@ -3,7 +3,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
@ -46,14 +45,14 @@ public class LoginController : ControllerBase
|
||||||
|
|
||||||
if (npTicket == null)
|
if (npTicket == null)
|
||||||
{
|
{
|
||||||
Logger.Log("npTicket was null, rejecting login", LoggerLevelLogin.Instance);
|
Logger.LogWarn("npTicket was null, rejecting login", "Login");
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
IPAddress? remoteIpAddress = this.HttpContext.Connection.RemoteIpAddress;
|
||||||
if (remoteIpAddress == null)
|
if (remoteIpAddress == null)
|
||||||
{
|
{
|
||||||
Logger.Log("unable to determine ip, rejecting login", LoggerLevelLogin.Instance);
|
Logger.LogWarn("unable to determine ip, rejecting login", "Login");
|
||||||
return this.StatusCode(403, ""); // 403 probably isnt the best status code for this, but whatever
|
return this.StatusCode(403, ""); // 403 probably isnt the best status code for this, but whatever
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +68,7 @@ public class LoginController : ControllerBase
|
||||||
token = await this.database.AuthenticateUser(npTicket, ipAddress);
|
token = await this.database.AuthenticateUser(npTicket, ipAddress);
|
||||||
if (token == null)
|
if (token == null)
|
||||||
{
|
{
|
||||||
Logger.Log($"Unable to find/generate a token for username {npTicket.Username}", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"Unable to find/generate a token for username {npTicket.Username}", "Login");
|
||||||
return this.StatusCode(403, ""); // If not, then 403.
|
return this.StatusCode(403, ""); // If not, then 403.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +77,7 @@ public class LoginController : ControllerBase
|
||||||
|
|
||||||
if (user == null || user.Banned)
|
if (user == null || user.Banned)
|
||||||
{
|
{
|
||||||
Logger.Log($"Unable to find user {npTicket.Username} from token", LoggerLevelLogin.Instance);
|
Logger.LogError($"Unable to find user {npTicket.Username} from token", "Login");
|
||||||
return this.StatusCode(403, "");
|
return this.StatusCode(403, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +94,7 @@ public class LoginController : ControllerBase
|
||||||
DeniedAuthenticationHelper.AddAttempt(ipAddressAndName);
|
DeniedAuthenticationHelper.AddAttempt(ipAddressAndName);
|
||||||
|
|
||||||
await this.database.SaveChangesAsync();
|
await this.database.SaveChangesAsync();
|
||||||
Logger.Log($"Too many recent denied logins from user {user.Username}, rejecting login", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"Too many recent denied logins from user {user.Username}, rejecting login", "Login");
|
||||||
return this.StatusCode(403, "");
|
return this.StatusCode(403, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,11 +126,11 @@ public class LoginController : ControllerBase
|
||||||
|
|
||||||
if (!token.Approved)
|
if (!token.Approved)
|
||||||
{
|
{
|
||||||
Logger.Log($"Token unapproved for user {user.Username}, rejecting login", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"Token unapproved for user {user.Username}, rejecting login", "Login");
|
||||||
return this.StatusCode(403, "");
|
return this.StatusCode(403, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Log($"Successfully logged in user {user.Username} as {token.GameVersion} client", LoggerLevelLogin.Instance);
|
Logger.LogSuccess($"Successfully logged in user {user.Username} as {token.GameVersion} client", "Login");
|
||||||
// After this point we are now considering this session as logged in.
|
// After this point we are now considering this session as logged in.
|
||||||
|
|
||||||
// We just logged in with the token. Mark it as used so someone else doesnt try to use it,
|
// We just logged in with the token. Mark it as used so someone else doesnt try to use it,
|
||||||
|
|
|
@ -5,7 +5,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
@ -48,7 +47,7 @@ public class MatchController : ControllerBase
|
||||||
|
|
||||||
if (bodyString.Length == 0 || bodyString[0] != '[') return this.BadRequest();
|
if (bodyString.Length == 0 || bodyString[0] != '[') return this.BadRequest();
|
||||||
|
|
||||||
Logger.Log("Received match data: " + bodyString, LoggerLevelMatch.Instance);
|
Logger.LogInfo("Received match data: " + bodyString, "Match");
|
||||||
|
|
||||||
IMatchData? matchData;
|
IMatchData? matchData;
|
||||||
try
|
try
|
||||||
|
@ -57,20 +56,19 @@ public class MatchController : ControllerBase
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log("Exception while parsing matchData: ", LoggerLevelMatch.Instance);
|
Logger.LogError("Exception while parsing matchData: ", "Match");
|
||||||
string[] lines = e.ToDetailedException().Split("\n");
|
Logger.LogError(e.ToDetailedException(), "Match");
|
||||||
foreach (string line in lines) Logger.Log(line, LoggerLevelMatch.Instance);
|
|
||||||
|
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (matchData == null)
|
if (matchData == null)
|
||||||
{
|
{
|
||||||
Logger.Log("Could not parse match data: matchData is null", LoggerLevelMatch.Instance);
|
Logger.LogError($"Could not parse match data: {nameof(matchData)} is null", "Match");
|
||||||
return this.BadRequest();
|
return this.BadRequest();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Log($"Parsed match from {user.Username} (type: {matchData.GetType()})", LoggerLevelMatch.Instance);
|
Logger.LogError($"Parsed match from {user.Username} (type: {matchData.GetType()})", "Match");
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
@ -99,7 +98,7 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.";
|
||||||
|
|
||||||
string scannedText = CensorHelper.ScanMessage(response);
|
string scannedText = CensorHelper.ScanMessage(response);
|
||||||
|
|
||||||
Logger.Log($"{user.Username}: {response} / {scannedText}", LoggerLevelFilter.Instance);
|
Logger.LogInfo($"{user.Username}: {response} / {scannedText}", "Filter");
|
||||||
|
|
||||||
return this.Ok(scannedText);
|
return this.Ok(scannedText);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using Discord;
|
using Discord;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
@ -68,7 +67,7 @@ public class PhotosController : ControllerBase
|
||||||
if (subject.User == null) continue;
|
if (subject.User == null) continue;
|
||||||
|
|
||||||
subject.UserId = subject.User.UserId;
|
subject.UserId = subject.User.UserId;
|
||||||
Logger.Log($"Adding PhotoSubject (userid {subject.UserId}) to db", LoggerLevelPhotos.Instance);
|
Logger.LogDebug($"Adding PhotoSubject (userid {subject.UserId}) to db", "Photos");
|
||||||
|
|
||||||
this.database.PhotoSubjects.Add(subject);
|
this.database.PhotoSubjects.Add(subject);
|
||||||
}
|
}
|
||||||
|
@ -88,7 +87,7 @@ public class PhotosController : ControllerBase
|
||||||
|
|
||||||
// photo.Slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId);
|
// photo.Slot = await this.database.Slots.FirstOrDefaultAsync(s => s.SlotId == photo.SlotId);
|
||||||
|
|
||||||
Logger.Log($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", LoggerLevelPhotos.Instance);
|
Logger.LogDebug($"Adding PhotoSubjectCollection ({photo.PhotoSubjectCollection}) to photo", "Photos");
|
||||||
|
|
||||||
this.database.Photos.Add(photo);
|
this.database.Photos.Add(photo);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
@ -97,27 +96,23 @@ public class ResourcesController : ControllerBase
|
||||||
// lbp treats code 409 as success and as an indicator that the file is already present
|
// lbp treats code 409 as success and as an indicator that the file is already present
|
||||||
if (FileHelper.ResourceExists(hash)) this.Conflict();
|
if (FileHelper.ResourceExists(hash)) this.Conflict();
|
||||||
|
|
||||||
Logger.Log($"Processing resource upload (hash: {hash})", LoggerLevelResources.Instance);
|
Logger.LogInfo($"Processing resource upload (hash: {hash})", "Resources");
|
||||||
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
|
LbpFile file = new(await BinaryHelper.ReadFromPipeReader(this.Request.BodyReader));
|
||||||
|
|
||||||
if (!FileHelper.IsFileSafe(file))
|
if (!FileHelper.IsFileSafe(file))
|
||||||
{
|
{
|
||||||
Logger.Log($"File is unsafe (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
|
Logger.LogWarn($"File is unsafe (hash: {hash}, type: {file.FileType})", "Resources");
|
||||||
return this.Conflict();
|
return this.Conflict();
|
||||||
}
|
}
|
||||||
|
|
||||||
string calculatedHash = file.Hash;
|
string calculatedHash = file.Hash;
|
||||||
if (calculatedHash != hash)
|
if (calculatedHash != hash)
|
||||||
{
|
{
|
||||||
Logger.Log
|
Logger.LogWarn($"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})", "Resources");
|
||||||
(
|
|
||||||
$"File hash does not match the uploaded file! (hash: {hash}, calculatedHash: {calculatedHash}, type: {file.FileType})",
|
|
||||||
LoggerLevelResources.Instance
|
|
||||||
);
|
|
||||||
return this.Conflict();
|
return this.Conflict();
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.Log($"File is OK! (hash: {hash}, type: {file.FileType})", LoggerLevelResources.Instance);
|
Logger.LogSuccess($"File is OK! (hash: {hash}, type: {file.FileType})", "Resources");
|
||||||
await IOFile.WriteAllBytesAsync(path, file.Data);
|
await IOFile.WriteAllBytesAsync(path, file.Data);
|
||||||
return this.Ok();
|
return this.Ok();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
@ -85,7 +84,7 @@ public class CollectionController : ControllerBase
|
||||||
Category? category = CollectionHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
Category? category = CollectionHelper.Categories.FirstOrDefault(c => c.Endpoint == endpointName);
|
||||||
if (category == null) return this.NotFound();
|
if (category == null) return this.NotFound();
|
||||||
|
|
||||||
Logger.Log("Found category " + category, LoggerLevelCategory.Instance);
|
Logger.LogDebug("Found category " + category, "Category");
|
||||||
|
|
||||||
List<Slot> slots;
|
List<Slot> slots;
|
||||||
int totalSlots;
|
int totalSlots;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
@ -45,14 +44,14 @@ public class SlotPageController : ControllerBase
|
||||||
|
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
{
|
{
|
||||||
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
|
Logger.LogError($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", "Comments");
|
||||||
return this.Redirect("~/slot/" + id);
|
return this.Redirect("~/slot/" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = SanitizationHelper.SanitizeString(msg);
|
msg = SanitizationHelper.SanitizeString(msg);
|
||||||
|
|
||||||
await this.database.PostComment(user, id, CommentType.Level, msg);
|
await this.database.PostComment(user, id, CommentType.Level, msg);
|
||||||
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
|
Logger.LogSuccess($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", "Comments");
|
||||||
|
|
||||||
return this.Redirect("~/slot/" + id);
|
return this.Redirect("~/slot/" + id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
@ -39,14 +38,14 @@ public class UserPageController : ControllerBase
|
||||||
|
|
||||||
if (msg == null)
|
if (msg == null)
|
||||||
{
|
{
|
||||||
Logger.Log($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", LoggerLevelComments.Instance);
|
Logger.LogError($"Refusing to post comment from {user.UserId} on user {id}, {nameof(msg)} is null", "Comments");
|
||||||
return this.Redirect("~/user/" + id);
|
return this.Redirect("~/user/" + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = SanitizationHelper.SanitizeString(msg);
|
msg = SanitizationHelper.SanitizeString(msg);
|
||||||
|
|
||||||
await this.database.PostComment(user, id, CommentType.Profile, msg);
|
await this.database.PostComment(user, id, CommentType.Profile, msg);
|
||||||
Logger.Log($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", LoggerLevelComments.Instance);
|
Logger.LogSuccess($"Posted comment from {user.UserId}: \"{msg}\" on user {id}", "Comments");
|
||||||
|
|
||||||
return this.Redirect("~/user/" + id);
|
return this.Redirect("~/user/" + id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using AspLogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
|
|
||||||
|
public static class AspLogLevelExtensions
|
||||||
|
{
|
||||||
|
public static LogLevel ToLighthouseLevel(this AspLogLevel level)
|
||||||
|
{
|
||||||
|
return level switch
|
||||||
|
{
|
||||||
|
AspLogLevel.Trace => LogLevel.Debug,
|
||||||
|
AspLogLevel.Debug => LogLevel.Debug,
|
||||||
|
AspLogLevel.Information => LogLevel.Info,
|
||||||
|
AspLogLevel.Warning => LogLevel.Warning,
|
||||||
|
AspLogLevel.Error => LogLevel.Error,
|
||||||
|
AspLogLevel.Critical => LogLevel.Error,
|
||||||
|
AspLogLevel.None => LogLevel.Info,
|
||||||
|
_ => LogLevel.Info,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
|
|
||||||
|
internal static class ConsoleColorExtensions
|
||||||
|
{
|
||||||
|
internal static ConsoleColor ToDark(this ConsoleColor color)
|
||||||
|
=> color switch
|
||||||
|
{
|
||||||
|
ConsoleColor.Blue => ConsoleColor.DarkBlue,
|
||||||
|
ConsoleColor.Cyan => ConsoleColor.DarkCyan,
|
||||||
|
ConsoleColor.Green => ConsoleColor.DarkGreen,
|
||||||
|
ConsoleColor.Gray => ConsoleColor.DarkGray,
|
||||||
|
ConsoleColor.Magenta => ConsoleColor.DarkMagenta,
|
||||||
|
ConsoleColor.Red => ConsoleColor.DarkRed,
|
||||||
|
ConsoleColor.White => ConsoleColor.Gray,
|
||||||
|
ConsoleColor.Yellow => ConsoleColor.DarkYellow,
|
||||||
|
_ => color,
|
||||||
|
};
|
||||||
|
}
|
18
ProjectLighthouse/Helpers/Extensions/LogLevelExtensions.cs
Normal file
18
ProjectLighthouse/Helpers/Extensions/LogLevelExtensions.cs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
using System;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
|
|
||||||
|
public static class LogLevelExtensions
|
||||||
|
{
|
||||||
|
public static ConsoleColor ToColor(this LogLevel level)
|
||||||
|
=> level switch
|
||||||
|
{
|
||||||
|
LogLevel.Debug => ConsoleColor.Magenta,
|
||||||
|
LogLevel.Error => ConsoleColor.Red,
|
||||||
|
LogLevel.Warning => ConsoleColor.Yellow,
|
||||||
|
LogLevel.Info => ConsoleColor.White,
|
||||||
|
LogLevel.Success => ConsoleColor.Green,
|
||||||
|
_ => ConsoleColor.White,
|
||||||
|
};
|
||||||
|
}
|
|
@ -6,7 +6,6 @@ using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Files;
|
using LBPUnion.ProjectLighthouse.Types.Files;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
@ -115,8 +114,7 @@ public static class FileHelper
|
||||||
EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png"));
|
EnsureDirectoryCreated(Path.Combine(Environment.CurrentDirectory, "png"));
|
||||||
if (Directory.Exists("r"))
|
if (Directory.Exists("r"))
|
||||||
{
|
{
|
||||||
Logger.Log
|
Logger.LogInfo("Converting all textures to PNG. This may take a while if this is the first time running this operation...", "Startup");
|
||||||
("Converting all textures to PNG. This may take a while if this is the first time running this operation...", LoggerLevelStartup.Instance);
|
|
||||||
|
|
||||||
ConcurrentQueue<string> fileQueue = new();
|
ConcurrentQueue<string> fileQueue = new();
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using InfluxDB.Client;
|
using InfluxDB.Client;
|
||||||
using InfluxDB.Client.Writes;
|
using InfluxDB.Client.Writes;
|
||||||
using Kettu;
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
@ -49,9 +49,8 @@ public static class InfluxHelper
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log("Exception while logging: ", LoggerLevelInflux.Instance);
|
Logger.LogError("Exception while logging: ", "InfluxDB");
|
||||||
|
Logger.LogError(e.ToDetailedException(), "InfluxDB");
|
||||||
foreach (string line in e.ToString().Split("\n")) Logger.Log(line, LoggerLevelInflux.Instance);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +58,7 @@ public static class InfluxHelper
|
||||||
public static async Task StartLogging()
|
public static async Task StartLogging()
|
||||||
{
|
{
|
||||||
await Client.ReadyAsync();
|
await Client.ReadyAsync();
|
||||||
Logger.Log("InfluxDB is now ready.", LoggerLevelInflux.Instance);
|
Logger.LogSuccess("InfluxDB is now ready.", "InfluxDB");
|
||||||
Thread t = new
|
Thread t = new
|
||||||
(
|
(
|
||||||
delegate()
|
delegate()
|
||||||
|
@ -72,9 +71,8 @@ public static class InfluxHelper
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log("Exception while running log thread: ", LoggerLevelInflux.Instance);
|
Logger.LogError("Exception while running log thread: ", "InfluxDB");
|
||||||
|
Logger.LogError(e.ToDetailedException(), "InfluxDB");
|
||||||
foreach (string line in e.ToString().Split("\n")) Logger.Log(line, LoggerLevelInflux.Instance);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread.Sleep(60000);
|
Thread.Sleep(60000);
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
@ -46,7 +45,7 @@ public class RoomHelper
|
||||||
{
|
{
|
||||||
if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP)
|
if (roomVersion == GameVersion.LittleBigPlanet1 || roomVersion == GameVersion.LittleBigPlanetPSP)
|
||||||
{
|
{
|
||||||
Logger.Log($"Returning null for FindBestRoom, game ({roomVersion}) does not support dive in (should never happen?)", LoggerLevelMatch.Instance);
|
Logger.LogError($"Returning null for FindBestRoom, game ({roomVersion}) does not support dive in (should never happen?)", "Match");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,7 +139,7 @@ public class RoomHelper
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
Logger.Log($"Found a room (id: {room.RoomId}) for user {user?.Username ?? "null"} (id: {user?.UserId ?? -1})", LoggerLevelMatch.Instance);
|
Logger.LogSuccess($"Found a room (id: {room.RoomId}) for user {user?.Username ?? "null"} (id: {user?.UserId ?? -1})", "Match");
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
@ -173,7 +172,7 @@ public class RoomHelper
|
||||||
|
|
||||||
CleanupRooms(room.Host, room);
|
CleanupRooms(room.Host, room);
|
||||||
lock(Rooms) Rooms.Add(room);
|
lock(Rooms) Rooms.Add(room);
|
||||||
Logger.Log($"Created room (id: {room.RoomId}) for host {room.Host.Username} (id: {room.Host.UserId})", LoggerLevelMatch.Instance);
|
Logger.LogInfo($"Created room (id: {room.RoomId}) for host {room.Host.Username} (id: {room.Host.UserId})", "Match");
|
||||||
|
|
||||||
return room;
|
return room;
|
||||||
}
|
}
|
||||||
|
@ -238,7 +237,7 @@ public class RoomHelper
|
||||||
|
|
||||||
if (roomCountBeforeCleanup != roomCountAfterCleanup)
|
if (roomCountBeforeCleanup != roomCountAfterCleanup)
|
||||||
{
|
{
|
||||||
Logger.Log($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", LoggerLevelMatch.Instance);
|
Logger.LogDebug($"Cleaned up {roomCountBeforeCleanup - roomCountAfterCleanup} rooms.", "Match");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,14 @@ using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Helpers;
|
namespace LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>
|
||||||
|
/// A filter for the swagger documentation endpoint.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Makes sure that only endpoints under <c>/api/v1</c> show up.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
public class SwaggerFilter : IDocumentFilter
|
public class SwaggerFilter : IDocumentFilter
|
||||||
{
|
{
|
||||||
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
|
||||||
|
@ -30,11 +29,11 @@ public static class VersionHelper
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
Logger.Log
|
Logger.LogError
|
||||||
(
|
(
|
||||||
"Project Lighthouse was built incorrectly. Please make sure git is available when building. " +
|
"Project Lighthouse was built incorrectly. Please make sure git is available when building. " +
|
||||||
"Because of this, you will not be notified of updates.",
|
"Because of this, you will not be notified of updates.",
|
||||||
LoggerLevelStartup.Instance
|
"Startup"
|
||||||
);
|
);
|
||||||
CommitHash = "invalid";
|
CommitHash = "invalid";
|
||||||
Branch = "invalid";
|
Branch = "invalid";
|
||||||
|
@ -43,11 +42,11 @@ public static class VersionHelper
|
||||||
|
|
||||||
if (IsDirty)
|
if (IsDirty)
|
||||||
{
|
{
|
||||||
Logger.Log
|
Logger.LogWarn
|
||||||
(
|
(
|
||||||
"This is a modified version of Project Lighthouse. " +
|
"This is a modified version of Project Lighthouse. " +
|
||||||
"Please make sure you are properly disclosing the source code to any users who may be using this instance.",
|
"Please make sure you are properly disclosing the source code to any users who may be using this instance.",
|
||||||
LoggerLevelStartup.Instance
|
"Startup"
|
||||||
);
|
);
|
||||||
CanCheckForUpdates = false;
|
CanCheckForUpdates = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
using System;
|
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging;
|
|
||||||
|
|
||||||
public class AspNetToKettuLogger : ILogger
|
|
||||||
{
|
|
||||||
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
|
|
||||||
public bool IsEnabled(LogLevel logLevel) => true;
|
|
||||||
|
|
||||||
public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
|
||||||
{
|
|
||||||
LoggerLevel loggerLevel = new LoggerLevelAspNet(logLevel);
|
|
||||||
|
|
||||||
Logger.Log(state.ToString(), loggerLevel);
|
|
||||||
if (exception == null) return;
|
|
||||||
|
|
||||||
string[] lines = exception.ToDetailedException().Replace("\r", "").Split("\n");
|
|
||||||
foreach (string line in lines) Logger.Log(line, loggerLevel);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
using System;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging;
|
|
||||||
|
|
||||||
[ProviderAlias("Kettu")]
|
|
||||||
public class AspNetToKettuLoggerProvider : ILoggerProvider, IDisposable
|
|
||||||
{
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ILogger CreateLogger(string categoryName) => new AspNetToKettuLogger();
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging;
|
|
||||||
|
|
||||||
public class LighthouseFileLogger : LoggerBase
|
|
||||||
{
|
|
||||||
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
|
||||||
public override bool AllowMultiple => false;
|
|
||||||
|
|
||||||
public override void Send(LoggerLine line)
|
|
||||||
{
|
|
||||||
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
|
||||||
|
|
||||||
string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] ";
|
|
||||||
|
|
||||||
string contentFile = $"{channel}{line.LineData}\n";
|
|
||||||
string contentAll = $"[{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}] {line.LineData}\n";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.AppendAllText(Path.Combine(logsDirectory, line.LoggerLevel.Name.ToFileName() + ".log"), contentFile);
|
|
||||||
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
|
|
||||||
}
|
|
||||||
catch(IOException) {} // windows, ya goofed
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
10
ProjectLighthouse/Logging/LogLevel.cs
Normal file
10
ProjectLighthouse/Logging/LogLevel.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
public enum LogLevel
|
||||||
|
{
|
||||||
|
Success = 0,
|
||||||
|
Info = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Error = 3,
|
||||||
|
Debug = 4,
|
||||||
|
}
|
9
ProjectLighthouse/Logging/LogLine.cs
Normal file
9
ProjectLighthouse/Logging/LogLine.cs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
public struct LogLine
|
||||||
|
{
|
||||||
|
public LogTrace Trace;
|
||||||
|
public LogLevel Level;
|
||||||
|
public string Area;
|
||||||
|
public string Message;
|
||||||
|
}
|
7
ProjectLighthouse/Logging/LogTrace.cs
Normal file
7
ProjectLighthouse/Logging/LogTrace.cs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
public struct LogTrace
|
||||||
|
{
|
||||||
|
public string Name;
|
||||||
|
public short Line;
|
||||||
|
}
|
174
ProjectLighthouse/Logging/Logger.cs
Normal file
174
ProjectLighthouse/Logging/Logger.cs
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics.CodeAnalysis;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
// TODO: make into singleton, but with ability to also have instances
|
||||||
|
// Logger.LogSuccess() should still work and all, but ideally i'm also able to have another instance and do:
|
||||||
|
// Logger logger = new();
|
||||||
|
// logger.LogSuccess();
|
||||||
|
// I should also be able to access the log queue.
|
||||||
|
// This functionality is going to be used in the admin panel to get the output of commands.
|
||||||
|
public static class Logger
|
||||||
|
{
|
||||||
|
|
||||||
|
#region Internals
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A list of custom loggers to use.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly List<ILogger> loggers = new();
|
||||||
|
|
||||||
|
public static void AddLogger(ILogger logger)
|
||||||
|
{
|
||||||
|
loggers.Add(logger);
|
||||||
|
LogSuccess("Initialized " + logger.GetType().Name, "Logger");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static LogTrace getTrace()
|
||||||
|
{
|
||||||
|
const int depth = 6;
|
||||||
|
const int skipDepth = depth - 2;
|
||||||
|
|
||||||
|
// Get the stacktrace for logging...
|
||||||
|
string trace = Environment.StackTrace.Split('\n', depth, StringSplitOptions.RemoveEmptyEntries).Skip(skipDepth).First();
|
||||||
|
|
||||||
|
trace = trace.TrimEnd('\r');
|
||||||
|
trace = trace.Substring(trace.LastIndexOf(Path.DirectorySeparatorChar) + 1);
|
||||||
|
trace = trace.Replace(".cs:line ", ":");
|
||||||
|
|
||||||
|
string[] traceSplit = trace.Split(':'); // Split for formatting!
|
||||||
|
|
||||||
|
short lineNumber;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lineNumber = short.Parse(traceSplit[1]);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
lineNumber = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new LogTrace
|
||||||
|
{
|
||||||
|
Name = traceSplit[0],
|
||||||
|
Line = lineNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Queue
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <para>A queue for the logger.</para>
|
||||||
|
/// <para>
|
||||||
|
/// We use a queue because if two threads try to log something at the time they'll mess each other's printing up.
|
||||||
|
/// </para>
|
||||||
|
/// </summary>
|
||||||
|
private static readonly ConcurrentQueue<LogLine> logQueue = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a <see cref="LogLine"/> to the queue. Only used internally.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="logLine">The logLine to send to the queue.</param>
|
||||||
|
private static void queueLog(LogLine logLine)
|
||||||
|
{
|
||||||
|
logQueue.Enqueue(logLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "FunctionNeverReturns")]
|
||||||
|
static Logger() // Start queue thread on first Logger access
|
||||||
|
{
|
||||||
|
Task.Factory.StartNew
|
||||||
|
(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
bool logged = queueLoop();
|
||||||
|
Thread.Sleep(logged ? 10 : 100);
|
||||||
|
// We wait 100ms if we dont log since it's less likely that the program logged again.
|
||||||
|
// If we did log, wait 10ms before looping again.
|
||||||
|
|
||||||
|
// This is all so we use as little CPU as possible. This is an endless while loop, after all.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A function used by the queue thread
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
private static bool queueLoop()
|
||||||
|
{
|
||||||
|
bool logged = false;
|
||||||
|
if (logQueue.TryDequeue(out LogLine line))
|
||||||
|
{
|
||||||
|
logged = true;
|
||||||
|
|
||||||
|
foreach (ILogger logger in loggers)
|
||||||
|
{
|
||||||
|
logger.Log(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return logged;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Logging functions
|
||||||
|
|
||||||
|
public static void LogDebug(string text, string area = "")
|
||||||
|
{
|
||||||
|
#if DEBUG
|
||||||
|
Log(text, area, LogLevel.Debug);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogSuccess(string text, string area = "")
|
||||||
|
{
|
||||||
|
Log(text, area, LogLevel.Success);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogInfo(string text, string area = "")
|
||||||
|
{
|
||||||
|
Log(text, area, LogLevel.Info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogWarn(string text, string area = "")
|
||||||
|
{
|
||||||
|
Log(text, area, LogLevel.Warning);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LogError(string text, string area = "")
|
||||||
|
{
|
||||||
|
Log(text, area, LogLevel.Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Log(string text, string area, LogLevel level)
|
||||||
|
{
|
||||||
|
queueLog
|
||||||
|
(
|
||||||
|
new LogLine
|
||||||
|
{
|
||||||
|
Level = level,
|
||||||
|
Message = text,
|
||||||
|
Area = area,
|
||||||
|
Trace = getTrace(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
}
|
6
ProjectLighthouse/Logging/LoggerBase.cs
Normal file
6
ProjectLighthouse/Logging/LoggerBase.cs
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
|
public interface ILogger
|
||||||
|
{
|
||||||
|
public void Log(LogLine line);
|
||||||
|
}
|
|
@ -1,86 +0,0 @@
|
||||||
using Kettu;
|
|
||||||
using Microsoft.Extensions.Logging;
|
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging;
|
|
||||||
|
|
||||||
public class LoggerLevelStartup : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelStartup Instance = new();
|
|
||||||
public override string Name => "Startup";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelDatabase : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelDatabase Instance = new();
|
|
||||||
public override string Name => "Database";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelHttp : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelHttp Instance = new();
|
|
||||||
public override string Name => "HTTP";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelFilter : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelFilter Instance = new();
|
|
||||||
public override string Name => "Filter";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelLogin : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelLogin Instance = new();
|
|
||||||
public override string Name => "Login";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelResources : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelResources Instance = new();
|
|
||||||
public override string Name => "Resources";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelMatch : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelMatch Instance = new();
|
|
||||||
public override string Name => "Match";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelPhotos : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelPhotos Instance = new();
|
|
||||||
public override string Name => "Photos";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelConfig : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelConfig Instance = new();
|
|
||||||
public override string Name => "Config";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelInflux : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelInflux Instance = new();
|
|
||||||
public override string Name => "Influx";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelComments : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelComments Instance = new();
|
|
||||||
public override string Name => "Comments";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelAspNet : LoggerLevel
|
|
||||||
{
|
|
||||||
|
|
||||||
public LoggerLevelAspNet(LogLevel level)
|
|
||||||
{
|
|
||||||
this.Channel = level.ToString();
|
|
||||||
}
|
|
||||||
public override string Name => "AspNet";
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LoggerLevelCategory : LoggerLevel
|
|
||||||
{
|
|
||||||
public static readonly LoggerLevelCategory Instance = new();
|
|
||||||
public override string Name => "Category";
|
|
||||||
}
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
using System;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using AspLogLevel = Microsoft.Extensions.Logging.LogLevel;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||||
|
|
||||||
|
public class AspNetToLighthouseLogger : Microsoft.Extensions.Logging.ILogger
|
||||||
|
{
|
||||||
|
public IDisposable BeginScope<TState>(TState state) => NullScope.Instance;
|
||||||
|
public bool IsEnabled(AspLogLevel logLevel) => true;
|
||||||
|
|
||||||
|
public string Category { get; init; }
|
||||||
|
|
||||||
|
public AspNetToLighthouseLogger(string category)
|
||||||
|
{
|
||||||
|
this.Category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Log<TState>(AspLogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
|
||||||
|
{
|
||||||
|
LogLevel level = logLevel.ToLighthouseLevel();
|
||||||
|
|
||||||
|
Logger.Log(state.ToString(), this.Category, level);
|
||||||
|
|
||||||
|
if (exception == null) return;
|
||||||
|
|
||||||
|
Logger.Log(exception.ToDetailedException(), this.Category, level);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
using System;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using IAspLogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||||
|
|
||||||
|
[ProviderAlias("Kettu")]
|
||||||
|
public class AspNetToLighthouseLoggerProvider : ILoggerProvider, IDisposable
|
||||||
|
{
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IAspLogger CreateLogger(string category) => new AspNetToLighthouseLogger(category);
|
||||||
|
}
|
44
ProjectLighthouse/Logging/Loggers/ConsoleLogger.cs
Normal file
44
ProjectLighthouse/Logging/Loggers/ConsoleLogger.cs
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
using System;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
|
||||||
|
public class ConsoleLogger : ILogger
|
||||||
|
{
|
||||||
|
public void Log(LogLine logLine)
|
||||||
|
{
|
||||||
|
ConsoleColor oldBackgroundColor = Console.BackgroundColor;
|
||||||
|
ConsoleColor oldForegroundColor = Console.ForegroundColor;
|
||||||
|
|
||||||
|
foreach (string line in logLine.Message.Split('\n'))
|
||||||
|
{
|
||||||
|
// The following is scuffed. Beware~
|
||||||
|
|
||||||
|
// Write the level! [Success]
|
||||||
|
Console.BackgroundColor = logLine.Level.ToColor().ToDark();
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write('[');
|
||||||
|
Console.ForegroundColor = logLine.Level.ToColor();
|
||||||
|
Console.Write(logLine.Level);
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write(']');
|
||||||
|
Console.ForegroundColor = oldForegroundColor;
|
||||||
|
Console.BackgroundColor = oldBackgroundColor;
|
||||||
|
Console.Write(' ');
|
||||||
|
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write('<');
|
||||||
|
Console.ForegroundColor = logLine.Level.ToColor();
|
||||||
|
Console.Write(logLine.Trace.Name);
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write(':');
|
||||||
|
Console.ForegroundColor = logLine.Level.ToColor();
|
||||||
|
Console.Write(logLine.Trace.Line);
|
||||||
|
Console.ForegroundColor = ConsoleColor.White;
|
||||||
|
Console.Write("> ");
|
||||||
|
Console.ForegroundColor = oldForegroundColor;
|
||||||
|
|
||||||
|
Console.WriteLine(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,21 +1,18 @@
|
||||||
using InfluxDB.Client;
|
using InfluxDB.Client;
|
||||||
using InfluxDB.Client.Writes;
|
using InfluxDB.Client.Writes;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Logging;
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
|
||||||
public class InfluxLogger : LoggerBase
|
public class InfluxLogger : ILogger
|
||||||
{
|
{
|
||||||
public override bool AllowMultiple => false;
|
public void Log(LogLine line)
|
||||||
|
|
||||||
public override void Send(LoggerLine line)
|
|
||||||
{
|
{
|
||||||
string channel = string.IsNullOrEmpty(line.LoggerLevel.Channel) ? "" : $"[{line.LoggerLevel.Channel}] ";
|
string channel = string.IsNullOrEmpty(line.Area) ? "" : $"[{line.Area}] ";
|
||||||
|
|
||||||
string level = $"{$"{line.LoggerLevel.Name} {channel}".TrimEnd()}";
|
string level = $"{$"{channel} {line}".TrimEnd()}";
|
||||||
string content = line.LineData;
|
string content = line.Message;
|
||||||
|
|
||||||
using WriteApi writeApi = InfluxHelper.Client.GetWriteApi();
|
using WriteApi writeApi = InfluxHelper.Client.GetWriteApi();
|
||||||
|
|
28
ProjectLighthouse/Logging/Loggers/LighthouseFileLogger.cs
Normal file
28
ProjectLighthouse/Logging/Loggers/LighthouseFileLogger.cs
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
|
|
||||||
|
namespace LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
|
||||||
|
public class LighthouseFileLogger : ILogger
|
||||||
|
{
|
||||||
|
private static readonly string logsDirectory = Path.Combine(Environment.CurrentDirectory, "logs");
|
||||||
|
|
||||||
|
public void Log(LogLine line)
|
||||||
|
{
|
||||||
|
FileHelper.EnsureDirectoryCreated(logsDirectory);
|
||||||
|
|
||||||
|
string channel = string.IsNullOrEmpty(line.Area) ? "" : $"[{line.Area}] ";
|
||||||
|
|
||||||
|
string contentFile = $"{channel}{line.Message}\n";
|
||||||
|
string contentAll = $"[{$"{line.Level} {channel}".TrimEnd()}] {line.Message}\n";
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File.AppendAllText(Path.Combine(logsDirectory, line.Level + ".log"), contentFile);
|
||||||
|
File.AppendAllText(Path.Combine(logsDirectory, "all.log"), contentAll);
|
||||||
|
}
|
||||||
|
catch(IOException) {} // windows, ya goofed
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types;
|
using LBPUnion.ProjectLighthouse.Types;
|
||||||
|
@ -25,17 +24,17 @@ public class CreateUserCommand : ICommand
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
|
user = await this._database.CreateUser(onlineId, CryptoHelper.BCryptHash(password));
|
||||||
Logger.Log($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", LoggerLevelLogin.Instance);
|
Logger.LogSuccess($"Created user {user.UserId} with online ID (username) {user.Username} and the specified password.", "Login");
|
||||||
|
|
||||||
user.PasswordResetRequired = true;
|
user.PasswordResetRequired = true;
|
||||||
Logger.Log("This user will need to reset their password when they log in.", LoggerLevelLogin.Instance);
|
Logger.LogInfo("This user will need to reset their password when they log in.", "Login");
|
||||||
|
|
||||||
await this._database.SaveChangesAsync();
|
await this._database.SaveChangesAsync();
|
||||||
Logger.Log("Database changes saved.", LoggerLevelDatabase.Instance);
|
Logger.LogInfo("Database changes saved.", "Database");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Logger.Log("A user with this username already exists.", LoggerLevelLogin.Instance);
|
Logger.LogError("A user with this username already exists.", "Login");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
@ -47,28 +46,28 @@ public class LoginForm : BaseLayout
|
||||||
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
Logger.Log($"User {username} failed to login on web due to invalid username", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"User {username} failed to login on web due to invalid username", "Login");
|
||||||
this.Error = "The username or password you entered is invalid.";
|
this.Error = "The username or password you entered is invalid.";
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BCrypt.Net.BCrypt.Verify(password, user.Password))
|
if (!BCrypt.Net.BCrypt.Verify(password, user.Password))
|
||||||
{
|
{
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login on web due to invalid password", "Login");
|
||||||
this.Error = "The username or password you entered is invalid.";
|
this.Error = "The username or password you entered is invalid.";
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.Banned)
|
if (user.Banned)
|
||||||
{
|
{
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login on web due to being banned", "Login");
|
||||||
this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason;
|
this.Error = "You have been banned. Please contact an administrator for more information.\nReason: " + user.BannedReason;
|
||||||
return this.Page();
|
return this.Page();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled)
|
if (user.EmailAddress == null && ServerSettings.Instance.SMTPEnabled)
|
||||||
{
|
{
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) failed to login; email not set", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"User {user.Username} (id: {user.UserId}) failed to login; email not set", "Login");
|
||||||
|
|
||||||
EmailSetToken emailSetToken = new()
|
EmailSetToken emailSetToken = new()
|
||||||
{
|
{
|
||||||
|
@ -102,7 +101,7 @@ public class LoginForm : BaseLayout
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance);
|
Logger.LogSuccess($"User {user.Username} (id: {user.UserId}) successfully logged in on web", "Login");
|
||||||
|
|
||||||
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
|
||||||
if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
if (ServerSettings.Instance.SMTPEnabled && !user.EmailAddressVerified) return this.Redirect("~/login/sendVerificationEmail");
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
using LBPUnion.ProjectLighthouse.Pages.Layouts;
|
||||||
|
@ -72,7 +71,7 @@ public class SetEmailForm : BaseLayout
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web after setting an email address", LoggerLevelLogin.Instance);
|
Logger.LogSuccess($"User {user.Username} (id: {user.UserId}) successfully logged in on web after setting an email address", "Login");
|
||||||
|
|
||||||
this.Database.WebTokens.Add(webToken);
|
this.Database.WebTokens.Add(webToken);
|
||||||
await this.Database.SaveChangesAsync();
|
await this.Database.SaveChangesAsync();
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging.Loggers;
|
||||||
|
using LBPUnion.ProjectLighthouse.Logging.Loggers.AspNet;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -23,46 +24,47 @@ public static class Program
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
// Setup logging
|
// Setup logging
|
||||||
|
|
||||||
Logger.StartLogging();
|
|
||||||
Logger.UpdateRate /= 2;
|
|
||||||
LoggerLine.LogFormat = "[{0}] {1}";
|
|
||||||
Logger.AddLogger(new ConsoleLogger());
|
Logger.AddLogger(new ConsoleLogger());
|
||||||
Logger.AddLogger(new LighthouseFileLogger());
|
Logger.AddLogger(new LighthouseFileLogger());
|
||||||
|
|
||||||
Logger.Log("Welcome to Project Lighthouse!", LoggerLevelStartup.Instance);
|
Logger.LogInfo("Welcome to Project Lighthouse!", "Startup");
|
||||||
Logger.Log($"You are running version {VersionHelper.FullVersion}", LoggerLevelStartup.Instance);
|
Logger.LogInfo($"You are running version {VersionHelper.FullVersion}", "Startup");
|
||||||
|
|
||||||
// Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information
|
// Referencing ServerSettings.Instance here loads the config, see ServerSettings.cs for more information
|
||||||
Logger.Log("Loaded config file version " + ServerSettings.Instance.ConfigVersion, LoggerLevelStartup.Instance);
|
Logger.LogSuccess("Loaded config file version " + ServerSettings.Instance.ConfigVersion, "Startup");
|
||||||
|
|
||||||
Logger.Log("Determining if the database is available...", LoggerLevelStartup.Instance);
|
Logger.LogInfo("Determining if the database is available...", "Startup");
|
||||||
bool dbConnected = ServerStatics.DbConnected;
|
bool dbConnected = ServerStatics.DbConnected;
|
||||||
Logger.Log(dbConnected ? "Connected to the database." : "Database unavailable! Exiting.", LoggerLevelStartup.Instance);
|
if (!dbConnected)
|
||||||
|
{
|
||||||
|
Logger.LogError("Database unavailable! Exiting.", "Startup");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Logger.LogSuccess("Connected to the database.", "Startup");
|
||||||
|
}
|
||||||
|
|
||||||
if (!dbConnected) Environment.Exit(1);
|
if (!dbConnected) Environment.Exit(1);
|
||||||
using Database database = new();
|
using Database database = new();
|
||||||
|
|
||||||
Logger.Log("Migrating database...", LoggerLevelDatabase.Instance);
|
Logger.LogInfo("Migrating database...", "Database");
|
||||||
MigrateDatabase(database);
|
MigrateDatabase(database);
|
||||||
|
|
||||||
if (ServerSettings.Instance.InfluxEnabled)
|
if (ServerSettings.Instance.InfluxEnabled)
|
||||||
{
|
{
|
||||||
Logger.Log("Influx logging is enabled. Starting influx logging...", LoggerLevelStartup.Instance);
|
Logger.LogInfo("Influx logging is enabled. Starting influx logging...", "Startup");
|
||||||
InfluxHelper.StartLogging().Wait();
|
InfluxHelper.StartLogging().Wait();
|
||||||
if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger());
|
if (ServerSettings.Instance.InfluxLoggingEnabled) Logger.AddLogger(new InfluxLogger());
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
Logger.LogDebug
|
||||||
Logger.Log
|
|
||||||
(
|
(
|
||||||
"This is a debug build, so performance may suffer! " +
|
"This is a debug build, so performance may suffer! " +
|
||||||
"If you are running Lighthouse in a production environment, " +
|
"If you are running Lighthouse in a production environment, " +
|
||||||
"it is highly recommended to run a release build. ",
|
"it is highly recommended to run a release build. ",
|
||||||
LoggerLevelStartup.Instance
|
"Startup"
|
||||||
);
|
);
|
||||||
Logger.Log("You can do so by running any dotnet command with the flag: \"-c Release\". ", LoggerLevelStartup.Instance);
|
Logger.LogDebug("You can do so by running any dotnet command with the flag: \"-c Release\". ", "Startup");
|
||||||
#endif
|
|
||||||
|
|
||||||
if (args.Length != 0)
|
if (args.Length != 0)
|
||||||
{
|
{
|
||||||
|
@ -72,11 +74,11 @@ public static class Program
|
||||||
|
|
||||||
if (ServerSettings.Instance.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng();
|
if (ServerSettings.Instance.ConvertAssetsOnStartup) FileHelper.ConvertAllTexturesToPng();
|
||||||
|
|
||||||
Logger.Log("Starting room cleanup thread...", LoggerLevelStartup.Instance);
|
Logger.LogInfo("Starting room cleanup thread...", "Startup");
|
||||||
RoomHelper.StartCleanupThread();
|
RoomHelper.StartCleanupThread();
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Logger.Log($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", LoggerLevelStartup.Instance);
|
Logger.LogSuccess($"Ready! Startup took {stopwatch.ElapsedMilliseconds}ms. Passing off control to ASP.NET...", "Startup");
|
||||||
|
|
||||||
CreateHostBuilder(args).Build().Run();
|
CreateHostBuilder(args).Build().Run();
|
||||||
}
|
}
|
||||||
|
@ -89,7 +91,7 @@ public static class Program
|
||||||
database.Database.MigrateAsync().Wait();
|
database.Database.MigrateAsync().Wait();
|
||||||
|
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
Logger.Log($"Migration took {stopwatch.ElapsedMilliseconds}ms.", LoggerLevelDatabase.Instance);
|
Logger.LogSuccess($"Migration took {stopwatch.ElapsedMilliseconds}ms.", "Database");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args)
|
public static IHostBuilder CreateHostBuilder(string[] args)
|
||||||
|
@ -108,7 +110,7 @@ public static class Program
|
||||||
logging =>
|
logging =>
|
||||||
{
|
{
|
||||||
logging.ClearProviders();
|
logging.ClearProviders();
|
||||||
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToKettuLoggerProvider>());
|
logging.Services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, AspNetToLighthouseLoggerProvider>());
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -17,7 +17,6 @@
|
||||||
<PackageReference Include="Discord.Net.Webhook" Version="3.6.1"/>
|
<PackageReference Include="Discord.Net.Webhook" Version="3.6.1"/>
|
||||||
<PackageReference Include="InfluxDB.Client" Version="4.1.0"/>
|
<PackageReference Include="InfluxDB.Client" Version="4.1.0"/>
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0"/>
|
<PackageReference Include="JetBrains.Annotations" Version="2022.1.0"/>
|
||||||
<PackageReference Include="Kettu" Version="1.2.4"/>
|
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.4"/>
|
<PackageReference Include="Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore" Version="6.0.4"/>
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.4"/>
|
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="6.0.4"/>
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4"/>
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="6.0.4"/>
|
||||||
|
|
|
@ -2,7 +2,7 @@ using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Kettu;
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Settings;
|
using LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
@ -40,18 +40,18 @@ public class DebugWarmupLifetime : IHostLifetime
|
||||||
string url = ServerSettings.Instance.ServerListenUrl;
|
string url = ServerSettings.Instance.ServerListenUrl;
|
||||||
url = url.Replace("0.0.0.0", "127.0.0.1");
|
url = url.Replace("0.0.0.0", "127.0.0.1");
|
||||||
|
|
||||||
Logger.Log("Warming up Hot Reload...", LoggerLevelStartup.Instance);
|
Logger.LogDebug("Warming up Hot Reload...", "Startup");
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.GetAsync(url).Wait();
|
client.GetAsync(url).Wait();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log("An error occurred while attempting to warm up hot reload. Initial page load will be delayed.", LoggerLevelStartup.Instance);
|
Logger.LogDebug("An error occurred while attempting to warm up hot reload. Initial page load will be delayed.", "Startup");
|
||||||
Logger.Log(e.Message, LoggerLevelStartup.Instance);
|
Logger.LogDebug(e.ToDetailedException(), "Startup");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Logger.Log("Hot Reload is ready to go!", LoggerLevelStartup.Instance);
|
Logger.LogSuccess("Hot Reload is ready to go!", "Startup");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken) => this.consoleLifetime.StopAsync(cancellationToken);
|
public Task StopAsync(CancellationToken cancellationToken) => this.consoleLifetime.StopAsync(cancellationToken);
|
||||||
|
|
|
@ -2,7 +2,6 @@ using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
|
@ -99,11 +98,11 @@ public class Startup
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey))
|
if (string.IsNullOrEmpty(ServerSettings.Instance.ServerDigestKey))
|
||||||
{
|
{
|
||||||
Logger.Log
|
Logger.LogWarn
|
||||||
(
|
(
|
||||||
"The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " +
|
"The serverDigestKey configuration option wasn't set, so digest headers won't be set or verified. This will also prevent LBP 1, LBP 2, and LBP Vita from working. " +
|
||||||
"To increase security, it is recommended that you find and set this variable.",
|
"To increase security, it is recommended that you find and set this variable.",
|
||||||
LoggerLevelStartup.Instance
|
"Startup"
|
||||||
);
|
);
|
||||||
computeDigests = false;
|
computeDigests = false;
|
||||||
}
|
}
|
||||||
|
@ -142,10 +141,10 @@ public class Startup
|
||||||
|
|
||||||
requestStopwatch.Stop();
|
requestStopwatch.Stop();
|
||||||
|
|
||||||
Logger.Log
|
Logger.LogInfo
|
||||||
(
|
(
|
||||||
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
$"{context.Response.StatusCode}, {requestStopwatch.ElapsedMilliseconds}ms: {context.Request.Method} {context.Request.Path}{context.Request.QueryString}",
|
||||||
LoggerLevelHttp.Instance
|
"HTTP"
|
||||||
);
|
);
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
|
@ -153,7 +152,7 @@ public class Startup
|
||||||
if (context.Request.Method == "POST")
|
if (context.Request.Method == "POST")
|
||||||
{
|
{
|
||||||
context.Request.Body.Position = 0;
|
context.Request.Body.Position = 0;
|
||||||
Logger.Log(await new StreamReader(context.Request.Body).ReadToEndAsync(), LoggerLevelHttp.Instance);
|
Logger.LogDebug(await new StreamReader(context.Request.Body).ReadToEndAsync(), "HTTP");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
using LBPUnion.ProjectLighthouse.Serialization;
|
using LBPUnion.ProjectLighthouse.Serialization;
|
||||||
using LBPUnion.ProjectLighthouse.Types.Levels;
|
using LBPUnion.ProjectLighthouse.Types.Levels;
|
||||||
|
@ -14,7 +13,7 @@ public abstract class CategoryWithUser : Category
|
||||||
public override Slot? GetPreviewSlot(Database database)
|
public override Slot? GetPreviewSlot(Database database)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Log("tried to get preview slot without user on CategoryWithUser", LoggerLevelCategory.Instance);
|
Logger.LogError("tried to get preview slot without user on CategoryWithUser", "Category");
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
if (Debugger.IsAttached) Debugger.Break();
|
||||||
#endif
|
#endif
|
||||||
return null;
|
return null;
|
||||||
|
@ -24,7 +23,7 @@ public abstract class CategoryWithUser : Category
|
||||||
public override int GetTotalSlots(Database database)
|
public override int GetTotalSlots(Database database)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Log("tried to get total slots without user on CategoryWithUser", LoggerLevelCategory.Instance);
|
Logger.LogError("tried to get total slots without user on CategoryWithUser", "Category");
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
if (Debugger.IsAttached) Debugger.Break();
|
||||||
#endif
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -34,7 +33,7 @@ public abstract class CategoryWithUser : Category
|
||||||
public override IEnumerable<Slot> GetSlots(Database database, int pageStart, int pageSize)
|
public override IEnumerable<Slot> GetSlots(Database database, int pageStart, int pageSize)
|
||||||
{
|
{
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Log("tried to get slots without user on CategoryWithUser", LoggerLevelCategory.Instance);
|
Logger.LogError("tried to get slots without user on CategoryWithUser", "Category");
|
||||||
if (Debugger.IsAttached) Debugger.Break();
|
if (Debugger.IsAttached) Debugger.Break();
|
||||||
#endif
|
#endif
|
||||||
return new List<Slot>();
|
return new List<Slot>();
|
||||||
|
@ -42,7 +41,7 @@ public abstract class CategoryWithUser : Category
|
||||||
|
|
||||||
public new string Serialize(Database database)
|
public new string Serialize(Database database)
|
||||||
{
|
{
|
||||||
Logger.Log("tried to serialize without user on CategoryWithUser", LoggerLevelCategory.Instance);
|
Logger.LogError("tried to serialize without user on CategoryWithUser", "Category");
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ using System.IO;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
@ -20,7 +19,7 @@ public class ServerSettings
|
||||||
{
|
{
|
||||||
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
if (ServerStatics.IsUnitTesting) return; // Unit testing, we don't want to read configurations here since the tests will provide their own
|
||||||
|
|
||||||
Logger.Log("Loading config...", LoggerLevelConfig.Instance);
|
Logger.LogInfo("Loading config...", "Config");
|
||||||
|
|
||||||
if (File.Exists(ConfigFileName))
|
if (File.Exists(ConfigFileName))
|
||||||
{
|
{
|
||||||
|
@ -30,7 +29,7 @@ public class ServerSettings
|
||||||
|
|
||||||
if (Instance.ConfigVersion < CurrentConfigVersion)
|
if (Instance.ConfigVersion < CurrentConfigVersion)
|
||||||
{
|
{
|
||||||
Logger.Log($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", LoggerLevelConfig.Instance);
|
Logger.LogInfo($"Upgrading config file from version {Instance.ConfigVersion} to version {CurrentConfigVersion}", "Config");
|
||||||
Instance.ConfigVersion = CurrentConfigVersion;
|
Instance.ConfigVersion = CurrentConfigVersion;
|
||||||
configFile = JsonSerializer.Serialize
|
configFile = JsonSerializer.Serialize
|
||||||
(
|
(
|
||||||
|
@ -59,12 +58,12 @@ public class ServerSettings
|
||||||
|
|
||||||
File.WriteAllText(ConfigFileName, configFile);
|
File.WriteAllText(ConfigFileName, configFile);
|
||||||
|
|
||||||
Logger.Log
|
Logger.LogWarn
|
||||||
(
|
(
|
||||||
"The configuration file was not found. " +
|
"The configuration file was not found. " +
|
||||||
"A blank configuration file has been created for you at " +
|
"A blank configuration file has been created for you at " +
|
||||||
$"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}",
|
$"{Path.Combine(Environment.CurrentDirectory, ConfigFileName)}",
|
||||||
LoggerLevelConfig.Instance
|
"Config"
|
||||||
);
|
);
|
||||||
|
|
||||||
Environment.Exit(1);
|
Environment.Exit(1);
|
||||||
|
@ -73,7 +72,7 @@ public class ServerSettings
|
||||||
// Set up reloading
|
// Set up reloading
|
||||||
if (Instance.ConfigReloading)
|
if (Instance.ConfigReloading)
|
||||||
{
|
{
|
||||||
Logger.Log("Setting up config reloading...", LoggerLevelConfig.Instance);
|
Logger.LogInfo("Setting up config reloading...", "Config");
|
||||||
fileWatcher = new FileSystemWatcher
|
fileWatcher = new FileSystemWatcher
|
||||||
{
|
{
|
||||||
Path = Environment.CurrentDirectory,
|
Path = Environment.CurrentDirectory,
|
||||||
|
@ -90,8 +89,8 @@ public class ServerSettings
|
||||||
private static void onConfigChanged(object sender, FileSystemEventArgs e)
|
private static void onConfigChanged(object sender, FileSystemEventArgs e)
|
||||||
{
|
{
|
||||||
Debug.Assert(e.Name == ConfigFileName);
|
Debug.Assert(e.Name == ConfigFileName);
|
||||||
Logger.Log("Configuration file modified, reloading config.", LoggerLevelConfig.Instance);
|
Logger.LogInfo("Configuration file modified, reloading config.", "Config");
|
||||||
Logger.Log("Some changes may not apply, in which case may require a restart of Project Lighthouse.", LoggerLevelConfig.Instance);
|
Logger.LogWarn("Some changes may not apply, in which case may require a restart of Project Lighthouse.", "Config");
|
||||||
|
|
||||||
string configFile = File.ReadAllText(ConfigFileName);
|
string configFile = File.ReadAllText(ConfigFileName);
|
||||||
Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));
|
Instance = JsonSerializer.Deserialize<ServerSettings>(configFile) ?? throw new ArgumentNullException(nameof(ConfigFileName));
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#nullable enable
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
|
||||||
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
namespace LBPUnion.ProjectLighthouse.Types.Settings;
|
||||||
|
@ -20,7 +19,7 @@ public static class ServerStatics
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log(e.ToString(), LoggerLevelDatabase.Instance);
|
Logger.LogError(e.ToString(), "Database");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,6 @@ using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using Kettu;
|
|
||||||
using LBPUnion.ProjectLighthouse.Helpers;
|
using LBPUnion.ProjectLighthouse.Helpers;
|
||||||
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
using LBPUnion.ProjectLighthouse.Helpers.Extensions;
|
||||||
using LBPUnion.ProjectLighthouse.Logging;
|
using LBPUnion.ProjectLighthouse.Logging;
|
||||||
|
@ -93,12 +92,8 @@ public class NPTicket
|
||||||
|
|
||||||
reader.ReadUInt16BE(); // Ticket length, we don't care about this
|
reader.ReadUInt16BE(); // Ticket length, we don't care about this
|
||||||
|
|
||||||
#if DEBUG
|
|
||||||
SectionHeader bodyHeader = reader.ReadSectionHeader();
|
SectionHeader bodyHeader = reader.ReadSectionHeader();
|
||||||
Logger.Log($"bodyHeader.Type is {bodyHeader.Type}", LoggerLevelLogin.Instance);
|
Logger.LogDebug($"bodyHeader.Type is {bodyHeader.Type}", "Login");
|
||||||
#else
|
|
||||||
reader.ReadSectionHeader();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
switch (npTicket.ticketVersion)
|
switch (npTicket.ticketVersion)
|
||||||
{
|
{
|
||||||
|
@ -120,15 +115,13 @@ public class NPTicket
|
||||||
npTicket.titleId = npTicket.titleId.Substring(0, npTicket.titleId.Length - 3); // Trim _00 at the end
|
npTicket.titleId = npTicket.titleId.Substring(0, npTicket.titleId.Length - 3); // Trim _00 at the end
|
||||||
// Data now (hopefully): BCUS98245
|
// Data now (hopefully): BCUS98245
|
||||||
|
|
||||||
#if DEBUG
|
Logger.LogDebug($"titleId is {npTicket.titleId}", "Login");
|
||||||
Logger.Log($"titleId is {npTicket.titleId}", LoggerLevelLogin.Instance);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
npTicket.GameVersion = GameVersionHelper.FromTitleId(npTicket.titleId); // Finally, convert it to GameVersion
|
npTicket.GameVersion = GameVersionHelper.FromTitleId(npTicket.titleId); // Finally, convert it to GameVersion
|
||||||
|
|
||||||
if (npTicket.GameVersion == GameVersion.Unknown)
|
if (npTicket.GameVersion == GameVersion.Unknown)
|
||||||
{
|
{
|
||||||
Logger.Log($"Could not determine game version from title id {npTicket.titleId}", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"Could not determine game version from title id {npTicket.titleId}", "Login");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,45 +138,34 @@ public class NPTicket
|
||||||
|
|
||||||
if (npTicket.Platform == Platform.Unknown)
|
if (npTicket.Platform == Platform.Unknown)
|
||||||
{
|
{
|
||||||
Logger.Log($"Could not determine platform from IssuerId {npTicket.IssuerId} decimal", LoggerLevelLogin.Instance);
|
Logger.LogWarn($"Could not determine platform from IssuerId {npTicket.IssuerId} decimal", "Login");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
Logger.Log("npTicket data:", LoggerLevelLogin.Instance);
|
Logger.LogDebug("npTicket data:", "Login");
|
||||||
foreach (string line in JsonSerializer.Serialize(npTicket).Split('\n'))
|
Logger.LogDebug(JsonSerializer.Serialize(npTicket), "Login");
|
||||||
{
|
|
||||||
Logger.Log(line, LoggerLevelLogin.Instance);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return npTicket;
|
return npTicket;
|
||||||
}
|
}
|
||||||
catch(NotImplementedException)
|
catch(NotImplementedException)
|
||||||
{
|
{
|
||||||
Logger.Log($"The ticket version {npTicket.ticketVersion} is not implemented yet.", LoggerLevelLogin.Instance);
|
Logger.LogError($"The ticket version {npTicket.ticketVersion} is not implemented yet.", "Login");
|
||||||
Logger.Log
|
Logger.LogError
|
||||||
(
|
(
|
||||||
"Please let us know that this is a ticket version that is actually used on our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues !",
|
"Please let us know that this is a ticket version that is actually used on our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues !",
|
||||||
LoggerLevelLogin.Instance
|
"Login"
|
||||||
);
|
);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
{
|
{
|
||||||
Logger.Log("Failed to read npTicket!", LoggerLevelLogin.Instance);
|
Logger.LogError("Failed to read npTicket!", "Login");
|
||||||
Logger.Log("Either this is spam data, or the more likely that this is a bug.", LoggerLevelLogin.Instance);
|
Logger.LogError("Either this is spam data, or the more likely that this is a bug.", "Login");
|
||||||
Logger.Log
|
Logger.LogError("Please report the following exception to our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues!", "Login");
|
||||||
(
|
Logger.LogError(e.ToDetailedException(), "Login");
|
||||||
"Please report the following exception to our issue tracker at https://github.com/LBPUnion/project-lighthouse/issues!",
|
|
||||||
LoggerLevelLogin.Instance
|
|
||||||
);
|
|
||||||
|
|
||||||
foreach (string line in e.ToDetailedException().Split('\n'))
|
|
||||||
{
|
|
||||||
Logger.Log(line, LoggerLevelLogin.Instance);
|
|
||||||
}
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue