mirror of
				https://gitlab.com/Kwoth/nadekobot.git
				synced 2025-11-04 08:34:27 -05:00 
			
		
		
		
	Updated editorconfig to (mostly?) require braces around if/else statements, and applied the new formatting rules
This commit is contained in:
		@@ -6,7 +6,7 @@ public static class CommandNameLoadHelper
 | 
			
		||||
{
 | 
			
		||||
    private static readonly IDeserializer _deserializer = new Deserializer();
 | 
			
		||||
 | 
			
		||||
    private static readonly Lazy<Dictionary<string, string[]>> _lazyCommandAliases 
 | 
			
		||||
    private static readonly Lazy<Dictionary<string, string[]>> _lazyCommandAliases
 | 
			
		||||
        = new(() => LoadAliases());
 | 
			
		||||
 | 
			
		||||
    public static Dictionary<string, string[]> LoadAliases(string aliasesFilePath = "data/aliases.yml")
 | 
			
		||||
 
 | 
			
		||||
@@ -41,8 +41,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
                AcquireAllLocks(ref acquiredLocks);
 | 
			
		||||
 | 
			
		||||
                for (var i = 0; i < tables.CountPerLock.Length; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    if (tables.CountPerLock[i] != 0)
 | 
			
		||||
                        return false;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
@@ -84,7 +86,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            {
 | 
			
		||||
                AcquireAllLocks(ref acquiredLocks);
 | 
			
		||||
 | 
			
		||||
                for (var i = 0; i < tables.CountPerLock.Length; i++) count += tables.CountPerLock[i];
 | 
			
		||||
                for (var i = 0; i < tables.CountPerLock.Length; i++)
 | 
			
		||||
                    count += tables.CountPerLock[i];
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
@@ -209,7 +212,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
    public ConcurrentHashSet(IEnumerable<T> collection, IEqualityComparer<T> comparer)
 | 
			
		||||
        : this(comparer)
 | 
			
		||||
    {
 | 
			
		||||
        if (collection is null) throw new ArgumentNullException(nameof(collection));
 | 
			
		||||
        if (collection is null)
 | 
			
		||||
            throw new ArgumentNullException(nameof(collection));
 | 
			
		||||
 | 
			
		||||
        InitializeFromCollection(collection);
 | 
			
		||||
    }
 | 
			
		||||
@@ -244,8 +248,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
    public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer)
 | 
			
		||||
        : this(concurrencyLevel, DEFAULT_CAPACITY, false, comparer)
 | 
			
		||||
    {
 | 
			
		||||
        if (collection is null) throw new ArgumentNullException(nameof(collection));
 | 
			
		||||
        if (comparer is null) throw new ArgumentNullException(nameof(comparer));
 | 
			
		||||
        if (collection is null)
 | 
			
		||||
            throw new ArgumentNullException(nameof(collection));
 | 
			
		||||
        if (comparer is null)
 | 
			
		||||
            throw new ArgumentNullException(nameof(comparer));
 | 
			
		||||
 | 
			
		||||
        InitializeFromCollection(collection);
 | 
			
		||||
    }
 | 
			
		||||
@@ -285,15 +291,19 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
        bool growLockArray,
 | 
			
		||||
        IEqualityComparer<T> comparer)
 | 
			
		||||
    {
 | 
			
		||||
        if (concurrencyLevel < 1) throw new ArgumentOutOfRangeException(nameof(concurrencyLevel));
 | 
			
		||||
        if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity));
 | 
			
		||||
        if (concurrencyLevel < 1)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(concurrencyLevel));
 | 
			
		||||
        if (capacity < 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(capacity));
 | 
			
		||||
 | 
			
		||||
        // The capacity should be at least as large as the concurrency level. Otherwise, we would have locks that don't guard
 | 
			
		||||
        // any buckets.
 | 
			
		||||
        if (capacity < concurrencyLevel) capacity = concurrencyLevel;
 | 
			
		||||
        if (capacity < concurrencyLevel)
 | 
			
		||||
            capacity = concurrencyLevel;
 | 
			
		||||
 | 
			
		||||
        var locks = new object[concurrencyLevel];
 | 
			
		||||
        for (var i = 0; i < locks.Length; i++) locks[i] = new();
 | 
			
		||||
        for (var i = 0; i < locks.Length; i++)
 | 
			
		||||
            locks[i] = new();
 | 
			
		||||
 | 
			
		||||
        var countPerLock = new int[locks.Length];
 | 
			
		||||
        var buckets = new Node[capacity];
 | 
			
		||||
@@ -335,7 +345,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
        var hashcode = _comparer.GetHashCode(item!);
 | 
			
		||||
 | 
			
		||||
        // We must capture the _buckets field in a local variable. It is set to a new table on each table resize.
 | 
			
		||||
        var localTables = this.tables;
 | 
			
		||||
        var localTables = tables;
 | 
			
		||||
 | 
			
		||||
        var bucketNo = GetBucket(hashcode, localTables.Buckets.Length);
 | 
			
		||||
 | 
			
		||||
@@ -359,8 +369,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
    void ICollection<T>.CopyTo(T[] array, int arrayIndex)
 | 
			
		||||
    {
 | 
			
		||||
        if (array is null) throw new ArgumentNullException(nameof(array));
 | 
			
		||||
        if (arrayIndex < 0) throw new ArgumentOutOfRangeException(nameof(arrayIndex));
 | 
			
		||||
        if (array is null)
 | 
			
		||||
            throw new ArgumentNullException(nameof(array));
 | 
			
		||||
        if (arrayIndex < 0)
 | 
			
		||||
            throw new ArgumentOutOfRangeException(nameof(arrayIndex));
 | 
			
		||||
 | 
			
		||||
        var locksAcquired = 0;
 | 
			
		||||
        try
 | 
			
		||||
@@ -369,7 +381,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
            var count = 0;
 | 
			
		||||
 | 
			
		||||
            for (var i = 0; i < tables.Locks.Length && count >= 0; i++) count += tables.CountPerLock[i];
 | 
			
		||||
            for (var i = 0; i < tables.Locks.Length && count >= 0; i++)
 | 
			
		||||
                count += tables.CountPerLock[i];
 | 
			
		||||
 | 
			
		||||
            if (array.Length - count < arrayIndex || count < 0) //"count" itself or "count + arrayIndex" can overflow
 | 
			
		||||
                throw new ArgumentException(
 | 
			
		||||
@@ -444,20 +457,26 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
        var hashcode = _comparer.GetHashCode(item);
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            var localTables = this.tables;
 | 
			
		||||
            var localTables = tables;
 | 
			
		||||
 | 
			
		||||
            GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, localTables.Buckets.Length, localTables.Locks.Length);
 | 
			
		||||
            GetBucketAndLockNo(hashcode,
 | 
			
		||||
                out var bucketNo,
 | 
			
		||||
                out var lockNo,
 | 
			
		||||
                localTables.Buckets.Length,
 | 
			
		||||
                localTables.Locks.Length);
 | 
			
		||||
 | 
			
		||||
            lock (localTables.Locks[lockNo])
 | 
			
		||||
            {
 | 
			
		||||
                // If the table just got resized, we may not be holding the right lock, and must retry.
 | 
			
		||||
                // This should be a rare occurrence.
 | 
			
		||||
                if (localTables != this.tables) continue;
 | 
			
		||||
                if (localTables != tables)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                Node previous = null;
 | 
			
		||||
                for (var current = localTables.Buckets[bucketNo]; current is not null; current = current.Next)
 | 
			
		||||
                {
 | 
			
		||||
                    Debug.Assert((previous is null && current == localTables.Buckets[bucketNo]) || previous!.Next == current);
 | 
			
		||||
                    Debug.Assert((previous is null && current == localTables.Buckets[bucketNo])
 | 
			
		||||
                                 || previous!.Next == current);
 | 
			
		||||
 | 
			
		||||
                    if (hashcode == current.Hashcode && _comparer.Equals(current.Item, item))
 | 
			
		||||
                    {
 | 
			
		||||
@@ -480,17 +499,23 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
    private void InitializeFromCollection(IEnumerable<T> collection)
 | 
			
		||||
    {
 | 
			
		||||
        foreach (var item in collection) AddInternal(item, _comparer.GetHashCode(item), false);
 | 
			
		||||
        foreach (var item in collection)
 | 
			
		||||
            AddInternal(item, _comparer.GetHashCode(item), false);
 | 
			
		||||
 | 
			
		||||
        if (budget == 0) budget = tables.Buckets.Length / tables.Locks.Length;
 | 
			
		||||
        if (budget == 0)
 | 
			
		||||
            budget = tables.Buckets.Length / tables.Locks.Length;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private bool AddInternal(T item, int hashcode, bool acquireLock)
 | 
			
		||||
    {
 | 
			
		||||
        while (true)
 | 
			
		||||
        {
 | 
			
		||||
            var localTables = this.tables;
 | 
			
		||||
            GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, localTables.Buckets.Length, localTables.Locks.Length);
 | 
			
		||||
            var localTables = tables;
 | 
			
		||||
            GetBucketAndLockNo(hashcode,
 | 
			
		||||
                out var bucketNo,
 | 
			
		||||
                out var lockNo,
 | 
			
		||||
                localTables.Buckets.Length,
 | 
			
		||||
                localTables.Locks.Length);
 | 
			
		||||
 | 
			
		||||
            var resizeDesired = false;
 | 
			
		||||
            var lockTaken = false;
 | 
			
		||||
@@ -501,13 +526,15 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
                // If the table just got resized, we may not be holding the right lock, and must retry.
 | 
			
		||||
                // This should be a rare occurrence.
 | 
			
		||||
                if (localTables != this.tables) continue;
 | 
			
		||||
                if (localTables != tables)
 | 
			
		||||
                    continue;
 | 
			
		||||
 | 
			
		||||
                // Try to find this item in the bucket
 | 
			
		||||
                Node previous = null;
 | 
			
		||||
                for (var current = localTables.Buckets[bucketNo]; current is not null; current = current.Next)
 | 
			
		||||
                {
 | 
			
		||||
                    Debug.Assert((previous is null && current == localTables.Buckets[bucketNo]) || previous!.Next == current);
 | 
			
		||||
                    Debug.Assert((previous is null && current == localTables.Buckets[bucketNo])
 | 
			
		||||
                                 || previous!.Next == current);
 | 
			
		||||
                    if (hashcode == current.Hashcode && _comparer.Equals(current.Item, item))
 | 
			
		||||
                        return false;
 | 
			
		||||
 | 
			
		||||
@@ -526,7 +553,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
                // It is also possible that GrowTable will increase the budget but won't resize the bucket table.
 | 
			
		||||
                // That happens if the bucket table is found to be poorly utilized due to a bad hash function.
 | 
			
		||||
                //
 | 
			
		||||
                if (localTables.CountPerLock[lockNo] > budget) resizeDesired = true;
 | 
			
		||||
                if (localTables.CountPerLock[lockNo] > budget)
 | 
			
		||||
                    resizeDesired = true;
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
@@ -542,7 +570,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            // - As a result, it is possible that GrowTable will be called unnecessarily. But, GrowTable will obtain lock 0
 | 
			
		||||
            //   and then verify that the table we passed to it as the argument is still the current table.
 | 
			
		||||
            //
 | 
			
		||||
            if (resizeDesired) GrowTable(localTables);
 | 
			
		||||
            if (resizeDesired)
 | 
			
		||||
                GrowTable(localTables);
 | 
			
		||||
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
@@ -579,7 +608,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            AcquireLocks(0, 1, ref locksAcquired);
 | 
			
		||||
 | 
			
		||||
            // Make sure nobody resized the table while we were waiting for lock 0:
 | 
			
		||||
            if (localTables != this.tables)
 | 
			
		||||
            if (localTables != tables)
 | 
			
		||||
                // We assume that since the table reference is different, it was already resized (or the budget
 | 
			
		||||
                // was adjusted). If we ever decide to do table shrinking, or replace the table for other reasons,
 | 
			
		||||
                // we will have to revisit this logic.
 | 
			
		||||
@@ -587,7 +616,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
            // Compute the (approx.) total size. Use an Int64 accumulation variable to avoid an overflow.
 | 
			
		||||
            long approxCount = 0;
 | 
			
		||||
            for (var i = 0; i < localTables.CountPerLock.Length; i++) approxCount += localTables.CountPerLock[i];
 | 
			
		||||
            for (var i = 0; i < localTables.CountPerLock.Length; i++)
 | 
			
		||||
                approxCount += localTables.CountPerLock[i];
 | 
			
		||||
 | 
			
		||||
            //
 | 
			
		||||
            // If the bucket array is too empty, double the budget instead of resizing the table
 | 
			
		||||
@@ -595,7 +625,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            if (approxCount < localTables.Buckets.Length / 4)
 | 
			
		||||
            {
 | 
			
		||||
                budget = 2 * budget;
 | 
			
		||||
                if (budget < 0) budget = int.MaxValue;
 | 
			
		||||
                if (budget < 0)
 | 
			
		||||
                    budget = int.MaxValue;
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
@@ -613,11 +644,13 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
 | 
			
		||||
                    // Now, we only need to check odd integers, and find the first that is not divisible
 | 
			
		||||
                    // by 3, 5 or 7.
 | 
			
		||||
                    while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0) newLength += 2;
 | 
			
		||||
                    while (newLength % 3 == 0 || newLength % 5 == 0 || newLength % 7 == 0)
 | 
			
		||||
                        newLength += 2;
 | 
			
		||||
 | 
			
		||||
                    Debug.Assert(newLength % 2 != 0);
 | 
			
		||||
 | 
			
		||||
                    if (newLength > maxArrayLength) maximizeTableSize = true;
 | 
			
		||||
                    if (newLength > maxArrayLength)
 | 
			
		||||
                        maximizeTableSize = true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            catch (OverflowException)
 | 
			
		||||
@@ -647,7 +680,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            {
 | 
			
		||||
                newLocks = new object[localTables.Locks.Length * 2];
 | 
			
		||||
                Array.Copy(localTables.Locks, 0, newLocks, 0, localTables.Locks.Length);
 | 
			
		||||
                for (var i = localTables.Locks.Length; i < newLocks.Length; i++) newLocks[i] = new();
 | 
			
		||||
                for (var i = localTables.Locks.Length; i < newLocks.Length; i++)
 | 
			
		||||
                    newLocks[i] = new();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            var newBuckets = new Node[newLength];
 | 
			
		||||
@@ -681,7 +715,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            budget = Math.Max(1, newBuckets.Length / newLocks.Length);
 | 
			
		||||
 | 
			
		||||
            // Replace tables with the new versions
 | 
			
		||||
            this.tables = new(newBuckets, newLocks, newCountPerLock);
 | 
			
		||||
            tables = new(newBuckets, newLocks, newCountPerLock);
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
@@ -695,8 +729,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
        var elems = this.Where(predicate);
 | 
			
		||||
        var removed = 0;
 | 
			
		||||
        foreach (var elem in elems)
 | 
			
		||||
        {
 | 
			
		||||
            if (TryRemove(elem))
 | 
			
		||||
                removed++;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return removed;
 | 
			
		||||
    }
 | 
			
		||||
@@ -726,7 +762,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
            }
 | 
			
		||||
            finally
 | 
			
		||||
            {
 | 
			
		||||
                if (lockTaken) locksAcquired++;
 | 
			
		||||
                if (lockTaken)
 | 
			
		||||
                    locksAcquired++;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -735,7 +772,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
 | 
			
		||||
    {
 | 
			
		||||
        Debug.Assert(fromInclusive <= toExclusive);
 | 
			
		||||
 | 
			
		||||
        for (var i = fromInclusive; i < toExclusive; i++) Monitor.Exit(tables.Locks[i]);
 | 
			
		||||
        for (var i = fromInclusive; i < toExclusive; i++)
 | 
			
		||||
            Monitor.Exit(tables.Locks[i]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void CopyToItems(T[] array, int index)
 | 
			
		||||
 
 | 
			
		||||
@@ -5,7 +5,7 @@ using System.Collections;
 | 
			
		||||
namespace NadekoBot.Common.Collections;
 | 
			
		||||
 | 
			
		||||
public class IndexedCollection<T> : IList<T>
 | 
			
		||||
    where T : class, IIndexed 
 | 
			
		||||
    where T : class, IIndexed
 | 
			
		||||
{
 | 
			
		||||
    public List<T> Source { get; }
 | 
			
		||||
 | 
			
		||||
@@ -54,7 +54,7 @@ public class IndexedCollection<T> : IList<T>
 | 
			
		||||
    public void Add(T item)
 | 
			
		||||
    {
 | 
			
		||||
        ArgumentNullException.ThrowIfNull(item);
 | 
			
		||||
        
 | 
			
		||||
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
        {
 | 
			
		||||
            item.Index = Source.Count;
 | 
			
		||||
@@ -93,8 +93,10 @@ public class IndexedCollection<T> : IList<T>
 | 
			
		||||
            if (Source.Remove(item))
 | 
			
		||||
            {
 | 
			
		||||
                for (var i = 0; i < Source.Count; i++)
 | 
			
		||||
                {
 | 
			
		||||
                    if (Source[i].Index != i)
 | 
			
		||||
                        Source[i].Index = i;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
@@ -108,7 +110,8 @@ public class IndexedCollection<T> : IList<T>
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
        {
 | 
			
		||||
            Source.Insert(index, item);
 | 
			
		||||
            for (var i = index; i < Source.Count; i++) Source[i].Index = i;
 | 
			
		||||
            for (var i = index; i < Source.Count; i++)
 | 
			
		||||
                Source[i].Index = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -117,7 +120,8 @@ public class IndexedCollection<T> : IList<T>
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
        {
 | 
			
		||||
            Source.RemoveAt(index);
 | 
			
		||||
            for (var i = index; i < Source.Count; i++) Source[i].Index = i;
 | 
			
		||||
            for (var i = index; i < Source.Count; i++)
 | 
			
		||||
                Source[i].Index = i;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -126,8 +130,10 @@ public class IndexedCollection<T> : IList<T>
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
        {
 | 
			
		||||
            for (var i = 0; i < Source.Count; i++)
 | 
			
		||||
            {
 | 
			
		||||
                if (Source[i].Index != i)
 | 
			
		||||
                    Source[i].Index = i;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -66,7 +66,7 @@ Used for cryptocurrency related commands.")]
 | 
			
		||||
 | 
			
		||||
    [Comment(@"Api key used for Osu related commands. Obtain this key at https://osu.ppy.sh/p/api")]
 | 
			
		||||
    public string OsuApiKey { get; set; }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    [Comment(@"Optional Trovo client id.
 | 
			
		||||
You should only use this if Trovo notifications stopped working or you're getting ratelimit errors.")]
 | 
			
		||||
    public string TrovoClientId { get; set; }
 | 
			
		||||
@@ -96,7 +96,11 @@ Windows default
 | 
			
		||||
        BotListToken = string.Empty;
 | 
			
		||||
        CleverbotApiKey = string.Empty;
 | 
			
		||||
        RedisOptions = "localhost:6379,syncTimeout=30000,responseTimeout=30000,allowAdmin=true,password=";
 | 
			
		||||
        Db = new() { Type = "sqlite", ConnectionString = "Data Source=data/NadekoBot.db" };
 | 
			
		||||
        Db = new()
 | 
			
		||||
        {
 | 
			
		||||
            Type = "sqlite",
 | 
			
		||||
            ConnectionString = "Data Source=data/NadekoBot.db"
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        CoordinatorUrl = "http://localhost:3442";
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -45,8 +45,10 @@ public readonly struct kwum : IEquatable<kwum>
 | 
			
		||||
    {
 | 
			
		||||
        value = default;
 | 
			
		||||
        foreach (var c in input)
 | 
			
		||||
        {
 | 
			
		||||
            if (!IsValidChar(c))
 | 
			
		||||
                return false;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        value = new(input);
 | 
			
		||||
        return true;
 | 
			
		||||
 
 | 
			
		||||
@@ -11,7 +11,7 @@ namespace NadekoBot.Modules;
 | 
			
		||||
public abstract class NadekoModule : ModuleBase
 | 
			
		||||
{
 | 
			
		||||
    protected CultureInfo Culture { get; set; }
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    // Injected by Discord.net
 | 
			
		||||
    public IBotStrings Strings { get; set; }
 | 
			
		||||
    public CommandHandler _cmdHandler { get; set; }
 | 
			
		||||
@@ -88,7 +88,7 @@ public abstract class NadekoModule : ModuleBase
 | 
			
		||||
        }
 | 
			
		||||
        finally
 | 
			
		||||
        {
 | 
			
		||||
            _= Task.Run(() => msg.DeleteAsync());
 | 
			
		||||
            _ = Task.Run(() => msg.DeleteAsync());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -113,7 +113,7 @@ public abstract class NadekoModule : ModuleBase
 | 
			
		||||
 | 
			
		||||
        Task MessageReceived(SocketMessage arg)
 | 
			
		||||
        {
 | 
			
		||||
            _= Task.Run(() =>
 | 
			
		||||
            _ = Task.Run(() =>
 | 
			
		||||
            {
 | 
			
		||||
                if (arg is not SocketUserMessage userMsg
 | 
			
		||||
                    || userMsg.Channel is not ITextChannel
 | 
			
		||||
@@ -121,7 +121,8 @@ public abstract class NadekoModule : ModuleBase
 | 
			
		||||
                    || userMsg.Channel.Id != channelId)
 | 
			
		||||
                    return Task.CompletedTask;
 | 
			
		||||
 | 
			
		||||
                if (userInputTask.TrySetResult(arg.Content)) userMsg.DeleteAfter(1);
 | 
			
		||||
                if (userInputTask.TrySetResult(arg.Content))
 | 
			
		||||
                    userMsg.DeleteAfter(1);
 | 
			
		||||
 | 
			
		||||
                return Task.CompletedTask;
 | 
			
		||||
            });
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ public class EventPubSub : IPubSub
 | 
			
		||||
    private readonly object _locker = new();
 | 
			
		||||
 | 
			
		||||
    public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
 | 
			
		||||
        where TData: notnull
 | 
			
		||||
        where TData : notnull
 | 
			
		||||
    {
 | 
			
		||||
        Func<object, ValueTask> localAction = obj => action((TData)obj);
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
@@ -30,7 +30,7 @@ public class EventPubSub : IPubSub
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Task Pub<TData>(in TypedKey<TData> key, TData data)
 | 
			
		||||
        where TData: notnull
 | 
			
		||||
        where TData : notnull
 | 
			
		||||
    {
 | 
			
		||||
        lock (_locker)
 | 
			
		||||
        {
 | 
			
		||||
@@ -67,7 +67,8 @@ public class EventPubSub : IPubSub
 | 
			
		||||
                        // 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);
 | 
			
		||||
                        if (actions.Count == 0)
 | 
			
		||||
                            _actions.Remove(key.Key);
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,8 @@ namespace NadekoBot.Common;
 | 
			
		||||
public interface IPubSub
 | 
			
		||||
{
 | 
			
		||||
    public Task Pub<TData>(in TypedKey<TData> key, TData data)
 | 
			
		||||
        where TData: notnull;
 | 
			
		||||
        where TData : notnull;
 | 
			
		||||
 | 
			
		||||
    public Task Sub<TData>(in TypedKey<TData> key, Func<TData, ValueTask> action)
 | 
			
		||||
        where TData: notnull;
 | 
			
		||||
        where TData : notnull;
 | 
			
		||||
}
 | 
			
		||||
@@ -7,7 +7,11 @@ public class JsonSeria : ISeria
 | 
			
		||||
{
 | 
			
		||||
    private readonly JsonSerializerOptions _serializerOptions = new()
 | 
			
		||||
    {
 | 
			
		||||
        Converters = { new Rgba32Converter(), new CultureInfoConverter() }
 | 
			
		||||
        Converters =
 | 
			
		||||
        {
 | 
			
		||||
            new Rgba32Converter(),
 | 
			
		||||
            new CultureInfoConverter()
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    public byte[] Serialize<T>(T data)
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@ public sealed class RedisPubSub : IPubSub
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                var dataObj = _serializer.Deserialize<TData>(data);
 | 
			
		||||
                if(dataObj is not null)
 | 
			
		||||
                if (dataObj is not null)
 | 
			
		||||
                    await action(dataObj);
 | 
			
		||||
                else
 | 
			
		||||
                    Log.Warning("Publishing event {EventName} with a null value. This is not allowed",
 | 
			
		||||
 
 | 
			
		||||
@@ -63,10 +63,8 @@ public class ReplacementBuilder
 | 
			
		||||
            {
 | 
			
		||||
                var to = TimeZoneInfo.Local;
 | 
			
		||||
                if (g is not null)
 | 
			
		||||
                {
 | 
			
		||||
                    if (GuildTimezoneService.AllServices.TryGetValue(client.CurrentUser.Id, out var tz))
 | 
			
		||||
                        to = tz.GetTimeZoneOrDefault(g.Id) ?? TimeZoneInfo.Local;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return TimeZoneInfo.ConvertTime(DateTime.UtcNow, TimeZoneInfo.Utc, to).ToString("HH:mm ")
 | 
			
		||||
                       + to.StandardName.GetInitials();
 | 
			
		||||
 
 | 
			
		||||
@@ -20,10 +20,13 @@ public class Replacer
 | 
			
		||||
            return input;
 | 
			
		||||
 | 
			
		||||
        foreach (var (key, text) in _replacements)
 | 
			
		||||
        {
 | 
			
		||||
            if (input.Contains(key))
 | 
			
		||||
                input = input.Replace(key, text(), StringComparison.InvariantCulture);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        foreach (var item in _regex) input = item.Regex.Replace(input, m => item.Replacement(m));
 | 
			
		||||
        foreach (var item in _regex)
 | 
			
		||||
            input = item.Regex.Replace(input, m => item.Replacement(m));
 | 
			
		||||
 | 
			
		||||
        return input;
 | 
			
		||||
    }
 | 
			
		||||
@@ -53,7 +56,8 @@ public class Replacer
 | 
			
		||||
        if (embedData.Author is not null)
 | 
			
		||||
            newEmbedData.Author = new()
 | 
			
		||||
            {
 | 
			
		||||
                Name = Replace(embedData.Author.Name), IconUrl = Replace(embedData.Author.IconUrl)
 | 
			
		||||
                Name = Replace(embedData.Author.Name),
 | 
			
		||||
                IconUrl = Replace(embedData.Author.IconUrl)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        if (embedData.Fields is not null)
 | 
			
		||||
@@ -63,7 +67,9 @@ public class Replacer
 | 
			
		||||
            {
 | 
			
		||||
                var newF = new SmartTextEmbedField
 | 
			
		||||
                {
 | 
			
		||||
                    Name = Replace(f.Name), Value = Replace(f.Value), Inline = f.Inline
 | 
			
		||||
                    Name = Replace(f.Name),
 | 
			
		||||
                    Value = Replace(f.Value),
 | 
			
		||||
                    Inline = f.Inline
 | 
			
		||||
                };
 | 
			
		||||
                fields.Add(newF);
 | 
			
		||||
            }
 | 
			
		||||
@@ -74,7 +80,8 @@ public class Replacer
 | 
			
		||||
        if (embedData.Footer is not null)
 | 
			
		||||
            newEmbedData.Footer = new()
 | 
			
		||||
            {
 | 
			
		||||
                Text = Replace(embedData.Footer.Text), IconUrl = Replace(embedData.Footer.IconUrl)
 | 
			
		||||
                Text = Replace(embedData.Footer.Text),
 | 
			
		||||
                IconUrl = Replace(embedData.Footer.IconUrl)
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
        newEmbedData.Color = embedData.Color;
 | 
			
		||||
 
 | 
			
		||||
@@ -36,16 +36,31 @@ public sealed record SmartEmbedText : SmartText
 | 
			
		||||
            Url = eb.Url,
 | 
			
		||||
            Thumbnail = eb.Thumbnail?.Url,
 | 
			
		||||
            Image = eb.Image?.Url,
 | 
			
		||||
            Author = eb.Author is { } ea ? new() { Name = ea.Name, Url = ea.Url, IconUrl = ea.IconUrl } : null,
 | 
			
		||||
            Footer = eb.Footer is { } ef ? new() { Text = ef.Text, IconUrl = ef.IconUrl } : null
 | 
			
		||||
            Author = eb.Author is { } ea
 | 
			
		||||
                ? new()
 | 
			
		||||
                {
 | 
			
		||||
                    Name = ea.Name,
 | 
			
		||||
                    Url = ea.Url,
 | 
			
		||||
                    IconUrl = ea.IconUrl
 | 
			
		||||
                }
 | 
			
		||||
                : null,
 | 
			
		||||
            Footer = eb.Footer is { } ef
 | 
			
		||||
                ? new()
 | 
			
		||||
                {
 | 
			
		||||
                    Text = ef.Text,
 | 
			
		||||
                    IconUrl = ef.IconUrl
 | 
			
		||||
                }
 | 
			
		||||
                : null
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (eb.Fields.Length > 0)
 | 
			
		||||
            set.Fields = eb.Fields.Select(field
 | 
			
		||||
                               => new SmartTextEmbedField
 | 
			
		||||
                                   {
 | 
			
		||||
                                       Inline = field.Inline, Name = field.Name, Value = field.Value
 | 
			
		||||
                                   })
 | 
			
		||||
                               {
 | 
			
		||||
                                   Inline = field.Inline,
 | 
			
		||||
                                   Name = field.Name,
 | 
			
		||||
                                   Value = field.Value
 | 
			
		||||
                               })
 | 
			
		||||
                           .ToArray();
 | 
			
		||||
 | 
			
		||||
        set.Color = eb.Color?.RawValue ?? 0;
 | 
			
		||||
@@ -91,8 +106,10 @@ public sealed record SmartEmbedText : SmartText
 | 
			
		||||
 | 
			
		||||
        if (Fields is not null)
 | 
			
		||||
            foreach (var f in Fields)
 | 
			
		||||
            {
 | 
			
		||||
                if (!string.IsNullOrWhiteSpace(f.Name) && !string.IsNullOrWhiteSpace(f.Value))
 | 
			
		||||
                    embed.AddField(f.Name, f.Value, f.Inline);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        return embed;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,10 @@ public abstract record SmartText
 | 
			
		||||
    public static SmartText operator +(SmartText text, string input)
 | 
			
		||||
        => text switch
 | 
			
		||||
        {
 | 
			
		||||
            SmartEmbedText set => set with { PlainText = set.PlainText + input },
 | 
			
		||||
            SmartEmbedText set => set with
 | 
			
		||||
            {
 | 
			
		||||
                PlainText = set.PlainText + input
 | 
			
		||||
            },
 | 
			
		||||
            SmartPlainText spt => new SmartPlainText(spt.Text + input),
 | 
			
		||||
            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
			
		||||
        };
 | 
			
		||||
@@ -22,7 +25,10 @@ public abstract record SmartText
 | 
			
		||||
    public static SmartText operator +(string input, SmartText text)
 | 
			
		||||
        => text switch
 | 
			
		||||
        {
 | 
			
		||||
            SmartEmbedText set => set with { PlainText = input + set.PlainText },
 | 
			
		||||
            SmartEmbedText set => set with
 | 
			
		||||
            {
 | 
			
		||||
                PlainText = input + set.PlainText
 | 
			
		||||
            },
 | 
			
		||||
            SmartPlainText spt => new SmartPlainText(input + spt.Text),
 | 
			
		||||
            _ => throw new ArgumentOutOfRangeException(nameof(text))
 | 
			
		||||
        };
 | 
			
		||||
@@ -41,7 +47,7 @@ public abstract record SmartText
 | 
			
		||||
 | 
			
		||||
            smartEmbedText.NormalizeFields();
 | 
			
		||||
 | 
			
		||||
            if (!smartEmbedText.IsValid) 
 | 
			
		||||
            if (!smartEmbedText.IsValid)
 | 
			
		||||
                return new SmartPlainText(input);
 | 
			
		||||
 | 
			
		||||
            return smartEmbedText;
 | 
			
		||||
 
 | 
			
		||||
@@ -16,7 +16,8 @@ public class PermissionAction
 | 
			
		||||
 | 
			
		||||
    public override bool Equals(object obj)
 | 
			
		||||
    {
 | 
			
		||||
        if (obj is null || GetType() != obj.GetType()) return false;
 | 
			
		||||
        if (obj is null || GetType() != obj.GetType())
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        return Value == ((PermissionAction)obj).Value;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,20 +18,23 @@ public class StoopidTime
 | 
			
		||||
    {
 | 
			
		||||
        var m = _regex.Match(input);
 | 
			
		||||
 | 
			
		||||
        if (m.Length == 0) throw new ArgumentException("Invalid string input format.");
 | 
			
		||||
        if (m.Length == 0)
 | 
			
		||||
            throw new ArgumentException("Invalid string input format.");
 | 
			
		||||
 | 
			
		||||
        var namesAndValues = new Dictionary<string, int>();
 | 
			
		||||
 | 
			
		||||
        foreach (var groupName in _regex.GetGroupNames())
 | 
			
		||||
        {
 | 
			
		||||
            if (groupName == "0") continue;
 | 
			
		||||
            if (groupName == "0")
 | 
			
		||||
                continue;
 | 
			
		||||
            if (!int.TryParse(m.Groups[groupName].Value, out var value))
 | 
			
		||||
            {
 | 
			
		||||
                namesAndValues[groupName] = 0;
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (value < 1) throw new ArgumentException($"Invalid {groupName} value.");
 | 
			
		||||
            if (value < 1)
 | 
			
		||||
                throw new ArgumentException($"Invalid {groupName} value.");
 | 
			
		||||
 | 
			
		||||
            namesAndValues[groupName] = value;
 | 
			
		||||
        }
 | 
			
		||||
@@ -40,8 +43,13 @@ public class StoopidTime
 | 
			
		||||
            namesAndValues["hours"],
 | 
			
		||||
            namesAndValues["minutes"],
 | 
			
		||||
            namesAndValues["seconds"]);
 | 
			
		||||
        if (ts > TimeSpan.FromDays(90)) throw new ArgumentException("Time is too long.");
 | 
			
		||||
        if (ts > TimeSpan.FromDays(90))
 | 
			
		||||
            throw new ArgumentException("Time is too long.");
 | 
			
		||||
 | 
			
		||||
        return new() { Input = input, Time = ts };
 | 
			
		||||
        return new()
 | 
			
		||||
        {
 | 
			
		||||
            Input = input,
 | 
			
		||||
            Time = ts
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -37,7 +37,10 @@ public sealed class ModuleOrCrTypeReader : NadekoTypeReader<ModuleOrCrInfo>
 | 
			
		||||
        if (module is null && input != "ACTUALEXPRESSIONS")
 | 
			
		||||
            return new(TypeReaderResult.FromError<ModuleOrCrInfo>(CommandError.ParseFailed, "No such module found."));
 | 
			
		||||
 | 
			
		||||
        return new(TypeReaderResult.FromSuccess(new ModuleOrCrInfo { Name = input }));
 | 
			
		||||
        return new(TypeReaderResult.FromSuccess(new ModuleOrCrInfo
 | 
			
		||||
        {
 | 
			
		||||
            Name = input
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,8 @@ public sealed class ShmartNumberTypeReader : NadekoTypeReader<ShmartNumber>
 | 
			
		||||
        }
 | 
			
		||||
        catch (Exception)
 | 
			
		||||
        {
 | 
			
		||||
            return ValueTask.FromResult(TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, $"Invalid input: {input}"));
 | 
			
		||||
            return ValueTask.FromResult(
 | 
			
		||||
                TypeReaderResult.FromError<ShmartNumber>(CommandError.ParseFailed, $"Invalid input: {input}"));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -21,7 +21,10 @@ public class MultilineScalarFlowStyleEmitter : ChainedEventEmitter
 | 
			
		||||
            {
 | 
			
		||||
                var isMultiLine = value.IndexOfAny(new[] { '\r', '\n', '\x85', '\x2028', '\x2029' }) >= 0;
 | 
			
		||||
                if (isMultiLine)
 | 
			
		||||
                    eventInfo = new(eventInfo.Source) { Style = ScalarStyle.Literal };
 | 
			
		||||
                    eventInfo = new(eventInfo.Source)
 | 
			
		||||
                    {
 | 
			
		||||
                        Style = ScalarStyle.Literal
 | 
			
		||||
                    };
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -18,14 +18,16 @@ public class YamlHelper
 | 
			
		||||
 | 
			
		||||
        foreach (var c in point)
 | 
			
		||||
        {
 | 
			
		||||
            if (!IsHex(c)) return point;
 | 
			
		||||
            if (!IsHex(c))
 | 
			
		||||
                return point;
 | 
			
		||||
 | 
			
		||||
            character = (character << 4) + AsHex(c);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check the value and write the character.
 | 
			
		||||
 | 
			
		||||
        if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF) return point;
 | 
			
		||||
        if (character is (>= 0xD800 and <= 0xDFFF) or > 0x10FFFF)
 | 
			
		||||
            return point;
 | 
			
		||||
 | 
			
		||||
        return char.ConvertFromUtf32(character);
 | 
			
		||||
    }
 | 
			
		||||
@@ -35,9 +37,11 @@ public class YamlHelper
 | 
			
		||||
 | 
			
		||||
    public static int AsHex(char c)
 | 
			
		||||
    {
 | 
			
		||||
        if (c <= '9') return c - '0';
 | 
			
		||||
        if (c <= '9')
 | 
			
		||||
            return c - '0';
 | 
			
		||||
 | 
			
		||||
        if (c <= 'F') return c - 'A' + 10;
 | 
			
		||||
        if (c <= 'F')
 | 
			
		||||
            return c - 'A' + 10;
 | 
			
		||||
 | 
			
		||||
        return c - 'a' + 10;
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user