Removed Ellie.Common
This commit is contained in:
parent
3ef832114f
commit
32637d4265
16 changed files with 0 additions and 818 deletions
|
@ -1,19 +0,0 @@
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public class AsyncLazy<T> : Lazy<Task<T>>
|
|
||||||
{
|
|
||||||
public AsyncLazy(Func<T> valueFactory)
|
|
||||||
: base(() => Task.Run(valueFactory))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public AsyncLazy(Func<Task<T>> taskFactory)
|
|
||||||
: base(() => Task.Run(taskFactory))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public TaskAwaiter<T> GetAwaiter()
|
|
||||||
=> Value.GetAwaiter();
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
using System.Diagnostics;
|
|
||||||
|
|
||||||
namespace System.Collections.Generic;
|
|
||||||
|
|
||||||
[DebuggerDisplay("{_backingStore.Count}")]
|
|
||||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T> where T : notnull
|
|
||||||
{
|
|
||||||
private readonly ConcurrentDictionary<T, bool> _backingStore;
|
|
||||||
|
|
||||||
public ConcurrentHashSet()
|
|
||||||
=> _backingStore = new();
|
|
||||||
|
|
||||||
public ConcurrentHashSet(IEnumerable<T> values, IEqualityComparer<T>? comparer = null)
|
|
||||||
=> _backingStore = new(values.Select(x => new KeyValuePair<T, bool>(x, true)), comparer);
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
=> _backingStore.Keys.GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
=> GetEnumerator();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds the specified item to the <see cref="ConcurrentHashSet{T}" />.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">The item to add.</param>
|
|
||||||
/// <returns>
|
|
||||||
/// true if the items was added to the <see cref="ConcurrentHashSet{T}" />
|
|
||||||
/// successfully; false if it already exists.
|
|
||||||
/// </returns>
|
|
||||||
/// <exception cref="T:System.OverflowException">
|
|
||||||
/// The <see cref="ConcurrentHashSet{T}" />
|
|
||||||
/// contains too many items.
|
|
||||||
/// </exception>
|
|
||||||
public bool Add(T item)
|
|
||||||
=> _backingStore.TryAdd(item, true);
|
|
||||||
|
|
||||||
void ICollection<T>.Add(T item)
|
|
||||||
=> Add(item);
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
=> _backingStore.Clear();
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
=> _backingStore.ContainsKey(item);
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(array);
|
|
||||||
|
|
||||||
if (arrayIndex < 0)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
|
||||||
|
|
||||||
if (arrayIndex >= array.Length)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(arrayIndex));
|
|
||||||
|
|
||||||
CopyToInternal(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void CopyToInternal(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
var len = array.Length;
|
|
||||||
foreach (var (k, _) in _backingStore)
|
|
||||||
{
|
|
||||||
if (arrayIndex >= len)
|
|
||||||
throw new IndexOutOfRangeException(nameof(arrayIndex));
|
|
||||||
|
|
||||||
array[arrayIndex++] = k;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ICollection<T>.Remove(T item)
|
|
||||||
=> TryRemove(item);
|
|
||||||
|
|
||||||
public bool TryRemove(T item)
|
|
||||||
=> _backingStore.TryRemove(item, out _);
|
|
||||||
|
|
||||||
public void RemoveWhere(Func<T, bool> predicate)
|
|
||||||
{
|
|
||||||
foreach (var elem in this.Where(predicate))
|
|
||||||
TryRemove(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
=> _backingStore.Count;
|
|
||||||
|
|
||||||
public bool IsReadOnly
|
|
||||||
=> false;
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public interface IIndexed
|
|
||||||
{
|
|
||||||
int Index { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class IndexedCollection<T> : IList<T>
|
|
||||||
where T : class, IIndexed
|
|
||||||
{
|
|
||||||
public List<T> Source { get; }
|
|
||||||
|
|
||||||
public int Count
|
|
||||||
=> Source.Count;
|
|
||||||
|
|
||||||
public bool IsReadOnly
|
|
||||||
=> false;
|
|
||||||
|
|
||||||
public virtual T this[int index]
|
|
||||||
{
|
|
||||||
get => Source[index];
|
|
||||||
set
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
value.Index = index;
|
|
||||||
Source[index] = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly object _locker = new();
|
|
||||||
|
|
||||||
public IndexedCollection()
|
|
||||||
=> Source = new();
|
|
||||||
|
|
||||||
public IndexedCollection(IEnumerable<T> source)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
Source = source.OrderBy(x => x.Index).ToList();
|
|
||||||
UpdateIndexes();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int IndexOf(T item)
|
|
||||||
=> item?.Index ?? -1;
|
|
||||||
|
|
||||||
public IEnumerator<T> GetEnumerator()
|
|
||||||
=> Source.GetEnumerator();
|
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
=> Source.GetEnumerator();
|
|
||||||
|
|
||||||
public void Add(T item)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(item);
|
|
||||||
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
item.Index = Source.Count;
|
|
||||||
Source.Add(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Clear()
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
Source.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(T item)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
return Source.Contains(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(T[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
Source.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual bool Remove(T item)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
if (Source.Remove(item))
|
|
||||||
{
|
|
||||||
for (var i = 0; i < Source.Count; i++)
|
|
||||||
{
|
|
||||||
if (Source[i].Index != i)
|
|
||||||
Source[i].Index = i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void Insert(int index, T item)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
Source.Insert(index, item);
|
|
||||||
for (var i = index; i < Source.Count; i++)
|
|
||||||
Source[i].Index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void RemoveAt(int index)
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
Source.RemoveAt(index);
|
|
||||||
for (var i = index; i < Source.Count; i++)
|
|
||||||
Source[i].Index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UpdateIndexes()
|
|
||||||
{
|
|
||||||
lock (_locker)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < Source.Count; i++)
|
|
||||||
{
|
|
||||||
if (Source[i].Index != i)
|
|
||||||
Source[i].Index = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator List<T>(IndexedCollection<T> x)
|
|
||||||
=> x.Source;
|
|
||||||
|
|
||||||
public List<T> ToList()
|
|
||||||
=> Source.ToList();
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net6.0</TargetFramework>
|
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="NonBlocking" Version="2.1.0" />
|
|
||||||
|
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
|
@ -1,69 +0,0 @@
|
||||||
#nullable disable
|
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public class EllieRandom : Random
|
|
||||||
{
|
|
||||||
private readonly RandomNumberGenerator _rng;
|
|
||||||
|
|
||||||
public EllieRandom()
|
|
||||||
=> _rng = RandomNumberGenerator.Create();
|
|
||||||
|
|
||||||
public override int Next()
|
|
||||||
{
|
|
||||||
var bytes = new byte[sizeof(int)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
return Math.Abs(BitConverter.ToInt32(bytes, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Next(int maxValue)
|
|
||||||
{
|
|
||||||
if (maxValue <= 0)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(maxValue));
|
|
||||||
var bytes = new byte[sizeof(int)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
return Math.Abs(BitConverter.ToInt32(bytes, 0)) % maxValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override int Next(int minValue, int maxValue)
|
|
||||||
{
|
|
||||||
if (minValue > maxValue)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(maxValue));
|
|
||||||
if (minValue == maxValue)
|
|
||||||
return minValue;
|
|
||||||
var bytes = new byte[sizeof(int)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
var sign = Math.Sign(BitConverter.ToInt32(bytes, 0));
|
|
||||||
return (sign * BitConverter.ToInt32(bytes, 0) % (maxValue - minValue)) + minValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long NextLong(long minValue, long maxValue)
|
|
||||||
{
|
|
||||||
if (minValue > maxValue)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(maxValue));
|
|
||||||
if (minValue == maxValue)
|
|
||||||
return minValue;
|
|
||||||
var bytes = new byte[sizeof(long)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
var sign = Math.Sign(BitConverter.ToInt64(bytes, 0));
|
|
||||||
return (sign * BitConverter.ToInt64(bytes, 0) % (maxValue - minValue)) + minValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void NextBytes(byte[] buffer)
|
|
||||||
=> _rng.GetBytes(buffer);
|
|
||||||
|
|
||||||
protected override double Sample()
|
|
||||||
{
|
|
||||||
var bytes = new byte[sizeof(double)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
return Math.Abs((BitConverter.ToDouble(bytes, 0) / double.MaxValue) + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override double NextDouble()
|
|
||||||
{
|
|
||||||
var bytes = new byte[sizeof(double)];
|
|
||||||
_rng.GetBytes(bytes);
|
|
||||||
return BitConverter.ToDouble(bytes, 0);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
// made for expressions because they almost never get added
|
|
||||||
// and they get looped through constantly
|
|
||||||
public static class ArrayExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Create a new array from the old array + new element at the end
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="input">Input array</param>
|
|
||||||
/// <param name="added">Item to add to the end of the output array</param>
|
|
||||||
/// <typeparam name="T">Type of the array</typeparam>
|
|
||||||
/// <returns>A new array with the new element at the end</returns>
|
|
||||||
public static T[] With<T>(this T[] input, T added)
|
|
||||||
{
|
|
||||||
var newExprs = new T[input.Length + 1];
|
|
||||||
Array.Copy(input, 0, newExprs, 0, input.Length);
|
|
||||||
newExprs[input.Length] = added;
|
|
||||||
return newExprs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new array by applying the specified function to every element in the input array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="arr">Array to modify</param>
|
|
||||||
/// <param name="f">Function to apply</param>
|
|
||||||
/// <typeparam name="TIn">Orignal type of the elements in the array</typeparam>
|
|
||||||
/// <typeparam name="TOut">Output type of the elements of the array</typeparam>
|
|
||||||
/// <returns>New array with updated elements</returns>
|
|
||||||
public static TOut[] Map<TIn, TOut>(this TIn[] arr, Func<TIn, TOut> f)
|
|
||||||
=> Array.ConvertAll(arr, x => f(x));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a new array by applying the specified function to every element in the input array
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="col">Array to modify</param>
|
|
||||||
/// <param name="f">Function to apply</param>
|
|
||||||
/// <typeparam name="TIn">Orignal type of the elements in the array</typeparam>
|
|
||||||
/// <typeparam name="TOut">Output type of the elements of the array</typeparam>
|
|
||||||
/// <returns>New array with updated elements</returns>
|
|
||||||
public static TOut[] Map<TIn, TOut>(this IReadOnlyCollection<TIn> col, Func<TIn, TOut> f)
|
|
||||||
{
|
|
||||||
var toReturn = new TOut[col.Count];
|
|
||||||
|
|
||||||
var i = 0;
|
|
||||||
foreach (var item in col)
|
|
||||||
toReturn[i++] = f(item);
|
|
||||||
|
|
||||||
return toReturn;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
using System.Security.Cryptography;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public static class EnumerableExtensions
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Concatenates the members of a collection, using the specified separator between each member.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Collection to join</param>
|
|
||||||
/// <param name="separator">
|
|
||||||
/// The character to use as a separator. separator is included in the returned string only if
|
|
||||||
/// values has more than one element.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="func">Optional transformation to apply to each element before concatenation.</param>
|
|
||||||
/// <typeparam name="T">The type of the members of values.</typeparam>
|
|
||||||
/// <returns>
|
|
||||||
/// A string that consists of the members of values delimited by the separator character. -or- Empty if values has
|
|
||||||
/// no elements.
|
|
||||||
/// </returns>
|
|
||||||
public static string Join<T>(this IEnumerable<T> data, char separator, Func<T, string>? func = null)
|
|
||||||
=> string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Concatenates the members of a collection, using the specified separator between each member.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">Collection to join</param>
|
|
||||||
/// <param name="separator">
|
|
||||||
/// The string to use as a separator.separator is included in the returned string only if values
|
|
||||||
/// has more than one element.
|
|
||||||
/// </param>
|
|
||||||
/// <param name="func">Optional transformation to apply to each element before concatenation.</param>
|
|
||||||
/// <typeparam name="T">The type of the members of values.</typeparam>
|
|
||||||
/// <returns>
|
|
||||||
/// A string that consists of the members of values delimited by the separator character. -or- Empty if values has
|
|
||||||
/// no elements.
|
|
||||||
/// </returns>
|
|
||||||
public static string Join<T>(this IEnumerable<T> data, string separator, Func<T, string>? func = null)
|
|
||||||
=> string.Join(separator, data.Select(func ?? (x => x?.ToString() ?? string.Empty)));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Randomize element order by performing the Fisher-Yates shuffle
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">Item type</typeparam>
|
|
||||||
/// <param name="items">Items to shuffle</param>
|
|
||||||
public static IReadOnlyList<T> Shuffle<T>(this IEnumerable<T> items)
|
|
||||||
{
|
|
||||||
using var provider = RandomNumberGenerator.Create();
|
|
||||||
var list = items.ToList();
|
|
||||||
var n = list.Count;
|
|
||||||
while (n > 1)
|
|
||||||
{
|
|
||||||
var box = new byte[(n / byte.MaxValue) + 1];
|
|
||||||
int boxSum;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
provider.GetBytes(box);
|
|
||||||
boxSum = box.Sum(b => b);
|
|
||||||
} while (!(boxSum < n * (byte.MaxValue * box.Length / n)));
|
|
||||||
|
|
||||||
var k = boxSum % n;
|
|
||||||
n--;
|
|
||||||
(list[k], list[n]) = (list[n], list[k]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ConcurrentDictionary{TKey,TValue}" /> class
|
|
||||||
/// that contains elements copied from the specified <see cref="IEnumerable{T}" />
|
|
||||||
/// has the default concurrency level, has the default initial capacity,
|
|
||||||
/// and uses the default comparer for the key type.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="dict">
|
|
||||||
/// The <see cref="IEnumerable{T}" /> whose elements are copied to the new
|
|
||||||
/// <see cref="ConcurrentDictionary{TKey,TValue}" />.
|
|
||||||
/// </param>
|
|
||||||
/// <returns>A new instance of the <see cref="ConcurrentDictionary{TKey,TValue}" /> class</returns>
|
|
||||||
public static ConcurrentDictionary<TKey, TValue> ToConcurrent<TKey, TValue>(
|
|
||||||
this IEnumerable<KeyValuePair<TKey, TValue>> dict)
|
|
||||||
where TKey : notnull
|
|
||||||
=> new(dict);
|
|
||||||
|
|
||||||
public static IndexedCollection<T> ToIndexed<T>(this IEnumerable<T> enumerable)
|
|
||||||
where T : class, IIndexed
|
|
||||||
=> new(enumerable);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a task that will complete when all of the <see cref="Task{TResult}" /> objects in an enumerable
|
|
||||||
/// collection have completed
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tasks">The tasks to wait on for completion.</param>
|
|
||||||
/// <typeparam name="TResult">The type of the completed task.</typeparam>
|
|
||||||
/// <returns>A task that represents the completion of all of the supplied tasks.</returns>
|
|
||||||
public static Task<TResult[]> WhenAll<TResult>(this IEnumerable<Task<TResult>> tasks)
|
|
||||||
=> Task.WhenAll(tasks);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a task that will complete when all of the <see cref="Task" /> objects in an enumerable
|
|
||||||
/// collection have completed
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="tasks">The tasks to wait on for completion.</param>
|
|
||||||
/// <returns>A task that represents the completion of all of the supplied tasks.</returns>
|
|
||||||
public static Task WhenAll(this IEnumerable<Task> tasks)
|
|
||||||
=> Task.WhenAll(tasks);
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
using System.Net.Http.Headers;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public static class HttpClientExtensions
|
|
||||||
{
|
|
||||||
public static HttpClient AddFakeHeaders(this HttpClient http)
|
|
||||||
{
|
|
||||||
AddFakeHeaders(http.DefaultRequestHeaders);
|
|
||||||
return http;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AddFakeHeaders(this HttpHeaders dict)
|
|
||||||
{
|
|
||||||
dict.Clear();
|
|
||||||
dict.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8");
|
|
||||||
dict.Add("User-Agent",
|
|
||||||
"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/535.1 (KHTML, like Gecko) Chrome/14.0.835.202 Safari/535.1");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsImage(this HttpResponseMessage msg)
|
|
||||||
=> IsImage(msg, out _);
|
|
||||||
|
|
||||||
public static bool IsImage(this HttpResponseMessage msg, out string? mimeType)
|
|
||||||
{
|
|
||||||
mimeType = msg.Content.Headers.ContentType?.MediaType;
|
|
||||||
if (mimeType is "image/png" or "image/jpeg" or "image/gif")
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static long GetContentLength(this HttpResponseMessage msg)
|
|
||||||
=> msg.Content.Headers.ContentLength ?? long.MaxValue;
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public delegate TOut PipeFunc<TIn, out TOut>(in TIn a);
|
|
||||||
public delegate TOut PipeFunc<TIn1, TIn2, out TOut>(in TIn1 a, in TIn2 b);
|
|
||||||
|
|
||||||
public static class PipeExtensions
|
|
||||||
{
|
|
||||||
public static TOut Pipe<TIn, TOut>(this TIn a, Func<TIn, TOut> fn)
|
|
||||||
=> fn(a);
|
|
||||||
|
|
||||||
public static TOut Pipe<TIn, TOut>(this TIn a, PipeFunc<TIn, TOut> fn)
|
|
||||||
=> fn(a);
|
|
||||||
|
|
||||||
public static TOut Pipe<TIn1, TIn2, TOut>(this (TIn1, TIn2) a, PipeFunc<TIn1, TIn2, TOut> fn)
|
|
||||||
=> fn(a.Item1, a.Item2);
|
|
||||||
|
|
||||||
public static (TIn, TExtra) With<TIn, TExtra>(this TIn a, TExtra b)
|
|
||||||
=> (a, b);
|
|
||||||
|
|
||||||
public static async Task<TOut> Pipe<TIn, TOut>(this Task<TIn> a, Func<TIn, TOut> fn)
|
|
||||||
=> fn(await a);
|
|
||||||
}
|
|
|
@ -1 +0,0 @@
|
||||||
global using NonBlocking;
|
|
|
@ -1,36 +0,0 @@
|
||||||
using Serilog.Events;
|
|
||||||
using Serilog.Sinks.SystemConsole.Themes;
|
|
||||||
using System.Text;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public static class LogSetup
|
|
||||||
{
|
|
||||||
public static void SetupLogger(object source)
|
|
||||||
{
|
|
||||||
Log.Logger = new LoggerConfiguration().MinimumLevel.Override("Microsoft", LogEventLevel.Information)
|
|
||||||
.MinimumLevel.Override("System", LogEventLevel.Information)
|
|
||||||
.MinimumLevel.Override("Microsoft.AspNetCore", LogEventLevel.Warning)
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.WriteTo.Console(LogEventLevel.Information,
|
|
||||||
theme: GetTheme(),
|
|
||||||
outputTemplate:
|
|
||||||
"[{Timestamp:HH:mm:ss} {Level:u3}] | #{LogSource} | {Message:lj}{NewLine}{Exception}")
|
|
||||||
.Enrich.WithProperty("LogSource", source)
|
|
||||||
.CreateLogger();
|
|
||||||
|
|
||||||
Console.OutputEncoding = Encoding.UTF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ConsoleTheme GetTheme()
|
|
||||||
{
|
|
||||||
if (Environment.OSVersion.Platform == PlatformID.Unix)
|
|
||||||
return AnsiConsoleTheme.Code;
|
|
||||||
#if DEBUG
|
|
||||||
return AnsiConsoleTheme.Code;
|
|
||||||
#else
|
|
||||||
return ConsoleTheme.None;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public static class StandardConversions
|
|
||||||
{
|
|
||||||
public static double CelsiusToFahrenheit(double cel)
|
|
||||||
=> (cel * 1.8f) + 32;
|
|
||||||
}
|
|
|
@ -1,100 +0,0 @@
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
// needs proper invalid input check (character array input out of range)
|
|
||||||
// needs negative number support
|
|
||||||
// ReSharper disable once InconsistentNaming
|
|
||||||
#pragma warning disable IDE1006
|
|
||||||
public readonly struct kwum : IEquatable<kwum>
|
|
||||||
#pragma warning restore IDE1006
|
|
||||||
{
|
|
||||||
private const string VALID_CHARACTERS = "23456789abcdefghijkmnpqrstuvwxyz";
|
|
||||||
private readonly int _value;
|
|
||||||
|
|
||||||
public kwum(int num)
|
|
||||||
=> _value = num;
|
|
||||||
|
|
||||||
public kwum(in char c)
|
|
||||||
{
|
|
||||||
if (!IsValidChar(c))
|
|
||||||
throw new ArgumentException("Character needs to be a valid kwum character.", nameof(c));
|
|
||||||
|
|
||||||
_value = InternalCharToValue(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
public kwum(in ReadOnlySpan<char> input)
|
|
||||||
{
|
|
||||||
_value = 0;
|
|
||||||
for (var index = 0; index < input.Length; index++)
|
|
||||||
{
|
|
||||||
var c = input[index];
|
|
||||||
if (!IsValidChar(c))
|
|
||||||
throw new ArgumentException("All characters need to be a valid kwum characters.", nameof(input));
|
|
||||||
|
|
||||||
_value += VALID_CHARACTERS.IndexOf(c) * (int)Math.Pow(VALID_CHARACTERS.Length, input.Length - index - 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
|
||||||
private static int InternalCharToValue(in char c)
|
|
||||||
=> VALID_CHARACTERS.IndexOf(c);
|
|
||||||
|
|
||||||
public static bool TryParse(in ReadOnlySpan<char> input, out kwum value)
|
|
||||||
{
|
|
||||||
value = default;
|
|
||||||
foreach (var c in input)
|
|
||||||
{
|
|
||||||
if (!IsValidChar(c))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = new(input);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static kwum operator +(kwum left, kwum right)
|
|
||||||
=> new(left._value + right._value);
|
|
||||||
|
|
||||||
public static bool operator ==(kwum left, kwum right)
|
|
||||||
=> left._value == right._value;
|
|
||||||
|
|
||||||
public static bool operator !=(kwum left, kwum right)
|
|
||||||
=> !(left == right);
|
|
||||||
|
|
||||||
public static implicit operator long(kwum kwum)
|
|
||||||
=> kwum._value;
|
|
||||||
|
|
||||||
public static implicit operator int(kwum kwum)
|
|
||||||
=> kwum._value;
|
|
||||||
|
|
||||||
public static implicit operator kwum(int num)
|
|
||||||
=> new(num);
|
|
||||||
|
|
||||||
public static bool IsValidChar(char c)
|
|
||||||
=> VALID_CHARACTERS.Contains(c);
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
var count = VALID_CHARACTERS.Length;
|
|
||||||
var localValue = _value;
|
|
||||||
var arrSize = (int)Math.Log(localValue, count) + 1;
|
|
||||||
Span<char> chars = new char[arrSize];
|
|
||||||
while (localValue > 0)
|
|
||||||
{
|
|
||||||
localValue = Math.DivRem(localValue, count, out var rem);
|
|
||||||
chars[--arrSize] = VALID_CHARACTERS[rem];
|
|
||||||
}
|
|
||||||
|
|
||||||
return new(chars);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
=> obj is kwum kw && kw == this;
|
|
||||||
|
|
||||||
public bool Equals(kwum other)
|
|
||||||
=> other == this;
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
=> _value.GetHashCode();
|
|
||||||
}
|
|
|
@ -1,63 +0,0 @@
|
||||||
using System.Threading.Channels;
|
|
||||||
using Serilog;
|
|
||||||
|
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public sealed class QueueRunner
|
|
||||||
{
|
|
||||||
private readonly Channel<Func<Task>> _channel;
|
|
||||||
private readonly int _delayMs;
|
|
||||||
|
|
||||||
public QueueRunner(int delayMs = 0, int maxCapacity = -1)
|
|
||||||
{
|
|
||||||
if (delayMs < 0)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(delayMs));
|
|
||||||
|
|
||||||
_delayMs = delayMs;
|
|
||||||
_channel = maxCapacity switch
|
|
||||||
{
|
|
||||||
0 or < -1 => throw new ArgumentOutOfRangeException(nameof(maxCapacity)),
|
|
||||||
-1 => Channel.CreateUnbounded<Func<Task>>(new UnboundedChannelOptions()
|
|
||||||
{
|
|
||||||
SingleReader = true,
|
|
||||||
SingleWriter = false,
|
|
||||||
AllowSynchronousContinuations = true,
|
|
||||||
}),
|
|
||||||
_ => Channel.CreateBounded<Func<Task>>(new BoundedChannelOptions(maxCapacity)
|
|
||||||
{
|
|
||||||
Capacity = maxCapacity,
|
|
||||||
FullMode = BoundedChannelFullMode.DropOldest,
|
|
||||||
SingleReader = true,
|
|
||||||
SingleWriter = false,
|
|
||||||
AllowSynchronousContinuations = true
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task RunAsync(CancellationToken cancel = default)
|
|
||||||
{
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var func = await _channel.Reader.ReadAsync(cancel);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await func();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Warning(ex, "Exception executing a staggered func: {ErrorMessage}", ex.Message);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (_delayMs != 0)
|
|
||||||
{
|
|
||||||
await Task.Delay(_delayMs, cancel);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public ValueTask EnqueueAsync(Func<Task> action)
|
|
||||||
=> _channel.Writer.WriteAsync(action);
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public readonly struct ShmartBankAmount
|
|
||||||
{
|
|
||||||
public long Amount { get; }
|
|
||||||
public ShmartBankAmount(long amount)
|
|
||||||
{
|
|
||||||
Amount = amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator ShmartBankAmount(long num)
|
|
||||||
=> new(num);
|
|
||||||
|
|
||||||
public static implicit operator long(ShmartBankAmount num)
|
|
||||||
=> num.Amount;
|
|
||||||
|
|
||||||
public static implicit operator ShmartBankAmount(int num)
|
|
||||||
=> new(num);
|
|
||||||
}
|
|
|
@ -1,38 +0,0 @@
|
||||||
namespace Ellie.Common;
|
|
||||||
|
|
||||||
public readonly struct ShmartNumber : IEquatable<ShmartNumber>
|
|
||||||
{
|
|
||||||
public long Value { get; }
|
|
||||||
|
|
||||||
public ShmartNumber(long val)
|
|
||||||
{
|
|
||||||
Value = val;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static implicit operator ShmartNumber(long num)
|
|
||||||
=> new(num);
|
|
||||||
|
|
||||||
public static implicit operator long(ShmartNumber num)
|
|
||||||
=> num.Value;
|
|
||||||
|
|
||||||
public static implicit operator ShmartNumber(int num)
|
|
||||||
=> new(num);
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
=> Value.ToString();
|
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
=> obj is ShmartNumber sn && Equals(sn);
|
|
||||||
|
|
||||||
public bool Equals(ShmartNumber other)
|
|
||||||
=> other.Value == Value;
|
|
||||||
|
|
||||||
public override int GetHashCode()
|
|
||||||
=> Value.GetHashCode();
|
|
||||||
|
|
||||||
public static bool operator ==(ShmartNumber left, ShmartNumber right)
|
|
||||||
=> left.Equals(right);
|
|
||||||
|
|
||||||
public static bool operator !=(ShmartNumber left, ShmartNumber right)
|
|
||||||
=> !(left == right);
|
|
||||||
}
|
|
Loading…
Reference in a new issue