Killed history

This commit is contained in:
Kwoth
2021-09-06 21:29:22 +02:00
commit 7aca29ae8a
950 changed files with 366651 additions and 0 deletions

View File

@@ -0,0 +1,77 @@
using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Core.Services
{
public class GreetGrouper<T>
{
private readonly Dictionary<ulong, HashSet<T>> group;
private readonly object locker = new object();
public GreetGrouper()
{
group = new Dictionary<ulong, HashSet<T>>();
}
/// <summary>
/// Creates a group, if group already exists, adds the specified user
/// </summary>
/// <param name="guildId">Id of the server for which to create group for</param>
/// <param name="toAddIfExists">User to add if group already exists</param>
/// <returns></returns>
public bool CreateOrAdd(ulong guildId, T toAddIfExists)
{
lock (locker)
{
if (group.TryGetValue(guildId, out var list))
{
list.Add(toAddIfExists);
return false;
}
group[guildId] = new HashSet<T>();
return true;
}
}
/// <summary>
/// Remove the specified amount of items from the group. If all items are removed, group will be removed.
/// </summary>
/// <param name="guildId">Id of the group</param>
/// <param name="count">Maximum number of items to retrieve</param>
/// <param name="items">Items retrieved</param>
/// <returns>Whether the group has no more items left and is deleted</returns>
public bool ClearGroup(ulong guildId, int count, out IEnumerable<T> items)
{
lock (locker)
{
if (group.TryGetValue(guildId, out var set))
{
// if we want more than there are, return everything
if (count >= set.Count)
{
items = set;
group.Remove(guildId);
return true;
}
// if there are more in the group than what's needed
// take the requested number, remove them from the set
// and return them
var toReturn = set.TakeWhile(item => count-- != 0).ToList();
foreach (var item in toReturn)
set.Remove(item);
items = toReturn;
// returning falsemeans group is not yet deleted
// because there are items left
return false;
}
items = Enumerable.Empty<T>();
return true;
}
}
}
}

View File

@@ -0,0 +1,141 @@
using Newtonsoft.Json.Linq;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Serilog;
namespace NadekoBot.Core.Services.Common
{
public class ImageLoader
{
private readonly HttpClient _http;
private readonly ConnectionMultiplexer _con;
public Func<string, RedisKey> GetKey { get; }
private IDatabase _db => _con.GetDatabase();
private readonly List<Task<KeyValuePair<RedisKey, RedisValue>>> uriTasks = new List<Task<KeyValuePair<RedisKey, RedisValue>>>();
public ImageLoader(HttpClient http, ConnectionMultiplexer con, Func<string, RedisKey> getKey)
{
_http = http;
_con = con;
GetKey = getKey;
}
private async Task<byte[]> GetImageData(Uri uri)
{
if (uri.IsFile)
{
try
{
var bytes = await File.ReadAllBytesAsync(uri.LocalPath);
return bytes;
}
catch (Exception ex)
{
Log.Warning(ex, "Failed reading image bytes");
return null;
}
}
else
{
return await _http.GetByteArrayAsync(uri);
}
}
async Task HandleJArray(JArray arr, string key)
{
var tasks = arr.Where(x => x.Type == JTokenType.String)
.Select(async x =>
{
try
{
return await GetImageData((Uri)x).ConfigureAwait(false);
}
catch
{
Log.Error("Error retreiving image for key {Key}: {Data}", key, x);
return null;
}
});
byte[][] vals = Array.Empty<byte[]>();
vals = await Task.WhenAll(tasks).ConfigureAwait(false);
if (vals.Any(x => x == null))
vals = vals.Where(x => x != null).ToArray();
await _db.KeyDeleteAsync(GetKey(key)).ConfigureAwait(false);
await _db.ListRightPushAsync(GetKey(key),
vals.Where(x => x != null)
.Select(x => (RedisValue)x)
.ToArray()).ConfigureAwait(false);
if (arr.Count != vals.Length)
{
Log.Information("{2}/{1} URIs for the key '{0}' have been loaded. Some of the supplied URIs are either unavailable or invalid.", key, arr.Count, vals.Count());
}
}
async Task<KeyValuePair<RedisKey, RedisValue>> HandleUri(Uri uri, string key)
{
try
{
RedisValue data = await GetImageData(uri).ConfigureAwait(false);
return new KeyValuePair<RedisKey, RedisValue>(GetKey(key), data);
}
catch
{
Log.Information("Setting '{0}' image failed. The URI you provided is either unavailable or invalid.", key.ToLowerInvariant());
return new KeyValuePair<RedisKey, RedisValue>("", "");
}
}
Task HandleJObject(JObject obj, string parent = "")
{
string GetParentString()
{
if (string.IsNullOrWhiteSpace(parent))
return "";
else
return parent + "_";
}
List<Task> tasks = new List<Task>();
Task t;
// go through all of the kvps in the object
foreach (var kvp in obj)
{
// if it's a JArray, resole it using jarray method which will
// return task<byte[][]> aka an array of all images' bytes
if (kvp.Value.Type == JTokenType.Array)
{
t = HandleJArray((JArray)kvp.Value, GetParentString() + kvp.Key);
tasks.Add(t);
}
else if (kvp.Value.Type == JTokenType.String)
{
var uriTask = HandleUri((Uri)kvp.Value, GetParentString() + kvp.Key);
uriTasks.Add(uriTask);
}
else if (kvp.Value.Type == JTokenType.Object)
{
t = HandleJObject((JObject)kvp.Value, GetParentString() + kvp.Key);
tasks.Add(t);
}
}
return Task.WhenAll(tasks);
}
public async Task LoadAsync(JObject obj)
{
await HandleJObject(obj).ConfigureAwait(false);
var results = await Task.WhenAll(uriTasks).ConfigureAwait(false);
await _db.StringSetAsync(results.Where(x => x.Key != "").ToArray()).ConfigureAwait(false);
}
}
}

View File

@@ -0,0 +1,52 @@
using StackExchange.Redis;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace NadekoBot.Core.Services.Common
{
public sealed class RedisImageArray : IReadOnlyList<byte[]>
{
public byte[] this[int index]
{
get
{
if (index < 0)
throw new ArgumentOutOfRangeException(nameof(index));
return _con.GetDatabase().ListGetByIndex(_key, index);
}
}
public int Count => _data.IsValueCreated
? _data.Value.Length
: (int)_con.GetDatabase().ListLength(_key);
private readonly ConnectionMultiplexer _con;
private readonly string _key;
private readonly Lazy<byte[][]> _data;
public RedisImageArray(string key, ConnectionMultiplexer con)
{
_con = con;
_key = key;
_data = new Lazy<byte[][]>(() => _con.GetDatabase().ListRange(_key).Select(x => (byte[])x).ToArray(), true);
}
public IEnumerator<byte[]> GetEnumerator()
{
var actualData = _data.Value;
for (int i = 0; i < actualData.Length; i++)
{
yield return actualData[i];
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return _data.Value.GetEnumerator();
}
}
}