Compare commits
7 Commits
39c6442126
...
3f3ba63554
Author | SHA1 | Date | |
---|---|---|---|
3f3ba63554 | |||
6a5c24dc2c | |||
1f7eb7f402 | |||
be87080c49 | |||
0a2392b957 | |||
88104484f6 | |||
c082054606 |
@ -1,6 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using HermesSocketLibrary.db;
|
using HermesSocketLibrary.db;
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -9,11 +10,13 @@ namespace HermesSocketServer.Requests
|
|||||||
{
|
{
|
||||||
public string Name => "create_tts_user";
|
public string Name => "create_tts_user";
|
||||||
private Database _database;
|
private Database _database;
|
||||||
|
private ChatterStore _chatters;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
public CreateTTSUser(Database database, ILogger logger)
|
public CreateTTSUser(ChatterStore chatters, Database database, ILogger logger)
|
||||||
{
|
{
|
||||||
_database = database;
|
_database = database;
|
||||||
|
_chatters = chatters;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,20 +28,25 @@ namespace HermesSocketServer.Requests
|
|||||||
return new RequestResult(false, null);
|
return new RequestResult(false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (long.TryParse(data["chatter"].ToString(), out long chatter))
|
if (long.TryParse(data["chatter"].ToString(), out long chatterId))
|
||||||
data["chatter"] = chatter;
|
data["chatter"] = chatterId;
|
||||||
|
else
|
||||||
|
return new RequestResult(false, "Invalid Twitch user id");
|
||||||
|
|
||||||
if (data["voice"] is JsonElement v)
|
if (data["voice"] is JsonElement v)
|
||||||
data["voice"] = v.ToString();
|
data["voice"] = v.ToString();
|
||||||
|
else
|
||||||
|
return new RequestResult(false, "Invalid voice id");
|
||||||
|
|
||||||
data["user"] = sender;
|
data["user"] = sender;
|
||||||
|
|
||||||
var check = await _database.ExecuteScalar("SELECT state FROM \"TtsVoiceState\" WHERE \"userId\" = @user AND \"ttsVoiceId\" = @voice", data) ?? false;
|
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);
|
return new RequestResult(false, "Voice is disabled on this channel.");
|
||||||
|
|
||||||
string sql = "INSERT INTO \"TtsChatVoice\" (\"userId\", \"chatterId\", \"ttsVoiceId\") VALUES (@user, @chatter, @voice)";
|
_chatters.Set(sender, chatterId, data["voice"].ToString());
|
||||||
var result = await _database.Execute(sql, data);
|
|
||||||
_logger.Information($"Selected a tts voice [voice: {data["voice"]}] for user [chatter: {data["chatter"]}] in channel [channel: {data["user"]}]");
|
_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);
|
return new RequestResult(true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using HermesSocketLibrary.db;
|
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -8,13 +8,13 @@ namespace HermesSocketServer.Requests
|
|||||||
public class CreateTTSVoice : IRequest
|
public class CreateTTSVoice : IRequest
|
||||||
{
|
{
|
||||||
public string Name => "create_tts_voice";
|
public string Name => "create_tts_voice";
|
||||||
private Database _database;
|
private IStore<string, string> _voices;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
private Random _random;
|
private Random _random;
|
||||||
|
|
||||||
public CreateTTSVoice(Database database, ILogger logger)
|
public CreateTTSVoice(VoiceStore voices, ILogger logger)
|
||||||
{
|
{
|
||||||
_database = database;
|
_voices = voices;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_random = new Random();
|
_random = new Random();
|
||||||
}
|
}
|
||||||
@ -28,18 +28,17 @@ namespace HermesSocketServer.Requests
|
|||||||
return new RequestResult(false, null);
|
return new RequestResult(false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
string id = RandomString(25);
|
|
||||||
data.Add("idd", id);
|
|
||||||
|
|
||||||
if (data["voice"] is JsonElement v)
|
if (data["voice"] is JsonElement v)
|
||||||
data["voice"] = v.ToString();
|
data["voice"] = v.ToString();
|
||||||
|
else
|
||||||
|
return new RequestResult(false, "Invalid voice name.");
|
||||||
|
|
||||||
string sql = "INSERT INTO \"TtsVoice\" (id, name) VALUES (@idd, @voice)";
|
string id = RandomString(25);
|
||||||
var result = await _database.Execute(sql, data);
|
|
||||||
_logger.Information($"Added a new voice [voice: {data["voice"]}][voice id: {data["idd"]}]");
|
|
||||||
|
|
||||||
data.Remove("idd");
|
_voices.Set(id, data["voice"].ToString());
|
||||||
return new RequestResult(result == 1, id);
|
_logger.Information($"Added a new voice [voice: {data["voice"]}][voice id: {id}]");
|
||||||
|
|
||||||
|
return new RequestResult(true, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RandomString(int length)
|
private string RandomString(int length)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using HermesSocketLibrary.db;
|
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -8,12 +8,12 @@ namespace HermesSocketServer.Requests
|
|||||||
public class DeleteTTSVoice : IRequest
|
public class DeleteTTSVoice : IRequest
|
||||||
{
|
{
|
||||||
public string Name => "delete_tts_voice";
|
public string Name => "delete_tts_voice";
|
||||||
private Database _database;
|
private IStore<string, string> _voices;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
public DeleteTTSVoice(Database database, ILogger logger)
|
public DeleteTTSVoice(VoiceStore voices, ILogger logger)
|
||||||
{
|
{
|
||||||
_database = database;
|
_voices = voices;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,10 +28,9 @@ namespace HermesSocketServer.Requests
|
|||||||
if (data["voice"] is JsonElement v)
|
if (data["voice"] is JsonElement v)
|
||||||
data["voice"] = v.ToString();
|
data["voice"] = v.ToString();
|
||||||
|
|
||||||
string sql = "DELETE FROM \"TtsVoice\" WHERE id = @voice";
|
_voices.Remove(data["voice"].ToString());
|
||||||
var result = await _database.Execute(sql, data);
|
|
||||||
_logger.Information($"Deleted a voice by id [voice id: {data["voice"]}]");
|
_logger.Information($"Deleted a voice by id [voice id: {data["voice"]}]");
|
||||||
return new RequestResult(result == 1, null);
|
return new RequestResult(true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
using HermesSocketLibrary.db;
|
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -7,24 +7,20 @@ namespace HermesSocketServer.Requests
|
|||||||
public class GetTTSUsers : IRequest
|
public class GetTTSUsers : IRequest
|
||||||
{
|
{
|
||||||
public string Name => "get_tts_users";
|
public string Name => "get_tts_users";
|
||||||
private readonly Database _database;
|
private ChatterStore _chatters;
|
||||||
private readonly ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
public GetTTSUsers(Database database, ILogger logger)
|
public GetTTSUsers(ChatterStore chatters, ILogger logger)
|
||||||
{
|
{
|
||||||
_database = database;
|
_chatters = chatters;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<RequestResult> Grant(string sender, IDictionary<string, object>? data)
|
public async Task<RequestResult> Grant(string sender, IDictionary<string, object>? data)
|
||||||
{
|
{
|
||||||
var temp = new Dictionary<string, object>() { { "user", sender } };
|
var temp = _chatters.Get(sender);
|
||||||
|
|
||||||
IDictionary<long, string> users = new Dictionary<long, string>();
|
|
||||||
string sql = $"SELECT \"ttsVoiceId\", \"chatterId\" FROM \"TtsChatVoice\" WHERE \"userId\" = @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}]");
|
_logger.Information($"Fetched all chatters' selected tts voice for channel [channel: {sender}]");
|
||||||
return new RequestResult(true, users, notifyClientsOnAccount: false);
|
return new RequestResult(true, temp, notifyClientsOnAccount: false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using HermesSocketLibrary.db;
|
using HermesSocketLibrary.db;
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -11,15 +12,18 @@ namespace HermesSocketServer.Requests
|
|||||||
|
|
||||||
private readonly ServerConfiguration _configuration;
|
private readonly ServerConfiguration _configuration;
|
||||||
private readonly Database _database;
|
private readonly Database _database;
|
||||||
private readonly ILogger _logger;
|
private ChatterStore _chatters;
|
||||||
|
private ILogger _logger;
|
||||||
|
|
||||||
public UpdateTTSUser(ServerConfiguration configuration, Database database, ILogger logger)
|
public UpdateTTSUser(ChatterStore chatters, Database database, ServerConfiguration configuration, ILogger logger)
|
||||||
{
|
{
|
||||||
_configuration = configuration;
|
|
||||||
_database = database;
|
_database = database;
|
||||||
|
_chatters = chatters;
|
||||||
|
_configuration = configuration;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<RequestResult> Grant(string sender, IDictionary<string, object>? data)
|
public async Task<RequestResult> Grant(string sender, IDictionary<string, object>? data)
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
@ -40,10 +44,9 @@ namespace HermesSocketServer.Requests
|
|||||||
return new RequestResult(false, null);
|
return new RequestResult(false, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
string sql = "UPDATE \"TtsChatVoice\" SET \"ttsVoiceId\" = @voice WHERE \"userId\" = @user AND \"chatterId\" = @chatter";
|
_chatters.Set(sender, chatterId, data["voice"].ToString());
|
||||||
var result = await _database.Execute(sql, data);
|
|
||||||
_logger.Information($"Updated chatter's [chatter: {data["chatter"]}] selected tts voice [voice: {data["voice"]}] in channel [channel: {sender}]");
|
_logger.Information($"Updated chatter's [chatter: {data["chatter"]}] selected tts voice [voice: {data["voice"]}] in channel [channel: {sender}]");
|
||||||
return new RequestResult(result == 1, null);
|
return new RequestResult(true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using HermesSocketLibrary.db;
|
|
||||||
using HermesSocketLibrary.Requests;
|
using HermesSocketLibrary.Requests;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
using ILogger = Serilog.ILogger;
|
using ILogger = Serilog.ILogger;
|
||||||
|
|
||||||
namespace HermesSocketServer.Requests
|
namespace HermesSocketServer.Requests
|
||||||
@ -8,12 +8,12 @@ namespace HermesSocketServer.Requests
|
|||||||
public class UpdateTTSVoice : IRequest
|
public class UpdateTTSVoice : IRequest
|
||||||
{
|
{
|
||||||
public string Name => "update_tts_voice";
|
public string Name => "update_tts_voice";
|
||||||
private Database _database;
|
private IStore<string, string> _voices;
|
||||||
private ILogger _logger;
|
private ILogger _logger;
|
||||||
|
|
||||||
public UpdateTTSVoice(Database database, ILogger logger)
|
public UpdateTTSVoice(VoiceStore voices, ILogger logger)
|
||||||
{
|
{
|
||||||
_database = database;
|
_voices = voices;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,10 +30,9 @@ namespace HermesSocketServer.Requests
|
|||||||
if (data["voiceid"] is JsonElement id)
|
if (data["voiceid"] is JsonElement id)
|
||||||
data["voiceid"] = id.ToString();
|
data["voiceid"] = id.ToString();
|
||||||
|
|
||||||
string sql = "UPDATE \"TtsVoice\" SET name = @voice WHERE id = @voiceid";
|
_voices.Set(data["voiceid"].ToString(), data["voice"].ToString());
|
||||||
var result = await _database.Execute(sql, data);
|
|
||||||
_logger.Information($"Updated voice's [voice id: {data["voiceid"]}] name [new name: {data["voice"]}]");
|
_logger.Information($"Updated voice's [voice id: {data["voiceid"]}] name [new name: {data["voice"]}]");
|
||||||
return new RequestResult(result == 1, null);
|
return new RequestResult(true, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
13
Server.cs
13
Server.cs
@ -52,6 +52,19 @@ namespace HermesSocketLibrary
|
|||||||
if (obj.OpCode != 0)
|
if (obj.OpCode != 0)
|
||||||
_logger.Information($"rxm: {message} [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]");
|
_logger.Information($"rxm: {message} [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]");
|
||||||
|
|
||||||
|
int[] nonProtectedOps = { 0, 1 };
|
||||||
|
if (string.IsNullOrEmpty(socket.Id) && !nonProtectedOps.Contains(obj.OpCode))
|
||||||
|
{
|
||||||
|
_logger.Warning($"An attempt was made to use protected routes while not logged in [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int[] protectedOps = { 0, 3, 5, 6, 7, 8 };
|
||||||
|
if (!string.IsNullOrEmpty(socket.Id) && !protectedOps.Contains(obj.OpCode))
|
||||||
|
{
|
||||||
|
_logger.Warning($"An attempt was made to use non-protected routes while logged in [ip: {socket.IPAddress}][id: {socket.Id}][name: {socket.Name}][token: {socket.ApiKey}][uid: {socket.UID}]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 0: Heartbeat
|
* 0: Heartbeat
|
||||||
* 1: Login RX
|
* 1: Login RX
|
||||||
|
@ -18,5 +18,6 @@ namespace HermesSocketServer
|
|||||||
public class DatabaseConfiguration
|
public class DatabaseConfiguration
|
||||||
{
|
{
|
||||||
public string ConnectionString;
|
public string ConnectionString;
|
||||||
|
public int SaveDelayInSeconds;
|
||||||
}
|
}
|
||||||
}
|
}
|
37
Services/DatabaseService.cs
Normal file
37
Services/DatabaseService.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using HermesSocketServer.Store;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Services
|
||||||
|
{
|
||||||
|
public class DatabaseService : BackgroundService
|
||||||
|
{
|
||||||
|
private readonly VoiceStore _voices;
|
||||||
|
private readonly ChatterStore _chatters;
|
||||||
|
private readonly ServerConfiguration _configuration;
|
||||||
|
private readonly Serilog.ILogger _logger;
|
||||||
|
|
||||||
|
public DatabaseService(VoiceStore voices, ChatterStore chatters, ServerConfiguration configuration, Serilog.ILogger logger) {
|
||||||
|
_voices = voices;
|
||||||
|
_chatters = chatters;
|
||||||
|
_configuration = configuration;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
_logger.Information("Loading TTS voices...");
|
||||||
|
await _voices.Load();
|
||||||
|
_logger.Information("Loading TTS chatters' voice.");
|
||||||
|
await _chatters.Load();
|
||||||
|
|
||||||
|
await Task.Run(async () =>
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(_configuration.Database.SaveDelayInSeconds));
|
||||||
|
await _voices.Save();
|
||||||
|
await _chatters.Save();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
21
Startup.cs
21
Startup.cs
@ -13,6 +13,9 @@ using Serilog.Events;
|
|||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
using YamlDotNet.Serialization.NamingConventions;
|
using YamlDotNet.Serialization.NamingConventions;
|
||||||
using Microsoft.AspNetCore.Connections;
|
using Microsoft.AspNetCore.Connections;
|
||||||
|
using HermesSocketServer.Validators;
|
||||||
|
using HermesSocketServer.Store;
|
||||||
|
using HermesSocketServer.Services;
|
||||||
|
|
||||||
|
|
||||||
var yamlDeserializer = new DeserializerBuilder()
|
var yamlDeserializer = new DeserializerBuilder()
|
||||||
@ -29,7 +32,7 @@ var configuration = yamlDeserializer.Deserialize<ServerConfiguration>(configCont
|
|||||||
if (configuration.Environment.ToUpper() != "QA" && configuration.Environment.ToUpper() != "PROD")
|
if (configuration.Environment.ToUpper() != "QA" && configuration.Environment.ToUpper() != "PROD")
|
||||||
throw new Exception("Invalid environment set.");
|
throw new Exception("Invalid environment set.");
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder();
|
||||||
builder.Logging.ClearProviders();
|
builder.Logging.ClearProviders();
|
||||||
|
|
||||||
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
@ -57,7 +60,7 @@ builder.Host.UseSerilog(logger);
|
|||||||
builder.Logging.AddSerilog(logger);
|
builder.Logging.AddSerilog(logger);
|
||||||
var s = builder.Services;
|
var s = builder.Services;
|
||||||
|
|
||||||
s.AddSerilog();
|
s.AddSerilog(logger);
|
||||||
|
|
||||||
s.AddSingleton<ServerConfiguration>(configuration);
|
s.AddSingleton<ServerConfiguration>(configuration);
|
||||||
s.AddSingleton<Database>();
|
s.AddSingleton<Database>();
|
||||||
@ -72,6 +75,14 @@ s.AddSingleton<ISocketHandler, ChatterHandler>();
|
|||||||
s.AddSingleton<ISocketHandler, EmoteDetailsHandler>();
|
s.AddSingleton<ISocketHandler, EmoteDetailsHandler>();
|
||||||
s.AddSingleton<ISocketHandler, EmoteUsageHandler>();
|
s.AddSingleton<ISocketHandler, EmoteUsageHandler>();
|
||||||
|
|
||||||
|
// Validators
|
||||||
|
s.AddSingleton<VoiceIdValidator>();
|
||||||
|
s.AddSingleton<VoiceNameValidator>();
|
||||||
|
|
||||||
|
// Stores
|
||||||
|
s.AddSingleton<VoiceStore>();
|
||||||
|
s.AddSingleton<ChatterStore>();
|
||||||
|
|
||||||
// Request handlers
|
// Request handlers
|
||||||
s.AddSingleton<IRequest, GetTTSUsers>();
|
s.AddSingleton<IRequest, GetTTSUsers>();
|
||||||
s.AddSingleton<IRequest, GetTTSVoices>();
|
s.AddSingleton<IRequest, GetTTSVoices>();
|
||||||
@ -102,6 +113,9 @@ s.AddSingleton(new JsonSerializerOptions()
|
|||||||
});
|
});
|
||||||
s.AddSingleton<Server>();
|
s.AddSingleton<Server>();
|
||||||
|
|
||||||
|
|
||||||
|
s.AddHostedService<DatabaseService>();
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
app.UseForwardedHeaders();
|
app.UseForwardedHeaders();
|
||||||
app.UseSerilogRequestLogging();
|
app.UseSerilogRequestLogging();
|
||||||
@ -122,7 +136,7 @@ app.Use(async (HttpContext context, RequestDelegate next) =>
|
|||||||
{
|
{
|
||||||
if (context.Request.Path != "/")
|
if (context.Request.Path != "/")
|
||||||
{
|
{
|
||||||
context.Response.StatusCode = StatusCodes.Status403Forbidden;
|
context.Response.StatusCode = StatusCodes.Status401Unauthorized;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,6 +149,7 @@ app.Use(async (HttpContext context, RequestDelegate next) =>
|
|||||||
{
|
{
|
||||||
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
context.Response.StatusCode = StatusCodes.Status400BadRequest;
|
||||||
}
|
}
|
||||||
|
await next(context);
|
||||||
});
|
});
|
||||||
|
|
||||||
await app.RunAsync();
|
await app.RunAsync();
|
283
Store/ChatterStore.cs
Normal file
283
Store/ChatterStore.cs
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Text;
|
||||||
|
using HermesSocketLibrary.db;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Store
|
||||||
|
{
|
||||||
|
public class ChatterStore : IStore<string, long, string>
|
||||||
|
{
|
||||||
|
private readonly Database _database;
|
||||||
|
private readonly Serilog.ILogger _logger;
|
||||||
|
private readonly IDictionary<string, IDictionary<long, string>> _chatters;
|
||||||
|
private readonly IDictionary<string, IList<long>> _added;
|
||||||
|
private readonly IDictionary<string, IList<long>> _modified;
|
||||||
|
private readonly IDictionary<string, IList<long>> _deleted;
|
||||||
|
private readonly object _lock;
|
||||||
|
|
||||||
|
|
||||||
|
public ChatterStore(Database database, Serilog.ILogger logger)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
_logger = logger;
|
||||||
|
_chatters = new Dictionary<string, IDictionary<long, string>>();
|
||||||
|
_added = new Dictionary<string, IList<long>>();
|
||||||
|
_modified = new Dictionary<string, IList<long>>();
|
||||||
|
_deleted = new Dictionary<string, IList<long>>();
|
||||||
|
_lock = new object();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Get(string user, long key)
|
||||||
|
{
|
||||||
|
if (!_chatters.TryGetValue(user, out var broadcaster))
|
||||||
|
return null;
|
||||||
|
if (broadcaster.TryGetValue(key, out var chatter))
|
||||||
|
return chatter;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<string> Get()
|
||||||
|
{
|
||||||
|
return _chatters.Select(c => c.Value).SelectMany(c => c.Values).ToImmutableList();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDictionary<long, string> Get(string user)
|
||||||
|
{
|
||||||
|
if (_chatters.TryGetValue(user, out var chatters))
|
||||||
|
return chatters.ToImmutableDictionary();
|
||||||
|
return new Dictionary<long, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Load()
|
||||||
|
{
|
||||||
|
string sql = "SELECT \"chatterId\", \"ttsVoiceId\", \"userId\" FROM \"TtsChatVoice\";";
|
||||||
|
await _database.Execute(sql, new Dictionary<string, object>(), (reader) =>
|
||||||
|
{
|
||||||
|
var chatterId = reader.GetInt64(0);
|
||||||
|
var ttsVoiceId = reader.GetString(1);
|
||||||
|
var userId = reader.GetString(2);
|
||||||
|
if (!_chatters.TryGetValue(userId, out var chatters))
|
||||||
|
{
|
||||||
|
chatters = new Dictionary<long, string>();
|
||||||
|
_chatters.Add(userId, chatters);
|
||||||
|
}
|
||||||
|
chatters.Add(chatterId, ttsVoiceId);
|
||||||
|
});
|
||||||
|
_logger.Information($"Loaded {_chatters.Count} TTS voices from database.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(string user, long? key)
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_chatters.TryGetValue(user, out var chatters) && chatters.Remove(key.Value))
|
||||||
|
{
|
||||||
|
if (!_added.TryGetValue(user, out var added) || !added.Remove(key.Value))
|
||||||
|
{
|
||||||
|
if (_modified.TryGetValue(user, out var modified))
|
||||||
|
modified.Remove(key.Value);
|
||||||
|
if (!_deleted.TryGetValue(user, out var deleted))
|
||||||
|
{
|
||||||
|
deleted = new List<long>();
|
||||||
|
_deleted.Add(user, deleted);
|
||||||
|
deleted.Add(key.Value);
|
||||||
|
}
|
||||||
|
else if (!deleted.Contains(key.Value))
|
||||||
|
deleted.Add(key.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(string? leftKey, long rightKey)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Save()
|
||||||
|
{
|
||||||
|
var changes = false;
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var sql = "";
|
||||||
|
|
||||||
|
if (_added.Any())
|
||||||
|
{
|
||||||
|
int count = _added.Count;
|
||||||
|
sb.Append("INSERT INTO \"TtsChatVoice\" (\"chatterId\", \"ttsVoiceId\", \"userId\") VALUES ");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var broadcaster in _added)
|
||||||
|
{
|
||||||
|
var userId = broadcaster.Key;
|
||||||
|
var user = _chatters[userId];
|
||||||
|
foreach (var chatterId in broadcaster.Value)
|
||||||
|
{
|
||||||
|
var voiceId = user[chatterId];
|
||||||
|
sb.Append("(")
|
||||||
|
.Append(chatterId)
|
||||||
|
.Append(",'")
|
||||||
|
.Append(voiceId)
|
||||||
|
.Append("','")
|
||||||
|
.Append(userId)
|
||||||
|
.Append("'),");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(';');
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_added.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to save {count} voices to database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to save TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modified.Any())
|
||||||
|
{
|
||||||
|
int count = _modified.Count;
|
||||||
|
sb.Append("UPDATE \"TtsChatVoice\" as t SET \"ttsVoiceId\" = c.\"ttsVoiceId\" FROM (VALUES ");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var broadcaster in _modified)
|
||||||
|
{
|
||||||
|
var userId = broadcaster.Key;
|
||||||
|
var user = _chatters[userId];
|
||||||
|
foreach (var chatterId in broadcaster.Value)
|
||||||
|
{
|
||||||
|
var voiceId = user[chatterId];
|
||||||
|
sb.Append("(")
|
||||||
|
.Append(chatterId)
|
||||||
|
.Append(",'")
|
||||||
|
.Append(voiceId)
|
||||||
|
.Append("','")
|
||||||
|
.Append(userId)
|
||||||
|
.Append("'),");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(") AS c(\"chatterId\", \"ttsVoiceId\", \"userId\") WHERE \"userId\" = c.\"userId\" AND \"chatterId\" = c.\"chatterId\";");
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_modified.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to update {count} voices on the database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to modify TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_deleted.Any())
|
||||||
|
{
|
||||||
|
int count = _deleted.Count;
|
||||||
|
sb.Append("DELETE FROM \"TtsChatVoice\" WHERE (\"chatterId\", \"userId\") IN (");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var broadcaster in _deleted)
|
||||||
|
{
|
||||||
|
var userId = broadcaster.Key;
|
||||||
|
var user = _chatters[userId];
|
||||||
|
foreach (var chatterId in broadcaster.Value)
|
||||||
|
{
|
||||||
|
sb.Append("(")
|
||||||
|
.Append(chatterId)
|
||||||
|
.Append(",'")
|
||||||
|
.Append(userId)
|
||||||
|
.Append("'),");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(");");
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_deleted.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to delete {count} voices from the database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to modify TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Set(string? user, long key, string? value)
|
||||||
|
{
|
||||||
|
if (user == null || value == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (!_chatters.TryGetValue(user, out var broadcaster))
|
||||||
|
{
|
||||||
|
broadcaster = new Dictionary<long, string>();
|
||||||
|
_chatters.Add(user, broadcaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (broadcaster.TryGetValue(key, out var chatter))
|
||||||
|
{
|
||||||
|
if (chatter != value)
|
||||||
|
{
|
||||||
|
broadcaster[key] = value;
|
||||||
|
if (!_added.TryGetValue(user, out var added) || !added.Contains(key))
|
||||||
|
{
|
||||||
|
if (!_modified.TryGetValue(user, out var modified))
|
||||||
|
{
|
||||||
|
modified = new List<long>();
|
||||||
|
_modified.Add(user, modified);
|
||||||
|
modified.Add(key);
|
||||||
|
}
|
||||||
|
else if (!modified.Contains(key))
|
||||||
|
modified.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
broadcaster.Add(key, value);
|
||||||
|
_added.TryAdd(user, new List<long>());
|
||||||
|
|
||||||
|
if (!_deleted.TryGetValue(user, out var deleted) || !deleted.Remove(key))
|
||||||
|
{
|
||||||
|
if (!_added.TryGetValue(user, out var added))
|
||||||
|
{
|
||||||
|
added = new List<long>();
|
||||||
|
_added.Add(user, added);
|
||||||
|
added.Add(key);
|
||||||
|
}
|
||||||
|
else if (!added.Contains(key))
|
||||||
|
added.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
Store/IStore.cs
Normal file
22
Store/IStore.cs
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
namespace HermesSocketServer.Store
|
||||||
|
{
|
||||||
|
public interface IStore<K, V>
|
||||||
|
{
|
||||||
|
V? Get(K key);
|
||||||
|
IDictionary<K, V> Get();
|
||||||
|
Task Load();
|
||||||
|
void Remove(K? key);
|
||||||
|
Task<bool> Save();
|
||||||
|
bool Set(K? key, V? value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IStore<L, R, V>
|
||||||
|
{
|
||||||
|
V? Get(L leftKey, R rightKey);
|
||||||
|
IDictionary<R, V> Get(L leftKey);
|
||||||
|
Task Load();
|
||||||
|
void Remove(L? leftKey, R? rightKey);
|
||||||
|
Task<bool> Save();
|
||||||
|
bool Set(L? leftKey, R? rightKey, V? value);
|
||||||
|
}
|
||||||
|
}
|
224
Store/VoiceStore.cs
Normal file
224
Store/VoiceStore.cs
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Text;
|
||||||
|
using HermesSocketLibrary.db;
|
||||||
|
using HermesSocketServer.Validators;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Store
|
||||||
|
{
|
||||||
|
public class VoiceStore : IStore<string, string>
|
||||||
|
{
|
||||||
|
private readonly Database _database;
|
||||||
|
private readonly IValidator _voiceIdValidator;
|
||||||
|
private readonly IValidator _voiceNameValidator;
|
||||||
|
private readonly Serilog.ILogger _logger;
|
||||||
|
private readonly IDictionary<string, string> _voices;
|
||||||
|
private readonly IList<string> _added;
|
||||||
|
private readonly IList<string> _modified;
|
||||||
|
private readonly IList<string> _deleted;
|
||||||
|
private readonly object _lock;
|
||||||
|
|
||||||
|
public DateTime PreviousSave;
|
||||||
|
|
||||||
|
|
||||||
|
public VoiceStore(Database database, VoiceIdValidator voiceIdValidator, VoiceNameValidator voiceNameValidator, Serilog.ILogger logger)
|
||||||
|
{
|
||||||
|
_database = database;
|
||||||
|
_voiceIdValidator = voiceIdValidator;
|
||||||
|
_voiceNameValidator = voiceNameValidator;
|
||||||
|
_logger = logger;
|
||||||
|
_voices = new Dictionary<string, string>();
|
||||||
|
_added = new List<string>();
|
||||||
|
_modified = new List<string>();
|
||||||
|
_deleted = new List<string>();
|
||||||
|
_lock = new object();
|
||||||
|
|
||||||
|
PreviousSave = DateTime.UtcNow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? Get(string key)
|
||||||
|
{
|
||||||
|
if (_voices.TryGetValue(key, out var voice))
|
||||||
|
return voice;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IDictionary<string, string> Get()
|
||||||
|
{
|
||||||
|
return _voices.ToImmutableDictionary();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Load()
|
||||||
|
{
|
||||||
|
string sql = "SELECT id, name FROM \"TtsVoice\";";
|
||||||
|
await _database.Execute(sql, new Dictionary<string, object>(), (reader) =>
|
||||||
|
{
|
||||||
|
var id = reader.GetString(0);
|
||||||
|
var name = reader.GetString(1);
|
||||||
|
_voices.Add(id, name);
|
||||||
|
});
|
||||||
|
_logger.Information($"Loaded {_voices.Count} TTS voices from database.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(string? key)
|
||||||
|
{
|
||||||
|
if (key == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_voices.ContainsKey(key))
|
||||||
|
{
|
||||||
|
_voices.Remove(key);
|
||||||
|
if (!_added.Remove(key))
|
||||||
|
{
|
||||||
|
_modified.Remove(key);
|
||||||
|
if (!_deleted.Contains(key))
|
||||||
|
_deleted.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> Save()
|
||||||
|
{
|
||||||
|
var changes = false;
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
var sql = "";
|
||||||
|
|
||||||
|
if (_added.Any())
|
||||||
|
{
|
||||||
|
int count = _added.Count;
|
||||||
|
sb.Append("INSERT INTO \"TtsVoice\" (id, name) VALUES ");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var voiceId in _added)
|
||||||
|
{
|
||||||
|
string voice = _voices[voiceId];
|
||||||
|
sb.Append("('")
|
||||||
|
.Append(voiceId)
|
||||||
|
.Append("','")
|
||||||
|
.Append(voice)
|
||||||
|
.Append("'),");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(';');
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_added.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to save {count} voices to database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to save TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_modified.Any())
|
||||||
|
{
|
||||||
|
int count = _modified.Count;
|
||||||
|
sb.Append("UPDATE \"TtsVoice\" as t SET name = c.name FROM (VALUES ");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var voiceId in _modified)
|
||||||
|
{
|
||||||
|
string voice = _voices[voiceId];
|
||||||
|
sb.Append("('")
|
||||||
|
.Append(voiceId)
|
||||||
|
.Append("','")
|
||||||
|
.Append(voice)
|
||||||
|
.Append("'),");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(") AS c(id, name) WHERE id = c.id;");
|
||||||
|
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_modified.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to update {count} voices on the database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to modify TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_deleted.Any())
|
||||||
|
{
|
||||||
|
int count = _deleted.Count;
|
||||||
|
sb.Append("DELETE FROM \"TtsVoice\" WHERE id IN (");
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
foreach (var voiceId in _deleted)
|
||||||
|
{
|
||||||
|
sb.Append("'")
|
||||||
|
.Append(voiceId)
|
||||||
|
.Append("',");
|
||||||
|
}
|
||||||
|
sb.Remove(sb.Length - 1, 1)
|
||||||
|
.Append(");");
|
||||||
|
|
||||||
|
|
||||||
|
sql = sb.ToString();
|
||||||
|
sb.Clear();
|
||||||
|
_deleted.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_logger.Debug($"About to delete {count} voices from the database.");
|
||||||
|
await _database.ExecuteScalar(sql);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
_logger.Error(ex, "Failed to modify TTS voices on database: " + sql);
|
||||||
|
}
|
||||||
|
changes = true;
|
||||||
|
}
|
||||||
|
return changes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Set(string? key, string? value)
|
||||||
|
{
|
||||||
|
if (key == null || value == null)
|
||||||
|
return false;
|
||||||
|
_voiceNameValidator.Check(value);
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_voices.TryGetValue(key, out var voice))
|
||||||
|
{
|
||||||
|
|
||||||
|
if (voice != value)
|
||||||
|
{
|
||||||
|
_voices[key] = value;
|
||||||
|
if (!_added.Contains(key) && !_modified.Contains(key))
|
||||||
|
_modified.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_voiceIdValidator.Check(key);
|
||||||
|
_voices.Add(key, value);
|
||||||
|
if (!_deleted.Remove(key) && !_added.Contains(key))
|
||||||
|
_added.Add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
7
Validators/IValidator.cs
Normal file
7
Validators/IValidator.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace HermesSocketServer.Validators
|
||||||
|
{
|
||||||
|
public interface IValidator
|
||||||
|
{
|
||||||
|
bool Check(string? input);
|
||||||
|
}
|
||||||
|
}
|
29
Validators/RegexValidator.cs
Normal file
29
Validators/RegexValidator.cs
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Validators
|
||||||
|
{
|
||||||
|
public class RegexValidator : IValidator
|
||||||
|
{
|
||||||
|
private readonly Regex _regex;
|
||||||
|
private readonly int _minimum;
|
||||||
|
private readonly int _maximum;
|
||||||
|
|
||||||
|
public RegexValidator(string regex, RegexOptions options, int minimum, int maximum) {
|
||||||
|
_regex = new Regex(regex, options | RegexOptions.Compiled);
|
||||||
|
_minimum = minimum;
|
||||||
|
_maximum = maximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Check(string? input)
|
||||||
|
{
|
||||||
|
if (input == null)
|
||||||
|
throw new ArgumentNullException(nameof(input));
|
||||||
|
if (input.Length < _minimum)
|
||||||
|
throw new ArgumentException("Too short. Must be of length 8 or greater.", nameof(input));
|
||||||
|
if (input.Length > _maximum)
|
||||||
|
throw new ArgumentException("Too long. Must be of length 24 or less.", nameof(input));
|
||||||
|
|
||||||
|
return _regex.IsMatch(input);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
Validators/VoiceIdValidator.cs
Normal file
10
Validators/VoiceIdValidator.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Validators
|
||||||
|
{
|
||||||
|
public class VoiceIdValidator : RegexValidator
|
||||||
|
{
|
||||||
|
public VoiceIdValidator()
|
||||||
|
: base("^[a-z0-9]{25}$", RegexOptions.IgnoreCase, 25, 25) { }
|
||||||
|
}
|
||||||
|
}
|
10
Validators/VoiceNameValidator.cs
Normal file
10
Validators/VoiceNameValidator.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace HermesSocketServer.Validators
|
||||||
|
{
|
||||||
|
public class VoiceNameValidator : RegexValidator
|
||||||
|
{
|
||||||
|
public VoiceNameValidator()
|
||||||
|
: base("^[a-z0-9_\\-]{2,32}$", RegexOptions.IgnoreCase, 2, 32) { }
|
||||||
|
}
|
||||||
|
}
|
@ -79,13 +79,13 @@ namespace HermesSocketLibrary.db
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<int> Execute(string sql, Action<NpgsqlCommand> action)
|
public async Task<int> Execute(string sql, Action<NpgsqlCommand> prepare)
|
||||||
{
|
{
|
||||||
using (var connection = await _source.OpenConnectionAsync())
|
using (var connection = await _source.OpenConnectionAsync())
|
||||||
{
|
{
|
||||||
using (var command = new NpgsqlCommand(sql, connection))
|
using (var command = new NpgsqlCommand(sql, connection))
|
||||||
{
|
{
|
||||||
action(command);
|
prepare(command);
|
||||||
await command.PrepareAsync();
|
await command.PrepareAsync();
|
||||||
|
|
||||||
return await command.ExecuteNonQueryAsync();
|
return await command.ExecuteNonQueryAsync();
|
||||||
|
Loading…
Reference in New Issue
Block a user