using HermesSocketLibrary.db; using HermesSocketLibrary.Requests.Messages; using HermesSocketLibrary.Socket.Data; using HermesSocketServer.Services; using HermesSocketServer.Store; using ILogger = Serilog.ILogger; namespace HermesSocketServer.Socket.Handlers { public class HermesLoginHandler : ISocketHandler { public int OperationCode { get; } = 1; private readonly ChannelManager _manager; private readonly IStore _voices; private readonly ServerConfiguration _configuration; private readonly Database _database; private readonly HermesSocketManager _sockets; private readonly ILogger _logger; private readonly object _lock; public HermesLoginHandler(ChannelManager manager, IStore voices, ServerConfiguration configuration, Database database, HermesSocketManager sockets, ILogger logger) { _manager = manager; _voices = voices; _configuration = configuration; _database = database; _sockets = sockets; _logger = logger; _lock = new object(); } public async Task Execute(WebSocketUser sender, T message, HermesSocketManager sockets) { if (message is not HermesLoginMessage data || data == null || data.ApiKey == null) return; if (sender.Id != null) return; string sql = "select \"userId\" from \"ApiKey\" where id = @key"; var result = await _database.ExecuteScalar(sql, new Dictionary() { { "key", data.ApiKey } }); string? userId = result?.ToString(); if (userId == null) return; lock (_lock) { if (sender.Id != null) return; sender.Id = userId; sender.ApiKey = data.ApiKey; sender.WebLogin = data.WebLogin; } var channel = _manager.Get(userId); if (channel == null) { channel = await _manager.Add(userId); if (channel == null) return; } sender.Name = channel.User.Name; sender.Admin = channel.User.Role == "ADMIN"; if (string.IsNullOrEmpty(sender.Name)) { _logger.Error($"Could not find username for a certain user [user id: {userId}][api key: {data.ApiKey}]"); return; } if (string.IsNullOrEmpty(channel.User.DefaultVoice)) _logger.Warning($"No default voice was set for an user [user id: {userId}][api key: {data.ApiKey}]"); sql = "select \"providerAccountId\" from \"Account\" where \"userId\" = @user and provider = @provider"; var result2 = await _database.ExecuteScalar(sql, new Dictionary() { { "user", userId }, { "provider", "twitch" } }); var providerId = result2?.ToString(); if (providerId == null) { _logger.Warning($"Could not find the Provider Account Id [user id: {userId}][provider: twitch]"); return; } var ack = new LoginAckMessage() { UserId = userId, ProviderAccountId = providerId, SessionId = sender.UID, UserName = channel.User.Name, OwnerId = _configuration.Tts.OwnerId, Admin = sender.Admin, WebLogin = data.WebLogin, WordFilters = channel.Filters.Get().Values, DefaultTTSVoice = channel.User.DefaultVoice ?? _configuration.Tts.DefaultTtsVoice, TTSVoicesAvailable = _voices.Get().ToDictionary(v => v.Key, v => v.Value.Name), }; var userIdDict = new Dictionary() { { "user", userId } }; ack.Connections = new List(); string sql3 = "select \"name\", \"type\", \"clientId\", \"accessToken\", \"grantType\", \"scope\", \"expiresAt\", \"default\" from \"Connection\" where \"userId\" = @user"; await _database.Execute(sql3, userIdDict, sql => ack.Connections.Add(new Connection() { UserId = channel.Id, Name = sql.GetString(0), Type = sql.GetString(1), ClientId = sql.GetString(2), AccessToken = sql.GetString(3), GrantType = sql.GetString(4), Scope = sql.GetString(5), ExpiresAt = sql.GetDateTime(6), Default = sql.GetBoolean(7) }) ); ack.EnabledTTSVoices = new List(); string sql5 = $"SELECT v.name FROM \"TtsVoiceState\" s " + "INNER JOIN \"TtsVoice\" v ON s.\"ttsVoiceId\" = v.id " + "WHERE \"userId\" = @user AND state = true"; await _database.Execute(sql5, userIdDict, (r) => ack.EnabledTTSVoices.Add(r.GetString(0))); 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.Tts.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 { tasks.Add(socket.Send(2, ack)); } catch (Exception) { } } await Task.WhenAll(tasks); } } }