mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 09:18:27 -04:00
Killed history
This commit is contained in:
95
NadekoBot.Core/Common/PubSub/EventPubSub.cs
Normal file
95
NadekoBot.Core/Common/PubSub/EventPubSub.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public class EventPubSub : IPubSub
|
||||
{
|
||||
private readonly Dictionary<string, Dictionary<Delegate, List<Func<object, ValueTask>>>> _actions
|
||||
= new Dictionary<string, Dictionary<Delegate, List<Func<object, ValueTask>>>>();
|
||||
private readonly object locker = new object();
|
||||
|
||||
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
|
||||
{
|
||||
Func<object, ValueTask> localAction = obj => action((TData) obj);
|
||||
lock(locker)
|
||||
{
|
||||
Dictionary<Delegate, List<Func<object, ValueTask>>> keyActions;
|
||||
if (!_actions.TryGetValue(key.Key, out keyActions))
|
||||
{
|
||||
keyActions = new Dictionary<Delegate, List<Func<object, ValueTask>>>();
|
||||
_actions[key.Key] = keyActions;
|
||||
}
|
||||
|
||||
List<Func<object, ValueTask>> sameActions;
|
||||
if (!keyActions.TryGetValue(action, out sameActions))
|
||||
{
|
||||
sameActions = new List<Func<object, ValueTask>>();
|
||||
keyActions[action] = sameActions;
|
||||
}
|
||||
|
||||
sameActions.Add(localAction);
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public Task Pub<TData>(in TypedKey<TData> key, TData data)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
if(_actions.TryGetValue(key.Key, out var actions))
|
||||
{
|
||||
// if this class ever gets used, this needs to be properly implemented
|
||||
// 1. ignore all valuetasks which are completed
|
||||
// 2. return task.whenall all other tasks
|
||||
return Task.WhenAll(actions
|
||||
.SelectMany(kvp => kvp.Value)
|
||||
.Select(action => action(data).AsTask()));
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public Task Unsub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
// get subscriptions for this action
|
||||
if (_actions.TryGetValue(key.Key, out var actions))
|
||||
{
|
||||
var hashCode = action.GetHashCode();
|
||||
// get subscriptions which have the same action hash code
|
||||
// note: having this as a list allows for multiple subscriptions of
|
||||
// the same insance's/static method
|
||||
if (actions.TryGetValue(action, out var sameActions))
|
||||
{
|
||||
// remove last subscription
|
||||
sameActions.RemoveAt(sameActions.Count - 1);
|
||||
|
||||
// if the last subscription was the only subscription
|
||||
// we can safely remove this action's dictionary entry
|
||||
if (sameActions.Count == 0)
|
||||
{
|
||||
actions.Remove(action);
|
||||
|
||||
// if our dictionary has no more elements after
|
||||
// removing the entry
|
||||
// it's safe to remove it from the key's subscriptions
|
||||
if (actions.Count == 0)
|
||||
{
|
||||
_actions.Remove(key.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
11
NadekoBot.Core/Common/PubSub/IPubSub.cs
Normal file
11
NadekoBot.Core/Common/PubSub/IPubSub.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public interface IPubSub
|
||||
{
|
||||
public Task Pub<TData>(in TypedKey<TData> key, TData data);
|
||||
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action);
|
||||
}
|
||||
}
|
8
NadekoBot.Core/Common/PubSub/ISeria.cs
Normal file
8
NadekoBot.Core/Common/PubSub/ISeria.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public interface ISeria
|
||||
{
|
||||
byte[] Serialize<T>(T data);
|
||||
T Deserialize<T>(byte[] data);
|
||||
}
|
||||
}
|
28
NadekoBot.Core/Common/PubSub/JsonSeria.cs
Normal file
28
NadekoBot.Core/Common/PubSub/JsonSeria.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Text.Json;
|
||||
using NadekoBot.Core.Common.JsonConverters;
|
||||
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public class JsonSeria : ISeria
|
||||
{
|
||||
private JsonSerializerOptions serializerOptions = new JsonSerializerOptions()
|
||||
{
|
||||
Converters =
|
||||
{
|
||||
new Rgba32Converter(),
|
||||
new CultureInfoConverter(),
|
||||
}
|
||||
};
|
||||
public byte[] Serialize<T>(T data)
|
||||
=> JsonSerializer.SerializeToUtf8Bytes(data, serializerOptions);
|
||||
|
||||
public T Deserialize<T>(byte[] data)
|
||||
{
|
||||
if (data is null)
|
||||
return default;
|
||||
|
||||
|
||||
return JsonSerializer.Deserialize<T>(data, serializerOptions);
|
||||
}
|
||||
}
|
||||
}
|
46
NadekoBot.Core/Common/PubSub/RedisPubSub.cs
Normal file
46
NadekoBot.Core/Common/PubSub/RedisPubSub.cs
Normal file
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NadekoBot.Core.Services;
|
||||
using NadekoBot.Extensions;
|
||||
using Serilog;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public sealed class RedisPubSub : IPubSub
|
||||
{
|
||||
private readonly ConnectionMultiplexer _multi;
|
||||
private readonly ISeria _serializer;
|
||||
private readonly IBotCredentials _creds;
|
||||
|
||||
public RedisPubSub(ConnectionMultiplexer multi, ISeria serializer, IBotCredentials creds)
|
||||
{
|
||||
_multi = multi;
|
||||
_serializer = serializer;
|
||||
_creds = creds;
|
||||
}
|
||||
|
||||
public Task Pub<TData>(in TypedKey<TData> key, TData data)
|
||||
{
|
||||
var serialized = _serializer.Serialize(data);
|
||||
return _multi.GetSubscriber().PublishAsync($"{_creds.RedisKey()}:{key.Key}", serialized, CommandFlags.FireAndForget);
|
||||
}
|
||||
|
||||
public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
|
||||
{
|
||||
var eventName = key.Key;
|
||||
return _multi.GetSubscriber().SubscribeAsync($"{_creds.RedisKey()}:{eventName}", async (ch, data) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var dataObj = _serializer.Deserialize<TData>(data);
|
||||
await action(dataObj);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"Error handling the event {eventName}: {ex.Message}");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
29
NadekoBot.Core/Common/PubSub/TypedKey.cs
Normal file
29
NadekoBot.Core/Common/PubSub/TypedKey.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public readonly struct TypedKey<TData>
|
||||
{
|
||||
public readonly string Key;
|
||||
|
||||
public TypedKey(in string key)
|
||||
{
|
||||
Key = key;
|
||||
}
|
||||
|
||||
public static implicit operator TypedKey<TData>(in string input)
|
||||
=> new TypedKey<TData>(input);
|
||||
public static implicit operator string(in TypedKey<TData> input)
|
||||
=> input.Key;
|
||||
|
||||
public static bool operator ==(in TypedKey<TData> left, in TypedKey<TData> right)
|
||||
=> left.Key == right.Key;
|
||||
public static bool operator !=(in TypedKey<TData> left, in TypedKey<TData> right)
|
||||
=> !(left == right);
|
||||
|
||||
public override bool Equals(object obj)
|
||||
=> obj is TypedKey<TData> o && o == this;
|
||||
|
||||
public override int GetHashCode() => Key?.GetHashCode() ?? 0;
|
||||
|
||||
public override string ToString() => Key;
|
||||
}
|
||||
}
|
38
NadekoBot.Core/Common/PubSub/YamlSeria.cs
Normal file
38
NadekoBot.Core/Common/PubSub/YamlSeria.cs
Normal file
@@ -0,0 +1,38 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using NadekoBot.Common.Yml;
|
||||
using NadekoBot.Core.Common.Configs;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace NadekoBot.Core.Common
|
||||
{
|
||||
public class YamlSeria : IConfigSeria
|
||||
{
|
||||
private readonly ISerializer _serializer;
|
||||
private readonly IDeserializer _deserializer;
|
||||
|
||||
private static readonly Regex CodePointRegex
|
||||
= new Regex(@"(\\U(?<code>[a-zA-Z0-9]{8})|\\u(?<code>[a-zA-Z0-9]{4})|\\x(?<code>[a-zA-Z0-9]{2}))",
|
||||
RegexOptions.Compiled);
|
||||
|
||||
public YamlSeria()
|
||||
{
|
||||
_serializer = Yaml.Serializer;
|
||||
_deserializer = Yaml.Deserializer;
|
||||
}
|
||||
|
||||
public string Serialize<T>(T obj)
|
||||
{
|
||||
var escapedOutput = _serializer.Serialize(obj);
|
||||
var output = CodePointRegex.Replace(escapedOutput, me =>
|
||||
{
|
||||
var str = me.Groups["code"].Value;
|
||||
var newString = YamlHelper.UnescapeUnicodeCodePoint(str);
|
||||
return newString;
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
public T Deserialize<T>(string data)
|
||||
=> _deserializer.Deserialize<T>(data);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user