Asyncify event storage.
This commit is contained in:
parent
dd377358e2
commit
0a7e01f154
8 changed files with 63 additions and 60 deletions
|
@ -27,14 +27,14 @@ public class DeleteMessageClientCommand : ClientCommand {
|
|||
return;
|
||||
}
|
||||
|
||||
StoredEventInfo? delMsg = ctx.Chat.Events.GetEvent(delSeqId);
|
||||
StoredEventInfo? delMsg = await ctx.Chat.Events.GetEvent(delSeqId);
|
||||
|
||||
if(delMsg?.Sender is null || delMsg.Sender.Rank > ctx.User.Rank || (!deleteAnyMessage && delMsg.Sender.UserId != ctx.User.UserId)) {
|
||||
await ctx.Chat.SendTo(ctx.User, new CommandResponseS2CPacket(msgId, LCR.MESSAGE_DELETE_ERROR));
|
||||
return;
|
||||
}
|
||||
|
||||
ctx.Chat.Events.RemoveEvent(delMsg);
|
||||
await ctx.Chat.Events.RemoveEvent(delMsg);
|
||||
await ctx.Chat.Send(new ChatMessageDeleteS2CPacket(delMsg.Id));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ public class Context {
|
|||
));
|
||||
}
|
||||
|
||||
Events.AddEvent(
|
||||
await Events.AddEvent(
|
||||
mce.MessageId, "msg:add",
|
||||
mce.ChannelName,
|
||||
mce.SenderId, mce.SenderName, mce.SenderColour, mce.SenderRank, mce.SenderNickName, mce.SenderPerms,
|
||||
|
@ -212,7 +212,7 @@ public class Context {
|
|||
if(!IsInChannel(user, chan)) {
|
||||
long msgId = RandomSnowflake.Next();
|
||||
await SendTo(chan, new UserConnectS2CPacket(msgId, DateTimeOffset.Now, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
|
||||
Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
await Events.AddEvent(msgId, "user:connect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
}
|
||||
|
||||
await conn.Send(new AuthSuccessS2CPacket(
|
||||
|
@ -236,7 +236,8 @@ public class Context {
|
|||
))
|
||||
));
|
||||
|
||||
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
||||
IEnumerable<StoredEventInfo> msgs = await Events.GetChannelEventLog(chan.Name);
|
||||
foreach(StoredEventInfo msg in msgs)
|
||||
await conn.Send(new ContextMessageS2CPacket(msg));
|
||||
|
||||
await conn.Send(new ContextChannelsS2CPacket(
|
||||
|
@ -262,7 +263,7 @@ public class Context {
|
|||
|
||||
long msgId = RandomSnowflake.Next();
|
||||
await SendTo(chan, new UserDisconnectS2CPacket(msgId, DateTimeOffset.Now, user.UserId, user.LegacyNameWithStatus, reason));
|
||||
Events.AddEvent(msgId, "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
|
||||
await Events.AddEvent(msgId, "user:disconnect", chan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, new { reason = (int)reason }, StoredEventFlags.Log);
|
||||
|
||||
if(chan.IsTemporary && chan.IsOwner(user))
|
||||
await RemoveChannel(chan);
|
||||
|
@ -300,11 +301,11 @@ public class Context {
|
|||
|
||||
long leaveId = RandomSnowflake.Next();
|
||||
await SendTo(oldChan, new UserChannelLeaveS2CPacket(leaveId, user.UserId));
|
||||
Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
await Events.AddEvent(leaveId, "chan:leave", oldChan.Name, user.UserId, user.UserName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
|
||||
long joinId = RandomSnowflake.Next();
|
||||
await SendTo(chan, new UserChannelJoinS2CPacket(joinId, user.UserId, user.LegacyNameWithStatus, user.Colour, user.Rank, user.Permissions));
|
||||
Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.LegacyName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
await Events.AddEvent(joinId, "chan:join", chan.Name, user.UserId, user.LegacyName, user.Colour, user.Rank, user.NickName, user.Permissions, null, StoredEventFlags.Log);
|
||||
|
||||
await SendTo(user, new ContextClearS2CPacket(ContextClearS2CPacket.Mode.MessagesUsers));
|
||||
await SendTo(user, new ContextUsersS2CPacket(
|
||||
|
@ -319,7 +320,8 @@ public class Context {
|
|||
))
|
||||
));
|
||||
|
||||
foreach(StoredEventInfo msg in Events.GetChannelEventLog(chan.Name))
|
||||
IEnumerable<StoredEventInfo> msgs = await Events.GetChannelEventLog(chan.Name);
|
||||
foreach(StoredEventInfo msg in msgs)
|
||||
await SendTo(user, new ContextMessageS2CPacket(msg));
|
||||
|
||||
await ForceChannel(user, chan);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
namespace SharpChat.EventStorage;
|
||||
|
||||
public interface EventStorage {
|
||||
void AddEvent(
|
||||
Task AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string channelName,
|
||||
|
@ -14,7 +14,7 @@ public interface EventStorage {
|
|||
object? data = null,
|
||||
StoredEventFlags flags = StoredEventFlags.None
|
||||
);
|
||||
void RemoveEvent(StoredEventInfo evt);
|
||||
StoredEventInfo? GetEvent(long seqId);
|
||||
IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0);
|
||||
Task RemoveEvent(StoredEventInfo evt);
|
||||
Task<StoredEventInfo?> GetEvent(long seqId);
|
||||
Task<IEnumerable<StoredEventInfo>> GetChannelEventLog(string channelName, int amount = 20, int offset = 0);
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace SharpChat.EventStorage;
|
|||
public partial class MariaDBEventStorage(string connString) : EventStorage {
|
||||
private string ConnectionString { get; } = connString ?? throw new ArgumentNullException(nameof(connString));
|
||||
|
||||
public void AddEvent(
|
||||
public async Task AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string channelName,
|
||||
|
@ -20,7 +20,7 @@ public partial class MariaDBEventStorage(string connString) : EventStorage {
|
|||
object? data = null,
|
||||
StoredEventFlags flags = StoredEventFlags.None
|
||||
) {
|
||||
RunCommand(
|
||||
await RunCommand(
|
||||
"INSERT INTO `sqc_events` (`event_id`, `event_created`, `event_type`, `event_target`, `event_flags`, `event_data`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`)"
|
||||
+ " VALUES (@id, NOW(), @type, @target, @flags, @data"
|
||||
|
@ -39,9 +39,9 @@ public partial class MariaDBEventStorage(string connString) : EventStorage {
|
|||
);
|
||||
}
|
||||
|
||||
public StoredEventInfo? GetEvent(long seqId) {
|
||||
public async Task<StoredEventInfo?> GetEvent(long seqId) {
|
||||
try {
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
using MySqlDataReader? reader = await RunQuery(
|
||||
"SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`"
|
||||
+ ", UNIX_TIMESTAMP(`event_created`) AS `event_created`"
|
||||
|
@ -86,11 +86,11 @@ public partial class MariaDBEventStorage(string connString) : EventStorage {
|
|||
);
|
||||
}
|
||||
|
||||
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
||||
public async Task<IEnumerable<StoredEventInfo>> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
||||
List<StoredEventInfo> events = [];
|
||||
|
||||
try {
|
||||
using MySqlDataReader? reader = RunQuery(
|
||||
using MySqlDataReader? reader = await RunQuery(
|
||||
"SELECT `event_id`, `event_type`, `event_flags`, `event_data`, `event_target`"
|
||||
+ ", `event_sender`, `event_sender_name`, `event_sender_colour`, `event_sender_rank`, `event_sender_nick`, `event_sender_perms`"
|
||||
+ ", UNIX_TIMESTAMP(`event_created`) AS `event_created`"
|
||||
|
@ -121,9 +121,8 @@ public partial class MariaDBEventStorage(string connString) : EventStorage {
|
|||
return events;
|
||||
}
|
||||
|
||||
public void RemoveEvent(StoredEventInfo evt) {
|
||||
ArgumentNullException.ThrowIfNull(evt);
|
||||
RunCommand(
|
||||
public async Task RemoveEvent(StoredEventInfo evt) {
|
||||
await RunCommand(
|
||||
"UPDATE IGNORE `sqc_events` SET `event_deleted` = NOW() WHERE `event_id` = @id AND `event_deleted` IS NULL",
|
||||
new MySqlParameter("id", evt.Id)
|
||||
);
|
||||
|
|
|
@ -29,20 +29,20 @@ public partial class MariaDBEventStorage {
|
|||
}.ToString();
|
||||
}
|
||||
|
||||
private MySqlConnection GetConnection() {
|
||||
private async Task<MySqlConnection> GetConnectionAsync() {
|
||||
MySqlConnection conn = new(ConnectionString);
|
||||
conn.Open();
|
||||
await conn.OpenAsync();
|
||||
return conn;
|
||||
}
|
||||
|
||||
private int RunCommand(string command, params MySqlParameter[] parameters) {
|
||||
private async Task<int> RunCommand(string command, params MySqlParameter[] parameters) {
|
||||
try {
|
||||
using MySqlConnection conn = GetConnection();
|
||||
using MySqlConnection conn = await GetConnectionAsync();
|
||||
using MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
return cmd.ExecuteNonQuery();
|
||||
return await cmd.ExecuteNonQueryAsync();
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
@ -50,14 +50,14 @@ public partial class MariaDBEventStorage {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private MySqlDataReader? RunQuery(string command, params MySqlParameter[] parameters) {
|
||||
private async Task<MySqlDataReader?> RunQuery(string command, params MySqlParameter[] parameters) {
|
||||
try {
|
||||
MySqlConnection conn = GetConnection();
|
||||
MySqlConnection conn = await GetConnectionAsync();
|
||||
MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
return cmd.ExecuteReader(System.Data.CommandBehavior.CloseConnection);
|
||||
return await cmd.ExecuteReaderAsync(System.Data.CommandBehavior.CloseConnection);
|
||||
} catch(MySqlException ex) {
|
||||
Logger.Write(ex);
|
||||
}
|
||||
|
@ -65,17 +65,17 @@ public partial class MariaDBEventStorage {
|
|||
return null;
|
||||
}
|
||||
|
||||
private T RunQueryValue<T>(string command, params MySqlParameter[] parameters)
|
||||
private async Task<T> RunQueryValue<T>(string command, params MySqlParameter[] parameters)
|
||||
where T : struct {
|
||||
try {
|
||||
using MySqlConnection conn = GetConnection();
|
||||
using MySqlConnection conn = await GetConnectionAsync();
|
||||
using MySqlCommand cmd = conn.CreateCommand();
|
||||
if(parameters?.Length > 0)
|
||||
cmd.Parameters.AddRange(parameters);
|
||||
cmd.CommandText = command;
|
||||
cmd.Prepare();
|
||||
await cmd.PrepareAsync();
|
||||
|
||||
object? raw = cmd.ExecuteScalar();
|
||||
object? raw = await cmd.ExecuteScalarAsync();
|
||||
if(raw is T value)
|
||||
return value;
|
||||
} catch(MySqlException ex) {
|
||||
|
|
|
@ -3,23 +3,23 @@
|
|||
namespace SharpChat.EventStorage;
|
||||
|
||||
public partial class MariaDBEventStorage {
|
||||
private void DoMigration(string name, Action action) {
|
||||
bool done = RunQueryValue<long>(
|
||||
private async Task DoMigration(string name, Func<Task> action) {
|
||||
bool done = await RunQueryValue<long>(
|
||||
"SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name",
|
||||
new MySqlParameter("name", name)
|
||||
) > 0;
|
||||
if(!done) {
|
||||
Logger.Write($"Running migration '{name}'...");
|
||||
action();
|
||||
RunCommand(
|
||||
await action();
|
||||
await RunCommand(
|
||||
"INSERT INTO `sqc_migrations` (`migration_name`) VALUES (@name)",
|
||||
new MySqlParameter("name", name)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public void RunMigrations() {
|
||||
RunCommand(
|
||||
public async Task RunMigrations() {
|
||||
await RunCommand(
|
||||
"CREATE TABLE IF NOT EXISTS `sqc_migrations` ("
|
||||
+ "`migration_name` VARCHAR(255) NOT NULL,"
|
||||
+ "`migration_completed` TIMESTAMP NOT NULL DEFAULT current_timestamp(),"
|
||||
|
@ -28,36 +28,36 @@ public partial class MariaDBEventStorage {
|
|||
+ ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;"
|
||||
);
|
||||
|
||||
DoMigration("create_events_table", CreateEventsTable);
|
||||
DoMigration("allow_null_target", AllowNullTarget);
|
||||
DoMigration("event_data_as_medium_blob", EventDataAsMediumBlob);
|
||||
DoMigration("event_user_and_nick_name_to_1000", EventUserAndNickNameTo1000);
|
||||
await DoMigration("create_events_table", CreateEventsTable);
|
||||
await DoMigration("allow_null_target", AllowNullTarget);
|
||||
await DoMigration("event_data_as_medium_blob", EventDataAsMediumBlob);
|
||||
await DoMigration("event_user_and_nick_name_to_1000", EventUserAndNickNameTo1000);
|
||||
}
|
||||
|
||||
private void EventUserAndNickNameTo1000() {
|
||||
RunCommand(
|
||||
private async Task EventUserAndNickNameTo1000() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_sender_name` `event_sender_name` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender`,"
|
||||
+ " CHANGE COLUMN `event_sender_nick` `event_sender_nick` VARCHAR(1000) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender_rank`;"
|
||||
);
|
||||
}
|
||||
|
||||
private void EventDataAsMediumBlob() {
|
||||
RunCommand(
|
||||
private async Task EventDataAsMediumBlob() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_data` `event_data` MEDIUMBLOB NULL DEFAULT NULL AFTER `event_flags`;"
|
||||
);
|
||||
}
|
||||
|
||||
private void AllowNullTarget() {
|
||||
RunCommand(
|
||||
private async Task AllowNullTarget() {
|
||||
await RunCommand(
|
||||
"ALTER TABLE `sqc_events`"
|
||||
+ " CHANGE COLUMN `event_target` `event_target` VARBINARY(255) NULL AFTER `event_type`;"
|
||||
);
|
||||
}
|
||||
|
||||
private void CreateEventsTable() {
|
||||
RunCommand(
|
||||
private async Task CreateEventsTable() {
|
||||
await RunCommand(
|
||||
"CREATE TABLE `sqc_events` ("
|
||||
+ "`event_id` BIGINT(20) NOT NULL,"
|
||||
+ "`event_sender` BIGINT(20) UNSIGNED NULL DEFAULT NULL,"
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace SharpChat.EventStorage;
|
|||
public class VirtualEventStorage : EventStorage {
|
||||
private readonly Dictionary<long, StoredEventInfo> Events = [];
|
||||
|
||||
public void AddEvent(
|
||||
public Task AddEvent(
|
||||
long id,
|
||||
string type,
|
||||
string channelName,
|
||||
|
@ -40,18 +40,20 @@ public class VirtualEventStorage : EventStorage {
|
|||
flags
|
||||
)
|
||||
);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public StoredEventInfo? GetEvent(long seqId) {
|
||||
return Events.TryGetValue(seqId, out StoredEventInfo? evt) ? evt : null;
|
||||
public Task<StoredEventInfo?> GetEvent(long seqId) {
|
||||
return Task.FromResult(Events.TryGetValue(seqId, out StoredEventInfo? evt) ? evt : null);
|
||||
}
|
||||
|
||||
public void RemoveEvent(StoredEventInfo evt) {
|
||||
ArgumentNullException.ThrowIfNull(evt);
|
||||
public Task RemoveEvent(StoredEventInfo evt) {
|
||||
Events.Remove(evt.Id);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public IEnumerable<StoredEventInfo> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
||||
public Task<IEnumerable<StoredEventInfo>> GetChannelEventLog(string channelName, int amount = 20, int offset = 0) {
|
||||
IEnumerable<StoredEventInfo> subset = Events.Values.Where(ev => ev.ChannelName == channelName);
|
||||
|
||||
int start = subset.Count() - offset - amount;
|
||||
|
@ -60,6 +62,6 @@ public class VirtualEventStorage : EventStorage {
|
|||
start = 0;
|
||||
}
|
||||
|
||||
return [.. subset.Skip(start).Take(amount)];
|
||||
return Task.FromResult(subset.Skip(start).Take(amount).ToArray() as IEnumerable<StoredEventInfo>);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,7 +129,7 @@ if(string.IsNullOrWhiteSpace(config.SafeReadValue("mariadb:host", string.Empty))
|
|||
} else {
|
||||
MariaDBEventStorage mdbes = new(MariaDBEventStorage.BuildConnString(config.ScopeTo("mariadb")));
|
||||
evtStore = mdbes;
|
||||
mdbes.RunMigrations();
|
||||
await mdbes.RunMigrations();
|
||||
}
|
||||
|
||||
if(hasCancelled) return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue