From c771a56971ba4f12988569af6db63d1bab95686e Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 10 Aug 2024 19:36:32 +0000 Subject: [PATCH] Added several request messages. Added redemptions. Added life TTS voice changes. A bunch of stuffs. --- .gitignore | 3 +- Requests/BanTTSUser.cs | 34 ---------- Requests/CreateTTSUser.cs | 15 +++-- Requests/CreateTTSVoice.cs | 10 ++- Requests/DeleteTTSVoice.cs | 10 ++- Requests/GetChatterIds.cs | 7 +-- Requests/GetDefaultTTSVoice.cs | 29 +++++++++ Requests/GetEmotes.cs | 6 +- Requests/GetEnabledTTSVoices.cs | 33 ++++++++++ Requests/GetPermissions.cs | 62 +++++++++++++++++++ Requests/GetRedeemableActions.cs | 40 ++++++++++++ Requests/GetRedemptions.cs | 39 ++++++++++++ Requests/GetTTSUsers.cs | 9 ++- Requests/GetTTSVoices.cs | 6 +- Requests/GetTTSWordFilters.cs | 9 +-- Requests/ServerRequestManager.cs | 14 ----- Requests/UpdateDefaultTTSVoice.cs | 36 +++++++++++ Requests/UpdateTTSUser.cs | 17 +++-- Requests/UpdateTTSVoice.cs | 10 ++- Requests/UpdateTTSVoiceState.cs | 11 +++- Server.cs | 36 +++++++---- ServerConfiguration.cs | 2 + Socket/Handlers/ChatterHandler.cs | 6 +- Socket/Handlers/EmoteDetailsHandler.cs | 4 +- Socket/Handlers/EmoteUsageHandler.cs | 6 +- Socket/Handlers/ErrorHandler.cs | 29 --------- Socket/Handlers/HeartbeatHandler.cs | 5 +- Socket/Handlers/HermesLoginHandler.cs | 84 +++++++++++++++++++------ Socket/Handlers/ISocketHandler.cs | 4 +- Socket/Handlers/LoggingHandler.cs | 44 +++++++++++++ Socket/Handlers/RequestHandler.cs | 10 ++- Socket/SocketHandlerManager.cs | 14 +---- Socket/SocketManager.cs | 26 ++++---- Socket/WebSocketUser.cs | 20 ++++-- SocketServer.csproj | 11 +--- Startup.cs | 86 ++++++++++++++++---------- 36 files changed, 552 insertions(+), 235 deletions(-) delete mode 100644 Requests/BanTTSUser.cs create mode 100644 Requests/GetDefaultTTSVoice.cs create mode 100644 Requests/GetEnabledTTSVoices.cs create mode 100644 Requests/GetPermissions.cs create mode 100644 Requests/GetRedeemableActions.cs create mode 100644 Requests/GetRedemptions.cs delete mode 100644 Requests/ServerRequestManager.cs create mode 100644 Requests/UpdateDefaultTTSVoice.cs delete mode 100644 Socket/Handlers/ErrorHandler.cs create mode 100644 Socket/Handlers/LoggingHandler.cs diff --git a/.gitignore b/.gitignore index 69f3b1a..320eef4 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ obj/ appsettings*.json server.config*.yml -logs/ \ No newline at end of file +logs/ +screenlog* \ No newline at end of file diff --git a/Requests/BanTTSUser.cs b/Requests/BanTTSUser.cs deleted file mode 100644 index 7be5743..0000000 --- a/Requests/BanTTSUser.cs +++ /dev/null @@ -1,34 +0,0 @@ -// using System.Text.Json; -// using HermesSocketLibrary.db; -// using HermesSocketLibrary.Requests; - -// namespace HermesSocketServer.Requests -// { -// public class BanTTSUser : IRequest -// { -// public string Name => "ban_tts_user"; -// private Database _database; -// private ILogger _logger; - -// public BanTTSUser(Database database, ILogger logger) -// { -// _database = database; -// _logger = logger; -// } - -// public async Task Grant(IDictionary data) -// { -// // if (long.TryParse(data["user"].ToString(), out long user)) -// // data["user"] = user; -// // if (data["broadcaster"] is JsonElement b) -// // data["broadcaster"] = b.ToString(); -// // if (data["voice"] is JsonElement v) -// // data["voice"] = v.ToString(); - -// // string sql = "UPDATE \"TtsChatVoice\" (\"broadcasterId\", \"chatterId\", \"ttsVoiceId\") VALUES (@broadcaster, @user, @voice)"; -// // var result = await _database.Execute(sql, data); -// // _logger.Information($"Selected a tts voice for {data["user"]} in channel {data["broadcaster"]}: {data["voice"]}"); -// return new RequestResult(1 == 1, null); -// } -// } -// } \ No newline at end of file diff --git a/Requests/CreateTTSUser.cs b/Requests/CreateTTSUser.cs index 51f9540..a4fdf58 100644 --- a/Requests/CreateTTSUser.cs +++ b/Requests/CreateTTSUser.cs @@ -17,8 +17,14 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + if (long.TryParse(data["chatter"].ToString(), out long chatter)) data["chatter"] = chatter; if (data["voice"] is JsonElement v) @@ -26,13 +32,12 @@ namespace HermesSocketServer.Requests data["user"] = sender; var check = await _database.ExecuteScalar("SELECT state FROM \"TtsVoiceState\" WHERE \"userId\" = @user AND \"ttsVoiceId\" = @voice", data) ?? false; - if (check is not bool state || !state){ + if (check is not bool state || !state) return new RequestResult(false, null); - } - + string sql = "INSERT INTO \"TtsChatVoice\" (\"userId\", \"chatterId\", \"ttsVoiceId\") VALUES (@user, @chatter, @voice)"; var result = await _database.Execute(sql, data); - _logger.Information($"Selected a tts voice for {data["chatter"]} in channel {data["user"]}: {data["voice"]}"); + _logger.Information($"Selected a tts voice [voice: {data["voice"]}] for user [chatter: {data["chatter"]}] in channel [channel: {data["user"]}]"); return new RequestResult(result == 1, null); } } diff --git a/Requests/CreateTTSVoice.cs b/Requests/CreateTTSVoice.cs index 9f54e29..2768a3d 100644 --- a/Requests/CreateTTSVoice.cs +++ b/Requests/CreateTTSVoice.cs @@ -20,8 +20,14 @@ namespace HermesSocketServer.Requests } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + string id = RandomString(25); data.Add("idd", id); @@ -30,7 +36,7 @@ namespace HermesSocketServer.Requests string sql = "INSERT INTO \"TtsVoice\" (id, name) VALUES (@idd, @voice)"; var result = await _database.Execute(sql, data); - _logger.Information($"Added a new voice: {data["voice"]} (id: {data["idd"]})"); + _logger.Information($"Added a new voice [voice: {data["voice"]}][voice id: {data["idd"]}]"); data.Remove("idd"); return new RequestResult(result == 1, id); diff --git a/Requests/DeleteTTSVoice.cs b/Requests/DeleteTTSVoice.cs index a61f259..87f7edf 100644 --- a/Requests/DeleteTTSVoice.cs +++ b/Requests/DeleteTTSVoice.cs @@ -17,14 +17,20 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + if (data["voice"] is JsonElement v) data["voice"] = v.ToString(); string sql = "DELETE FROM \"TtsVoice\" WHERE id = @voice"; var result = await _database.Execute(sql, data); - _logger.Information($"Deleted a voice by id: {data["voice"]}"); + _logger.Information($"Deleted a voice by id [voice id: {data["voice"]}]"); return new RequestResult(result == 1, null); } } diff --git a/Requests/GetChatterIds.cs b/Requests/GetChatterIds.cs index 7329f44..3728f55 100644 --- a/Requests/GetChatterIds.cs +++ b/Requests/GetChatterIds.cs @@ -1,4 +1,3 @@ -using System.Text.Json; using HermesSocketLibrary.db; using HermesSocketLibrary.Requests; using ILogger = Serilog.ILogger; @@ -17,12 +16,12 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { IList ids = new List(); string sql = $"SELECT id FROM \"Chatter\""; - await _database.Execute(sql, data, (r) => ids.Add(r.GetInt64(0))); - _logger.Information($"Fetched all chatters."); + await _database.Execute(sql, (IDictionary?) null, (r) => ids.Add(r.GetInt64(0))); + _logger.Information($"Fetched all chatters for channel [channel: {sender}]"); return new RequestResult(true, ids, notifyClientsOnAccount: false); } } diff --git a/Requests/GetDefaultTTSVoice.cs b/Requests/GetDefaultTTSVoice.cs new file mode 100644 index 0000000..7faa37d --- /dev/null +++ b/Requests/GetDefaultTTSVoice.cs @@ -0,0 +1,29 @@ +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class GetDefaultTTSVoice : IRequest + { + public string Name => "get_default_tts_voice"; + private Database _database; + private ILogger _logger; + + public GetDefaultTTSVoice(Database database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + var temp = new Dictionary() { { "user", sender } }; + + string sql = $"SELECT \"ttsDefaultVoice\" FROM \"User\" WHERE id = @user"; + string? value = (string?)await _database.ExecuteScalar(sql, temp); + _logger.Information($"Fetched the default TTS voice for channel [channel: {sender}]"); + return new RequestResult(true, value, notifyClientsOnAccount: false); + } + } +} \ No newline at end of file diff --git a/Requests/GetEmotes.cs b/Requests/GetEmotes.cs index 056014c..5f956a9 100644 --- a/Requests/GetEmotes.cs +++ b/Requests/GetEmotes.cs @@ -18,16 +18,16 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { IList emotes = new List(); string sql = $"SELECT id, name FROM \"Emote\""; - await _database.Execute(sql, data, (r) => emotes.Add(new EmoteInfo() + await _database.Execute(sql, (IDictionary?) null, (r) => emotes.Add(new EmoteInfo() { Id = r.GetString(0), Name = r.GetString(1) })); - _logger.Information($"Fetched all emotes."); + _logger.Information($"Fetched all emotes for channel [channel: {sender}]"); return new RequestResult(true, emotes, notifyClientsOnAccount: false); } } diff --git a/Requests/GetEnabledTTSVoices.cs b/Requests/GetEnabledTTSVoices.cs new file mode 100644 index 0000000..ade970f --- /dev/null +++ b/Requests/GetEnabledTTSVoices.cs @@ -0,0 +1,33 @@ +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class GetEnabledTTSVoices : IRequest + { + public string Name => "get_enabled_tts_voices"; + + private readonly Database _database; + private readonly ILogger _logger; + + public GetEnabledTTSVoices(Database database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + var temp = new Dictionary() { { "user", sender } }; + + var voices = new List(); + string sql = $"SELECT v.name FROM \"TtsVoiceState\" s " + + "INNER JOIN \"TtsVoice\" v ON s.\"ttsVoiceId\" = v.id " + + "WHERE \"userId\" = @user AND state = true"; + await _database.Execute(sql, temp, (r) => voices.Add(r.GetString(0))); + _logger.Information($"Fetched all enabled TTS voice for channel [channel: {sender}]"); + return new RequestResult(true, voices, notifyClientsOnAccount: false); + } + } +} \ No newline at end of file diff --git a/Requests/GetPermissions.cs b/Requests/GetPermissions.cs new file mode 100644 index 0000000..9fc6468 --- /dev/null +++ b/Requests/GetPermissions.cs @@ -0,0 +1,62 @@ +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using HermesSocketLibrary.Requests.Messages; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class GetPermissions : IRequest + { + public string Name => "get_permissions"; + + private readonly Database _database; + private readonly ILogger _logger; + + public GetPermissions(Database database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + var temp = new Dictionary() { { "user", sender } }; + + var groups = new List(); + string sql = $"SELECT id, name, priority FROM \"Group\" WHERE \"userId\" = @user"; + await _database.Execute(sql, temp, (r) => groups.Add(new Group() + { + Id = r.GetGuid(0).ToString("D"), + Name = r.GetString(1), + Priority = r.GetInt32(2) + })); + + var groupChatters = new List(); + sql = $"SELECT \"groupId\", \"chatterId\", \"chatterId\" FROM \"ChatterGroup\" WHERE \"userId\" = @user"; + await _database.Execute(sql, temp, (r) => groupChatters.Add(new GroupChatter() + { + GroupId = r.GetGuid(0).ToString("D"), + ChatterId = r.GetInt32(1) + })); + + var groupPermissions = new List(); + sql = $"SELECT id, \"groupId\", \"path\", \"allow\" FROM \"GroupPermission\" WHERE \"userId\" = @user"; + await _database.Execute(sql, temp, (r) => groupPermissions.Add(new GroupPermission() + { + Id = r.GetGuid(0).ToString("D"), + GroupId = r.GetGuid(1).ToString("D"), + Path = r.GetString(2), + Allow = r.GetBoolean(3) + })); + _logger.Information($"Fetched all redemptions for channel [channel: {sender}]"); + + var info = new GroupInfo() + { + Groups = groups, + GroupChatters = groupChatters, + GroupPermissions = groupPermissions + }; + return new RequestResult(true, info, notifyClientsOnAccount: false); + } + } +} \ No newline at end of file diff --git a/Requests/GetRedeemableActions.cs b/Requests/GetRedeemableActions.cs new file mode 100644 index 0000000..1a15780 --- /dev/null +++ b/Requests/GetRedeemableActions.cs @@ -0,0 +1,40 @@ +using System.Text.Json; +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using HermesSocketLibrary.Requests.Messages; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class GetRedeemableActions : IRequest + { + public string Name => "get_redeemable_actions"; + + private readonly JsonSerializerOptions _options; + private readonly Database _database; + private readonly ILogger _logger; + + public GetRedeemableActions(JsonSerializerOptions options, Database database, ILogger logger) + { + _options = options; + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + var temp = new Dictionary() { { "user", sender } }; + + var redemptions = new List(); + string sql = $"SELECT name, type, data FROM \"Action\" WHERE \"userId\" = @user"; + await _database.Execute(sql, temp, (r) => redemptions.Add(new RedeemableAction() + { + Name = r.GetString(0), + Type = r.GetString(1), + Data = JsonSerializer.Deserialize>(r.GetString(2), _options)! + })); + _logger.Information($"Fetched all chatters' selected tts voice for channel [channel: {sender}]"); + return new RequestResult(true, redemptions, notifyClientsOnAccount: false); + } + } +} \ No newline at end of file diff --git a/Requests/GetRedemptions.cs b/Requests/GetRedemptions.cs new file mode 100644 index 0000000..9f03982 --- /dev/null +++ b/Requests/GetRedemptions.cs @@ -0,0 +1,39 @@ +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using HermesSocketLibrary.Requests.Messages; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class GetRedemptions : IRequest + { + public string Name => "get_redemptions"; + + private readonly Database _database; + private readonly ILogger _logger; + + public GetRedemptions(Database database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + var temp = new Dictionary() { { "user", sender } }; + + var redemptions = new List(); + string sql = $"SELECT id, \"redemptionId\", \"actionName\", \"order\", state FROM \"Redemption\" WHERE \"userId\" = @user"; + await _database.Execute(sql, temp, (r) => redemptions.Add(new Redemption() + { + Id = r.GetGuid(0).ToString("D"), + RedemptionId = r.GetString(1), + ActionName = r.GetString(2), + Order = r.GetInt32(3), + State = r.GetBoolean(4) + })); + _logger.Information($"Fetched all redemptions for channel [channel: {sender}]"); + return new RequestResult(true, redemptions, notifyClientsOnAccount: false); + } + } +} \ No newline at end of file diff --git a/Requests/GetTTSUsers.cs b/Requests/GetTTSUsers.cs index 66ba217..09ee4d4 100644 --- a/Requests/GetTTSUsers.cs +++ b/Requests/GetTTSUsers.cs @@ -1,4 +1,3 @@ -using System.Text.Json; using HermesSocketLibrary.db; using HermesSocketLibrary.Requests; using ILogger = Serilog.ILogger; @@ -17,14 +16,14 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { - data["user"] = sender; + var temp = new Dictionary() { { "user", sender } }; IDictionary users = new Dictionary(); string sql = $"SELECT \"ttsVoiceId\", \"chatterId\" FROM \"TtsChatVoice\" WHERE \"userId\" = @user"; - await _database.Execute(sql, data, (r) => users.Add(r.GetInt64(1), r.GetString(0))); - _logger.Information($"Fetched all chatters' selected tts voice for channel {data["user"]}."); + await _database.Execute(sql, temp, (r) => users.Add(r.GetInt64(1), r.GetString(0))); + _logger.Information($"Fetched all chatters' selected tts voice for channel [channel: {sender}]"); return new RequestResult(true, users, notifyClientsOnAccount: false); } } diff --git a/Requests/GetTTSVoices.cs b/Requests/GetTTSVoices.cs index e9bdc8e..362c339 100644 --- a/Requests/GetTTSVoices.cs +++ b/Requests/GetTTSVoices.cs @@ -17,16 +17,16 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { IList voices = new List(); string sql = "SELECT id, name FROM \"TtsVoice\""; - await _database.Execute(sql, data, (r) => voices.Add(new VoiceDetails() + await _database.Execute(sql, (IDictionary?) null, (r) => voices.Add(new VoiceDetails() { Id = r.GetString(0), Name = r.GetString(1) })); - _logger.Information("Fetched all TTS voices."); + _logger.Information($"Fetched all TTS voices for channel [channel: {sender}]"); return new RequestResult(true, voices, notifyClientsOnAccount: false); } } diff --git a/Requests/GetTTSWordFilters.cs b/Requests/GetTTSWordFilters.cs index 076df4f..90baf03 100644 --- a/Requests/GetTTSWordFilters.cs +++ b/Requests/GetTTSWordFilters.cs @@ -1,4 +1,4 @@ -using System.Text.Json; +using System.Text.RegularExpressions; using HermesSocketLibrary.db; using HermesSocketLibrary.Requests; using HermesSocketLibrary.Requests.Messages; @@ -18,18 +18,19 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { - data["user"] = sender; + var temp = new Dictionary() { { "user", sender } }; IList filters = new List(); string sql = $"SELECT id, search, replace FROM \"TtsWordFilter\" WHERE \"userId\" = @user"; - await _database.Execute(sql, data, (r) => filters.Add(new TTSWordFilter() + await _database.Execute(sql, temp, (r) => filters.Add(new TTSWordFilter() { Id = r.GetString(0), Search = r.GetString(1), Replace = r.GetString(2) })); + _logger.Information($"Fetched all word filters for channel [channel: {sender}]"); return new RequestResult(true, filters, notifyClientsOnAccount: false); } } diff --git a/Requests/ServerRequestManager.cs b/Requests/ServerRequestManager.cs deleted file mode 100644 index c8c21e8..0000000 --- a/Requests/ServerRequestManager.cs +++ /dev/null @@ -1,14 +0,0 @@ -using HermesSocketLibrary.Requests; -using ILogger = Serilog.ILogger; - -namespace HermesSocketServer -{ - public class ServerRequestManager : RequestManager - { - public ServerRequestManager(IServiceProvider serviceProvider, ILogger logger) : base(serviceProvider, logger) - { - } - - protected override string AssemblyName => "SocketServer"; - } -} \ No newline at end of file diff --git a/Requests/UpdateDefaultTTSVoice.cs b/Requests/UpdateDefaultTTSVoice.cs new file mode 100644 index 0000000..ba9dc12 --- /dev/null +++ b/Requests/UpdateDefaultTTSVoice.cs @@ -0,0 +1,36 @@ +using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Requests +{ + public class UpdateDefaultTTSVoice : IRequest + { + public string Name => "update_default_tts_voice"; + private Database _database; + private ILogger _logger; + + public UpdateDefaultTTSVoice(Database database, ILogger logger) + { + _database = database; + _logger = logger; + } + + public async Task Grant(string sender, IDictionary? data) + { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + + data["user"] = data["user"].ToString(); + data["voice"] = data["voice"].ToString(); + + string sql = $"UPDATE \"User\" SET ttsDefaultVoice = @voice WHERE id = @user"; + await _database.Execute(sql, data); + _logger.Information($"Updated default TTS voice for channel [channel: {sender}][voice: {data["voice"]}]"); + return new RequestResult(true, null); + } + } +} \ No newline at end of file diff --git a/Requests/UpdateTTSUser.cs b/Requests/UpdateTTSUser.cs index 9cabdb4..e3613f9 100644 --- a/Requests/UpdateTTSUser.cs +++ b/Requests/UpdateTTSUser.cs @@ -8,17 +8,26 @@ namespace HermesSocketServer.Requests public class UpdateTTSUser : IRequest { public string Name => "update_tts_user"; + + private readonly ServerConfiguration _configuration; private readonly Database _database; private readonly ILogger _logger; - public UpdateTTSUser(Database database, ILogger logger) + public UpdateTTSUser(ServerConfiguration configuration, Database database, ILogger logger) { + _configuration = configuration; _database = database; _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + if (long.TryParse(data["chatter"].ToString(), out long chatterId)) data["chatter"] = chatterId; if (data["voice"] is JsonElement v) @@ -26,14 +35,14 @@ namespace HermesSocketServer.Requests data["user"] = sender; var check = await _database.ExecuteScalar("SELECT state FROM \"TtsVoiceState\" WHERE \"userId\" = @user AND \"ttsVoiceId\" = @voice", data) ?? false; - if (check is not bool state || !state) + if ((check is not bool state || !state) && chatterId != _configuration.OwnerId) { return new RequestResult(false, null); } string sql = "UPDATE \"TtsChatVoice\" SET \"ttsVoiceId\" = @voice WHERE \"userId\" = @user AND \"chatterId\" = @chatter"; var result = await _database.Execute(sql, data); - _logger.Information($"Updated {data["chatter"]}'s selected tts voice to {data["voice"]} in channel {data["user"]}."); + _logger.Information($"Updated chatter's [chatter: {data["chatter"]}] selected tts voice [voice: {data["voice"]}] in channel [channel: {sender}]"); return new RequestResult(result == 1, null); } } diff --git a/Requests/UpdateTTSVoice.cs b/Requests/UpdateTTSVoice.cs index 162157c..4672888 100644 --- a/Requests/UpdateTTSVoice.cs +++ b/Requests/UpdateTTSVoice.cs @@ -17,8 +17,14 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + if (data["voice"] is JsonElement v) data["voice"] = v.ToString(); if (data["voiceid"] is JsonElement id) @@ -26,7 +32,7 @@ namespace HermesSocketServer.Requests string sql = "UPDATE \"TtsVoice\" SET name = @voice WHERE id = @voiceid"; var result = await _database.Execute(sql, data); - _logger.Information($"Updated voice {data["voiceid"]}'s name to {data["voice"]}."); + _logger.Information($"Updated voice's [voice id: {data["voiceid"]}] name [new name: {data["voice"]}]"); return new RequestResult(result == 1, null); } } diff --git a/Requests/UpdateTTSVoiceState.cs b/Requests/UpdateTTSVoiceState.cs index 1b0d3e5..7791181 100644 --- a/Requests/UpdateTTSVoiceState.cs +++ b/Requests/UpdateTTSVoiceState.cs @@ -17,18 +17,23 @@ namespace HermesSocketServer.Requests _logger = logger; } - public async Task Grant(string sender, IDictionary data) + public async Task Grant(string sender, IDictionary? data) { + if (data == null) + { + _logger.Warning("Data received from request is null. Ignoring it."); + return new RequestResult(false, null); + } + if (data["voice"] is JsonElement voice) data["voice"] = voice.ToString(); if (data["state"] is JsonElement state) data["state"] = state.ToString() == "True"; data["user"] = sender; - //string sql = "UPDATE \"TtsVoiceState\" SET state = @state WHERE \"userId\" = @user AND \"ttsVoiceId\" = @voice"; string sql = "INSERT INTO \"TtsVoiceState\" (\"userId\", \"ttsVoiceId\", state) VALUES (@user, @voice, @state) ON CONFLICT (\"userId\", \"ttsVoiceId\") DO UPDATE SET state = @state"; var result = await _database.Execute(sql, data); - _logger.Information($"Updated voice {data["voice"]}'s state (from {data["user"]}) to {data["state"]}."); + _logger.Information($"Updated voice's [voice id: {data["voice"]}] state [new state: {data["state"]}][channel: {data["user"]}]"); return new RequestResult(result == 1, null); } } diff --git a/Server.cs b/Server.cs index ee52229..da27e8a 100644 --- a/Server.cs +++ b/Server.cs @@ -1,6 +1,7 @@ using System.Net.WebSockets; using System.Text; using System.Text.Json; +using CommonSocketLibrary.Common; using HermesSocketLibrary.Socket.Data; using HermesSocketServer.Socket; using ILogger = Serilog.ILogger; @@ -31,7 +32,7 @@ namespace HermesSocketLibrary public async Task Handle(WebSocketUser socket, HttpContext context) { - _logger.Information($"Socket connected [ip: {socket.IPAddress}]"); + _logger.Information($"Socket connected [ip: {socket.IPAddress}][uid: {socket.UID}]"); _sockets.Add(socket); var buffer = new byte[1024 * 8]; @@ -44,12 +45,12 @@ namespace HermesSocketLibrary break; string message = Encoding.UTF8.GetString(buffer, 0, result.Count).TrimEnd('\0'); - var obj = JsonSerializer.Deserialize(message, _options); - if (obj == null || !obj.OpCode.HasValue) + var obj = JsonSerializer.Deserialize(message, _options); + if (obj == null) continue; if (obj.OpCode != 0) - _logger.Information("Message: " + message); + _logger.Information($"rxm: {message} [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]"); /** * 0: Heartbeat @@ -57,11 +58,11 @@ namespace HermesSocketLibrary * 2: Login Ack TX * 3: Request RX * 4: Request Ack TX - * 5: Error RX/TX + * 5: Logging RX/TX */ if (obj.Data == null) { - await socket.Send(5, new ErrorMessage("Received no data in the message.")); + await socket.Send(5, new LoggingMessage("Received no data in the message.", HermesLoggingLevel.Warn)); continue; } else if (obj.OpCode == 0) @@ -71,7 +72,7 @@ namespace HermesSocketLibrary else if (obj.OpCode == 3) obj.Data = JsonSerializer.Deserialize(obj.Data.ToString(), _options); else if (obj.OpCode == 5) - obj.Data = JsonSerializer.Deserialize(obj.Data.ToString(), _options); + obj.Data = JsonSerializer.Deserialize(obj.Data.ToString(), _options); else if (obj.OpCode == 6) obj.Data = JsonSerializer.Deserialize(obj.Data.ToString(), _options); else if (obj.OpCode == 7) @@ -80,27 +81,36 @@ namespace HermesSocketLibrary obj.Data = JsonSerializer.Deserialize(obj.Data.ToString(), _options); else { - await socket.Send(5, new ErrorMessage("Received an invalid message: " + message)); + await socket.Send(5, new LoggingMessage("Received an invalid message: " + message, HermesLoggingLevel.Error)); continue; } - await _handlers.Execute(socket, obj.OpCode.Value, obj.Data); + await _handlers.Execute(socket, obj.OpCode, obj.Data); + } + catch (WebSocketException wse) + { + _logger.Error(wse, $"Error trying to process a socket message [code: {wse.ErrorCode}][ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]"); } catch (Exception e) { - _logger.Error(e, "Error trying to process a socket message"); + _logger.Error(e, $"Error trying to process a socket message [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]"); } } try { if (socket.Connected) - await socket.Close(socket.CloseStatus ?? WebSocketCloseStatus.NormalClosure, socket.CloseStatusDescription, CancellationToken.None); + await socket.Close(socket.CloseStatus ?? WebSocketCloseStatus.NormalClosure, "", CancellationToken.None); } - catch (Exception) + catch (Exception e) { + _logger.Information(e, $"Client failed to disconnect [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]"); + } + finally + { + socket.Dispose(); _sockets.Remove(socket); } - _logger.Information($"Client disconnected [username: {socket.Name}][id: {socket.Id}][ip: {socket.IPAddress}]"); + _logger.Information($"Client disconnected [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]"); } } } \ No newline at end of file diff --git a/ServerConfiguration.cs b/ServerConfiguration.cs index ac0e81c..f2c30ed 100644 --- a/ServerConfiguration.cs +++ b/ServerConfiguration.cs @@ -5,6 +5,8 @@ namespace HermesSocketServer public string Environment; public WebsocketServerConfiguration WebsocketServer; public DatabaseConfiguration Database; + public long OwnerId; + public string AdminPassword; } public class WebsocketServerConfiguration diff --git a/Socket/Handlers/ChatterHandler.cs b/Socket/Handlers/ChatterHandler.cs index 20a3682..745e619 100644 --- a/Socket/Handlers/ChatterHandler.cs +++ b/Socket/Handlers/ChatterHandler.cs @@ -6,7 +6,7 @@ namespace HermesSocketServer.Socket.Handlers { public class ChatterHandler : ISocketHandler { - public int OpCode { get; } = 6; + public int OperationCode { get; } = 6; private readonly Database _database; private readonly HashSet _chatters; private readonly ChatterMessage[] _array; @@ -27,7 +27,7 @@ namespace HermesSocketServer.Socket.Handlers public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) { - if (message is not ChatterMessage data) + if (message is not ChatterMessage data || sender.Id == null) return; lock (_lock) @@ -45,7 +45,7 @@ namespace HermesSocketServer.Socket.Handlers try { - string sql = "INSERT INTO \"Chatter\" (id, name) VALUES (@idd, @name)"; + string sql = "INSERT INTO \"Chatter\" (id, name) VALUES (@idd, @name) ON CONFLICT (id) DO UPDATE SET name = @name"; await _database.Execute(sql, new Dictionary() { { "idd", data.Id }, { "name", data.Name } }); } catch (Exception e) diff --git a/Socket/Handlers/EmoteDetailsHandler.cs b/Socket/Handlers/EmoteDetailsHandler.cs index 45231df..87c1707 100644 --- a/Socket/Handlers/EmoteDetailsHandler.cs +++ b/Socket/Handlers/EmoteDetailsHandler.cs @@ -7,7 +7,7 @@ namespace HermesSocketServer.Socket.Handlers { public class EmoteDetailsHandler : ISocketHandler { - public int OpCode { get; } = 7; + public int OperationCode { get; } = 7; private readonly Database _database; private readonly HashSet _emotes; private readonly ILogger _logger; @@ -23,7 +23,7 @@ namespace HermesSocketServer.Socket.Handlers public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) { - if (message is not EmoteDetailsMessage data) + if (message is not EmoteDetailsMessage data || sender.Id == null) return; if (data.Emotes == null) diff --git a/Socket/Handlers/EmoteUsageHandler.cs b/Socket/Handlers/EmoteUsageHandler.cs index 0d53a94..3f36b79 100644 --- a/Socket/Handlers/EmoteUsageHandler.cs +++ b/Socket/Handlers/EmoteUsageHandler.cs @@ -7,7 +7,7 @@ namespace HermesSocketServer.Socket.Handlers { public class EmoteUsageHandler : ISocketHandler { - public int OpCode { get; } = 8; + public int OperationCode { get; } = 8; private readonly Database _database; private readonly HashSet _history; @@ -28,7 +28,7 @@ namespace HermesSocketServer.Socket.Handlers public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) { - if (message is not EmoteUsageMessage data) + if (message is not EmoteUsageMessage data || sender.Id == null) return; lock (_logger) @@ -69,7 +69,7 @@ namespace HermesSocketServer.Socket.Handlers } } - _logger.Information($"Tracked {rows} emote(s) to history."); + _logger.Debug($"Tracked {rows} emote(s) to history."); } } } \ No newline at end of file diff --git a/Socket/Handlers/ErrorHandler.cs b/Socket/Handlers/ErrorHandler.cs deleted file mode 100644 index d930757..0000000 --- a/Socket/Handlers/ErrorHandler.cs +++ /dev/null @@ -1,29 +0,0 @@ -using HermesSocketLibrary.Socket.Data; -using ILogger = Serilog.ILogger; - -namespace HermesSocketServer.Socket.Handlers -{ - public class ErrorHandler : ISocketHandler - { - public int OpCode { get; } = 0; - - private ILogger _logger; - - public ErrorHandler(ILogger logger) - { - _logger = logger; - } - - - public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) - { - if (message is not ErrorMessage data) - return; - - if (data.Exception == null) - _logger.Error(data.Message); - else - _logger.Error(data.Exception, data.Message); - } - } -} \ No newline at end of file diff --git a/Socket/Handlers/HeartbeatHandler.cs b/Socket/Handlers/HeartbeatHandler.cs index 91ccabe..80b2a5a 100644 --- a/Socket/Handlers/HeartbeatHandler.cs +++ b/Socket/Handlers/HeartbeatHandler.cs @@ -5,7 +5,7 @@ namespace HermesSocketServer.Socket.Handlers { public class HeartbeatHandler : ISocketHandler { - public int OpCode { get; } = 0; + public int OperationCode { get; } = 0; private ILogger _logger; @@ -23,11 +23,14 @@ namespace HermesSocketServer.Socket.Handlers _logger.Verbose($"Received heartbeat from socket [ip: {sender.IPAddress}]."); if (data.Respond) + { + sender.LastHearbeatSent = DateTime.UtcNow; await sender.Send(0, new HeartbeatMessage() { DateTime = DateTime.UtcNow, Respond = false }); + } } } } \ No newline at end of file diff --git a/Socket/Handlers/HermesLoginHandler.cs b/Socket/Handlers/HermesLoginHandler.cs index f930b83..b692bb7 100644 --- a/Socket/Handlers/HermesLoginHandler.cs +++ b/Socket/Handlers/HermesLoginHandler.cs @@ -1,4 +1,5 @@ using HermesSocketLibrary.db; +using HermesSocketLibrary.Requests.Messages; using HermesSocketLibrary.Socket.Data; using ILogger = Serilog.ILogger; @@ -6,15 +7,17 @@ namespace HermesSocketServer.Socket.Handlers { public class HermesLoginHandler : ISocketHandler { - public int OpCode { get; } = 1; + public int OperationCode { get; } = 1; + private readonly ServerConfiguration _configuration; private readonly Database _database; private readonly HermesSocketManager _sockets; private readonly ILogger _logger; private readonly object _lock; - public HermesLoginHandler(Database database, HermesSocketManager sockets, ILogger logger) + public HermesLoginHandler(ServerConfiguration configuration, Database database, HermesSocketManager sockets, ILogger logger) { + _configuration = configuration; _database = database; _sockets = sockets; _logger = logger; @@ -36,48 +39,89 @@ namespace HermesSocketServer.Socket.Handlers if (userId == null) return; - var recipients = _sockets.GetSockets(userId).ToList(); - lock (_lock) { if (sender.Id != null) return; sender.Id = userId; + sender.ApiKey = data.ApiKey; + sender.WebLogin = data.WebLogin; } - string sql2 = "select \"name\" from \"User\" where id = @user"; - var result2 = await _database.ExecuteScalar(sql2, new Dictionary() { { "user", userId } }); - string? name = result2?.ToString(); - - if (string.IsNullOrEmpty(name)) - return; - - sender.Name = name; - - await sender.Send(2, new LoginAckMessage() + string sql2 = "select name, role from \"User\" where id = @user"; + await _database.Execute(sql2, new Dictionary() { { "user", userId } }, sql => { - UserId = userId + sender.Name = sql.GetString(0); + sender.Admin = sql.GetString(1) == "ADMIN"; }); + if (string.IsNullOrEmpty(sender.Name)) + { + _logger.Error($"Could not find username using the user id [user id: {userId}][api key: {data.ApiKey}]"); + return; + } + var ack = new LoginAckMessage() { - AnotherClient = true, - UserId = userId + UserId = userId, + OwnerId = _configuration.OwnerId, + Admin = sender.Admin, + WebLogin = data.WebLogin, }; + var connections = new List(); + string sql3 = "select \"name\", \"type\", \"clientId\", \"accessToken\", \"grantType\", \"scope\", \"expiresAt\", \"default\" from \"Connection\" where \"userId\" = @user"; + await _database.Execute(sql3, new Dictionary() { { "user", userId } }, sql => + connections.Add(new Connection() + { + Name = sql.GetString(0), + Type = sql.GetString(1), + ClientId = sql.GetString(2), + AccessToken = sql.GetString(3), + GrantType = sql.GetString(4), + Scope = sql.GetString(5), + ExpiresIn = sql.GetDateTime(6), + Default = sql.GetBoolean(7) + }) + ); + ack.Connections = connections.ToArray(); + + IList voices = new List(); + string sql4 = "SELECT id, name FROM \"TtsVoice\""; + await _database.Execute(sql4, (IDictionary?) null, (r) => voices.Add(new VoiceDetails() + { + Id = r.GetString(0), + Name = r.GetString(1) + })); + ack.TTSVoicesAvailable = voices.ToDictionary(e => e.Id, e => e.Name); + + await sender.Send(2, ack); + + string version = data.MajorVersion == null ? "unknown" : $"{data.MajorVersion}.{data.MinorVersion}"; + _logger.Information($"Hermes client logged in {(sender.Admin ? "as administrator " : "")}[name: {sender.Name}][id: {userId}][ip: {sender.IPAddress}][version: {version}][web: {data.WebLogin}]"); + + ack = new LoginAckMessage() + { + AnotherClient = true, + UserId = userId, + OwnerId = _configuration.OwnerId, + WebLogin = data.WebLogin + }; + + var recipients = _sockets.GetSockets(userId).ToList().Where(s => s.UID != sender.UID); + var tasks = new List(); foreach (var socket in recipients) { try { - await socket.Send(2, ack); + tasks.Add(socket.Send(2, ack)); } catch (Exception) { } } - - _logger.Information($"Hermes client logged in [name: {name}][id: {userId}][ip: {sender.IPAddress}]"); + await Task.WhenAll(tasks); } } } \ No newline at end of file diff --git a/Socket/Handlers/ISocketHandler.cs b/Socket/Handlers/ISocketHandler.cs index 349694d..33046e6 100644 --- a/Socket/Handlers/ISocketHandler.cs +++ b/Socket/Handlers/ISocketHandler.cs @@ -1,10 +1,8 @@ -using System.Net.WebSockets; - namespace HermesSocketServer.Socket.Handlers { public interface ISocketHandler { - int OpCode { get; } + int OperationCode { get; } Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets); } } \ No newline at end of file diff --git a/Socket/Handlers/LoggingHandler.cs b/Socket/Handlers/LoggingHandler.cs new file mode 100644 index 0000000..ddce6e5 --- /dev/null +++ b/Socket/Handlers/LoggingHandler.cs @@ -0,0 +1,44 @@ +using HermesSocketLibrary.Socket.Data; +using ILogger = Serilog.ILogger; + +namespace HermesSocketServer.Socket.Handlers +{ + public class LoggingHandler : ISocketHandler + { + public int OperationCode { get; } = 5; + + private ILogger _logger; + + public LoggingHandler(ILogger logger) + { + _logger = logger; + } + + + public async Task Execute(WebSocketUser sender, T data, HermesSocketManager sockets) + { + if (data is not LoggingMessage message || sender.Id == null) + return; + + Action logging; + if (message.Level == HermesLoggingLevel.Trace) + logging = _logger.Verbose; + else if (message.Level == HermesLoggingLevel.Debug) + logging = _logger.Debug; + else if (message.Level == HermesLoggingLevel.Info) + logging = _logger.Information; + else if (message.Level == HermesLoggingLevel.Warn) + logging = _logger.Warning; + else if (message.Level == HermesLoggingLevel.Error) + logging = _logger.Error; + else if (message.Level == HermesLoggingLevel.Critical) + logging = _logger.Fatal; + else { + _logger.Warning("Failed to receive a logging level from client."); + return; + } + + logging.Invoke(message.Exception, message.Message + $" [ip: {sender.IPAddress}][id: {sender.Id}][name: {sender.Name}][token: {sender.ApiKey}][uid: {sender.UID}]"); + } + } +} \ No newline at end of file diff --git a/Socket/Handlers/RequestHandler.cs b/Socket/Handlers/RequestHandler.cs index 177985d..d720af5 100644 --- a/Socket/Handlers/RequestHandler.cs +++ b/Socket/Handlers/RequestHandler.cs @@ -6,12 +6,12 @@ namespace HermesSocketServer.Socket.Handlers { public class RequestHandler : ISocketHandler { - public int OpCode { get; } = 3; - private readonly RequestManager _requests; + public int OperationCode { get; } = 3; + private readonly IRequestManager _requests; private readonly HermesSocketManager _sockets; private readonly ILogger _logger; - public RequestHandler(RequestManager requests, HermesSocketManager sockets, ILogger logger) + public RequestHandler(IRequestManager requests, HermesSocketManager sockets, ILogger logger) { _requests = requests; _sockets = sockets; @@ -21,9 +21,7 @@ namespace HermesSocketServer.Socket.Handlers public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) { - if (sender.Id == null) - return; - if (message is not RequestMessage data) + if (message is not RequestMessage data || sender.Id == null) return; RequestResult? result = null; diff --git a/Socket/SocketHandlerManager.cs b/Socket/SocketHandlerManager.cs index 672826e..f0198e5 100644 --- a/Socket/SocketHandlerManager.cs +++ b/Socket/SocketHandlerManager.cs @@ -1,4 +1,3 @@ -using System.Text.Json; using CommonSocketLibrary.Abstract; using HermesSocketServer.Socket.Handlers; using ILogger = Serilog.ILogger; @@ -8,22 +7,15 @@ namespace HermesSocketServer.Socket public class SocketHandlerManager : HandlerManager { private readonly HermesSocketManager _sockets; - private readonly IServiceProvider _serviceProvider; - public SocketHandlerManager(HermesSocketManager sockets, IServiceProvider serviceProvider, ILogger logger) + public SocketHandlerManager(HermesSocketManager sockets, IEnumerable handlers, ILogger logger) : base(logger) { _sockets = sockets; - _serviceProvider = serviceProvider; - Add(0, _serviceProvider.GetRequiredKeyedService("hermes-heartbeat")); - Add(1, _serviceProvider.GetRequiredKeyedService("hermes-hermeslogin")); - Add(3, _serviceProvider.GetRequiredKeyedService("hermes-request")); - Add(5, _serviceProvider.GetRequiredKeyedService("hermes-error")); - Add(6, _serviceProvider.GetRequiredKeyedService("hermes-chatter")); - Add(7, _serviceProvider.GetRequiredKeyedService("hermes-emotedetails")); - Add(8, _serviceProvider.GetRequiredKeyedService("hermes-emoteusage")); + foreach (ISocketHandler handler in handlers) + Add(handler.OperationCode, handler); } protected override async Task Execute(WebSocketUser sender, ISocketHandler handler, T value) diff --git a/Socket/SocketManager.cs b/Socket/SocketManager.cs index 3b17222..2441927 100644 --- a/Socket/SocketManager.cs +++ b/Socket/SocketManager.cs @@ -1,4 +1,3 @@ -using System.Net.WebSockets; using System.Timers; using HermesSocketLibrary.Socket.Data; using ILogger = Serilog.ILogger; @@ -16,7 +15,6 @@ namespace HermesSocketServer.Socket { _sockets = new List(); _timer = new System.Timers.Timer(TimeSpan.FromSeconds(1)); - _timer.AutoReset = true; _timer.Elapsed += async (sender, e) => await HandleHeartbeats(e); _timer.Enabled = true; _logger = logger; @@ -66,25 +64,27 @@ namespace HermesSocketServer.Socket try { socket.LastHearbeatSent = DateTime.UtcNow; - await socket.Send(0, new HeartbeatMessage() { DateTime = socket.LastHearbeatSent }); + await socket.Send(0, new HeartbeatMessage() { DateTime = signalTime, Respond = true }); + } + catch (Exception) + { + } + } + else if (signalTime - socket.LastHeartbeatReceived > TimeSpan.FromSeconds(60)) + { + _logger.Debug($"Closing socket [ip: {socket.IPAddress}] for not responding for 2 minutes."); + try + { + socket.Dispose(); } catch (Exception) { - _logger.Warning($"Failed to send the heartbeat to socket [ip: {socket.IPAddress}]."); - await socket.Close(WebSocketCloseStatus.NormalClosure, "Failed to send a heartbeat message.", CancellationToken.None); } finally { - if (!socket.Connected) - _sockets.RemoveAt(i--); + _sockets.RemoveAt(i--); } } - else if (signalTime - socket.LastHeartbeatReceived > TimeSpan.FromSeconds(120)) - { - _logger.Debug($"Closing socket [ip: {socket.IPAddress}] for not responding for 2 minutes."); - await socket.Close(WebSocketCloseStatus.NormalClosure, "No heartbeat received.", CancellationToken.None); - _sockets.RemoveAt(i--); - } } } } diff --git a/Socket/WebSocketUser.cs b/Socket/WebSocketUser.cs index c1bc5f5..7a32e23 100644 --- a/Socket/WebSocketUser.cs +++ b/Socket/WebSocketUser.cs @@ -2,12 +2,12 @@ using System.Net; using System.Net.WebSockets; using System.Text; using System.Text.Json; -using HermesSocketLibrary.Socket.Data; +using CommonSocketLibrary.Common; using ILogger = Serilog.ILogger; namespace HermesSocketServer.Socket { - public class WebSocketUser + public class WebSocketUser : IDisposable { private readonly WebSocket _socket; private readonly JsonSerializerOptions _options; @@ -22,8 +22,12 @@ namespace HermesSocketServer.Socket public WebSocketState State { get => _socket.State; } public IPAddress? IPAddress { get => _ipAddress; } public bool Connected { get => _connected; } + public string UID { get; } + public string ApiKey { get; set; } public string? Id { get; set; } public string? Name { get; set; } + public bool Admin { get; set; } + public bool WebLogin { get; set; } public DateTime LastHeartbeatReceived { get; set; } public DateTime LastHearbeatSent { get; set; } public CancellationToken Token { get => _cts.Token; } @@ -36,7 +40,10 @@ namespace HermesSocketServer.Socket _options = options; _connected = true; _logger = logger; + Admin = false; + WebLogin = false; _cts = new CancellationTokenSource(); + UID = Guid.NewGuid().ToString("D"); LastHeartbeatReceived = DateTime.UtcNow; } @@ -65,6 +72,11 @@ namespace HermesSocketServer.Socket } } + public void Dispose() + { + _socket.Dispose(); + } + public async Task Send(int opcode, Data data) { var message = GenerateMessage(opcode, data); @@ -101,9 +113,9 @@ namespace HermesSocketServer.Socket return null; } - private SocketMessage GenerateMessage(int opcode, Data data) + private WebSocketMessage GenerateMessage(int opcode, Data data) { - return new SocketMessage() + return new WebSocketMessage() { OpCode = opcode, Data = data diff --git a/SocketServer.csproj b/SocketServer.csproj index cd851aa..d0a0451 100644 --- a/SocketServer.csproj +++ b/SocketServer.csproj @@ -11,18 +11,13 @@ - - - - + - - - - + + diff --git a/Startup.cs b/Startup.cs index af8a441..f75437b 100644 --- a/Startup.cs +++ b/Startup.cs @@ -12,17 +12,19 @@ using Serilog; using Serilog.Events; using YamlDotNet.Serialization; using YamlDotNet.Serialization.NamingConventions; +using Microsoft.AspNetCore.Connections; -var deserializer = new DeserializerBuilder() +var yamlDeserializer = new DeserializerBuilder() .WithNamingConvention(HyphenatedNamingConvention.Instance) .Build(); var configFileName = "server.config.yml"; -if (File.Exists("server.config." + Environment.GetEnvironmentVariable("TTS_ENV").ToLower() + ".yml")) - configFileName = "server.config." + Environment.GetEnvironmentVariable("TTS_ENV").ToLower() + ".yml"; +var environment = Environment.GetEnvironmentVariable("TTS_ENV")!.ToLower(); +if (File.Exists("server.config." + environment + ".yml")) + configFileName = "server.config." + environment + ".yml"; var configContent = File.ReadAllText(configFileName); -var configuration = deserializer.Deserialize(configContent); +var configuration = yamlDeserializer.Deserialize(configContent); if (configuration.Environment.ToUpper() != "QA" && configuration.Environment.ToUpper() != "PROD") throw new Exception("Invalid environment set."); @@ -36,12 +38,20 @@ builder.Services.Configure(options => }); builder.WebHost.UseUrls($"http://{configuration.WebsocketServer.Host}:{configuration.WebsocketServer.Port}"); -var logger = new LoggerConfiguration() - .MinimumLevel.Debug() - .Enrich.FromLogContext() - .WriteTo.File("logs/log.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7) - .WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information) - .CreateLogger(); +var loggerConfiguration = new LoggerConfiguration(); +if (configuration.Environment.ToUpper() == "QA") + loggerConfiguration.MinimumLevel.Verbose(); +else + loggerConfiguration.MinimumLevel.Debug(); + +loggerConfiguration.Enrich.FromLogContext() + .WriteTo.File($"logs/{configuration.Environment.ToUpper()}/serverlog-.log", rollingInterval: RollingInterval.Day, retainedFileCountLimit: 7); +if (configuration.Environment.ToUpper() == "QA") + loggerConfiguration.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Debug); +else + loggerConfiguration.WriteTo.Console(restrictedToMinimumLevel: LogEventLevel.Information); + +var logger = loggerConfiguration.CreateLogger(); builder.Host.UseSerilog(logger); builder.Logging.AddSerilog(logger); @@ -54,32 +64,37 @@ s.AddSingleton(); // Socket message handlers s.AddSingleton(logger); -s.AddKeyedSingleton("hermes-heartbeat"); -s.AddKeyedSingleton("hermes-hermeslogin"); -s.AddKeyedSingleton("hermes-request"); -s.AddKeyedSingleton("hermes-error"); -s.AddKeyedSingleton("hermes-chatter"); -s.AddKeyedSingleton("hermes-emotedetails"); -s.AddKeyedSingleton("hermes-emoteusage"); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); // Request handlers -s.AddKeyedSingleton("BanTTSUser"); -s.AddKeyedSingleton("GetTTSUsers"); -s.AddKeyedSingleton("GetTTSVoices"); -s.AddKeyedSingleton("GetTTSWordFilters"); -s.AddKeyedSingleton("CreateTTSUser"); -s.AddKeyedSingleton("CreateTTSVoice"); -s.AddKeyedSingleton("DeleteTTSVoice"); -s.AddKeyedSingleton("UpdateTTSUser"); -s.AddKeyedSingleton("UpdateTTSVoice"); -s.AddKeyedSingleton("GetChatterIds"); -s.AddKeyedSingleton("GetEmotes"); -s.AddKeyedSingleton("UpdateTTSVoiceState"); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); +s.AddSingleton(); s.AddSingleton(); s.AddSingleton(); -s.AddSingleton(); -s.AddSingleton(new JsonSerializerOptions() +s.AddSingleton(); +s.AddSingleton(new JsonSerializerOptions() { PropertyNameCaseInsensitive = false, PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower @@ -89,10 +104,15 @@ s.AddSingleton(); var app = builder.Build(); app.UseForwardedHeaders(); app.UseSerilogRequestLogging(); -app.UseWebSockets(new WebSocketOptions() + +var wsOptions = new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(30) -}); +}; +// wsOptions.AllowedOrigins.Add("wss://tomtospeech.com"); +//wsOptions.AllowedOrigins.Add("ws.tomtospeech.com"); +//wsOptions.AllowedOrigins.Add("hermes-ws.goblincaves.com"); +app.UseWebSockets(wsOptions); var options = app.Services.GetRequiredService(); var server = app.Services.GetRequiredService();