mirror of
https://gitlab.com/Kwoth/nadekobot.git
synced 2025-09-10 17:28:27 -04:00
Fixed around 140 wrong namings and other refactorings which were marked as warnings
This commit is contained in:
@@ -12,9 +12,7 @@ namespace NadekoBot.Coordinator
|
|||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
public CoordStartup(IConfiguration config)
|
public CoordStartup(IConfiguration config)
|
||||||
{
|
=> Configuration = config;
|
||||||
Configuration = config;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
|
@@ -6,7 +6,6 @@ using System.Linq;
|
|||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using YamlDotNet.Serialization;
|
using YamlDotNet.Serialization;
|
||||||
@@ -30,7 +29,7 @@ namespace NadekoBot.Coordinator
|
|||||||
private readonly Random _rng;
|
private readonly Random _rng;
|
||||||
private bool _gracefulImminent;
|
private bool _gracefulImminent;
|
||||||
|
|
||||||
public CoordinatorRunner(IConfiguration configuration)
|
public CoordinatorRunner()
|
||||||
{
|
{
|
||||||
_serializer = new();
|
_serializer = new();
|
||||||
_deserializer = new();
|
_deserializer = new();
|
||||||
@@ -91,7 +90,7 @@ namespace NadekoBot.Coordinator
|
|||||||
var shardIds = Enumerable.Range(0, 1) // shard 0 is always first
|
var shardIds = Enumerable.Range(0, 1) // shard 0 is always first
|
||||||
.Append((int)((117523346618318850 >> 22) % _config.TotalShards)) // then nadeko server shard
|
.Append((int)((117523346618318850 >> 22) % _config.TotalShards)) // then nadeko server shard
|
||||||
.Concat(Enumerable.Range(1, _config.TotalShards - 1)
|
.Concat(Enumerable.Range(1, _config.TotalShards - 1)
|
||||||
.OrderBy(x => _rng.Next())) // then all other shards in a random order
|
.OrderBy(_ => _rng.Next())) // then all other shards in a random order
|
||||||
.Distinct()
|
.Distinct()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@@ -191,8 +190,7 @@ namespace NadekoBot.Coordinator
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Process StartShardProcess(int shardId)
|
private Process StartShardProcess(int shardId)
|
||||||
{
|
=> Process.Start(new ProcessStartInfo()
|
||||||
return Process.Start(new ProcessStartInfo()
|
|
||||||
{
|
{
|
||||||
FileName = _config.ShardStartCommand,
|
FileName = _config.ShardStartCommand,
|
||||||
Arguments = string.Format(_config.ShardStartArgs,
|
Arguments = string.Format(_config.ShardStartArgs,
|
||||||
@@ -205,7 +203,6 @@ namespace NadekoBot.Coordinator
|
|||||||
// CreateNoWindow = true,
|
// CreateNoWindow = true,
|
||||||
// UseShellExecute = false,
|
// UseShellExecute = false,
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public bool Heartbeat(int shardId, int guildCount, ConnState state)
|
public bool Heartbeat(int shardId, int guildCount, ConnState state)
|
||||||
{
|
{
|
||||||
@@ -239,7 +236,6 @@ namespace NadekoBot.Coordinator
|
|||||||
{
|
{
|
||||||
lock (locker)
|
lock (locker)
|
||||||
{
|
{
|
||||||
ref var toSave = ref _config;
|
|
||||||
SaveConfig(new Config(
|
SaveConfig(new Config(
|
||||||
totalShards,
|
totalShards,
|
||||||
_config.RecheckIntervalMs,
|
_config.RecheckIntervalMs,
|
||||||
@@ -284,7 +280,7 @@ namespace NadekoBot.Coordinator
|
|||||||
for (var shardId = 0; shardId < _shardStatuses.Length; shardId++)
|
for (var shardId = 0; shardId < _shardStatuses.Length; shardId++)
|
||||||
{
|
{
|
||||||
var status = _shardStatuses[shardId];
|
var status = _shardStatuses[shardId];
|
||||||
if (status.Process is Process p)
|
if (status.Process is { } p)
|
||||||
{
|
{
|
||||||
p.Kill();
|
p.Kill();
|
||||||
p.Dispose();
|
p.Dispose();
|
||||||
@@ -346,7 +342,7 @@ namespace NadekoBot.Coordinator
|
|||||||
|
|
||||||
if (savedState.StatusObjects.Count != _config.TotalShards)
|
if (savedState.StatusObjects.Count != _config.TotalShards)
|
||||||
{
|
{
|
||||||
Log.Error("Unable to restore old state because shard count doesn't match.");
|
Log.Error("Unable to restore old state because shard count doesn't match");
|
||||||
File.Move(GRACEFUL_STATE_PATH, GRACEFUL_STATE_BACKUP_PATH, overwrite: true);
|
File.Move(GRACEFUL_STATE_PATH, GRACEFUL_STATE_BACKUP_PATH, overwrite: true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -357,7 +353,7 @@ namespace NadekoBot.Coordinator
|
|||||||
{
|
{
|
||||||
var statusObj = savedState.StatusObjects[shardId];
|
var statusObj = savedState.StatusObjects[shardId];
|
||||||
Process p = null;
|
Process p = null;
|
||||||
if (statusObj.Pid is int pid)
|
if (statusObj.Pid is { } pid)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -365,7 +361,7 @@ namespace NadekoBot.Coordinator
|
|||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Warning(ex, $"Process for shard {shardId} is not runnning.");
|
Log.Warning(ex, "Process for shard {ShardId} is not runnning", shardId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -5,14 +5,12 @@ using Grpc.Core;
|
|||||||
|
|
||||||
namespace NadekoBot.Coordinator
|
namespace NadekoBot.Coordinator
|
||||||
{
|
{
|
||||||
public sealed class CoordinatorService : NadekoBot.Coordinator.Coordinator.CoordinatorBase
|
public sealed class CoordinatorService : Coordinator.CoordinatorBase
|
||||||
{
|
{
|
||||||
private readonly CoordinatorRunner _runner;
|
private readonly CoordinatorRunner _runner;
|
||||||
|
|
||||||
public CoordinatorService(CoordinatorRunner runner)
|
public CoordinatorService(CoordinatorRunner runner)
|
||||||
{
|
=> _runner = runner;
|
||||||
_runner = runner;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Task<HeartbeatReply> Heartbeat(HeartbeatRequest request, ServerCallContext context)
|
public override Task<HeartbeatReply> Heartbeat(HeartbeatRequest request, ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
@@ -1,6 +1,4 @@
|
|||||||
using System;
|
namespace NadekoBot.Coordinator
|
||||||
|
|
||||||
namespace NadekoBot.Coordinator
|
|
||||||
{
|
{
|
||||||
public class JsonStatusObject
|
public class JsonStatusObject
|
||||||
{
|
{
|
||||||
|
@@ -6,7 +6,6 @@ using Microsoft.CodeAnalysis;
|
|||||||
using Microsoft.CodeAnalysis.CSharp;
|
using Microsoft.CodeAnalysis.CSharp;
|
||||||
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
using Microsoft.CodeAnalysis.CSharp.Syntax;
|
||||||
using Microsoft.CodeAnalysis.Text;
|
using Microsoft.CodeAnalysis.Text;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -16,71 +15,69 @@ namespace Cloneable
|
|||||||
[Generator]
|
[Generator]
|
||||||
public class CloneableGenerator : ISourceGenerator
|
public class CloneableGenerator : ISourceGenerator
|
||||||
{
|
{
|
||||||
private const string PreventDeepCopyKeyString = "PreventDeepCopy";
|
private const string PREVENT_DEEP_COPY_KEY_STRING = "PreventDeepCopy";
|
||||||
private const string ExplicitDeclarationKeyString = "ExplicitDeclaration";
|
private const string EXPLICIT_DECLARATION_KEY_STRING = "ExplicitDeclaration";
|
||||||
|
|
||||||
private const string CloneableNamespace = "Cloneable";
|
private const string CLONEABLE_NAMESPACE = "Cloneable";
|
||||||
private const string CloneableAttributeString = "CloneableAttribute";
|
private const string CLONEABLE_ATTRIBUTE_STRING = "CloneableAttribute";
|
||||||
private const string CloneAttributeString = "CloneAttribute";
|
private const string CLONE_ATTRIBUTE_STRING = "CloneAttribute";
|
||||||
private const string IgnoreCloneAttributeString = "IgnoreCloneAttribute";
|
private const string IGNORE_CLONE_ATTRIBUTE_STRING = "IgnoreCloneAttribute";
|
||||||
|
|
||||||
private const string cloneableAttributeText = @"// <AutoGenerated/>
|
private const string CLONEABLE_ATTRIBUTE_TEXT = @"// <AutoGenerated/>
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace " + CloneableNamespace + @"
|
namespace " + CLONEABLE_NAMESPACE + @"
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, Inherited = true, AllowMultiple = false)]
|
||||||
public sealed class " + CloneableAttributeString + @" : Attribute
|
public sealed class " + CLONEABLE_ATTRIBUTE_STRING + @" : Attribute
|
||||||
{
|
{
|
||||||
public " + CloneableAttributeString + @"()
|
public " + CLONEABLE_ATTRIBUTE_STRING + @"()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool " + ExplicitDeclarationKeyString + @" { get; set; }
|
public bool " + EXPLICIT_DECLARATION_KEY_STRING + @" { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
private const string clonePropertyAttributeText = @"// <AutoGenerated/>
|
private const string CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// <AutoGenerated/>
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace " + CloneableNamespace + @"
|
namespace " + CLONEABLE_NAMESPACE + @"
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
||||||
public sealed class " + CloneAttributeString + @" : Attribute
|
public sealed class " + CLONE_ATTRIBUTE_STRING + @" : Attribute
|
||||||
{
|
{
|
||||||
public " + CloneAttributeString + @"()
|
public " + CLONE_ATTRIBUTE_STRING + @"()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool " + PreventDeepCopyKeyString + @" { get; set; }
|
public bool " + PREVENT_DEEP_COPY_KEY_STRING + @" { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
private const string ignoreClonePropertyAttributeText = @"// <AutoGenerated/>
|
private const string IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT = @"// <AutoGenerated/>
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace " + CloneableNamespace + @"
|
namespace " + CLONEABLE_NAMESPACE + @"
|
||||||
{
|
{
|
||||||
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
[AttributeUsage(AttributeTargets.Property, Inherited = true, AllowMultiple = false)]
|
||||||
public sealed class " + IgnoreCloneAttributeString + @" : Attribute
|
public sealed class " + IGNORE_CLONE_ATTRIBUTE_STRING + @" : Attribute
|
||||||
{
|
{
|
||||||
public " + IgnoreCloneAttributeString + @"()
|
public " + IGNORE_CLONE_ATTRIBUTE_STRING + @"()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
";
|
";
|
||||||
|
|
||||||
private INamedTypeSymbol? cloneableAttribute;
|
private INamedTypeSymbol? _cloneableAttribute;
|
||||||
private INamedTypeSymbol? ignoreCloneAttribute;
|
private INamedTypeSymbol? _ignoreCloneAttribute;
|
||||||
private INamedTypeSymbol? cloneAttribute;
|
private INamedTypeSymbol? _cloneAttribute;
|
||||||
|
|
||||||
public void Initialize(GeneratorInitializationContext context)
|
public void Initialize(GeneratorInitializationContext context)
|
||||||
{
|
=> context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
|
||||||
context.RegisterForSyntaxNotifications(() => new SyntaxReceiver());
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Execute(GeneratorExecutionContext context)
|
public void Execute(GeneratorExecutionContext context)
|
||||||
{
|
{
|
||||||
@@ -100,36 +97,36 @@ namespace " + CloneableNamespace + @"
|
|||||||
var classSymbols = GetClassSymbols(compilation, receiver);
|
var classSymbols = GetClassSymbols(compilation, receiver);
|
||||||
foreach (var classSymbol in classSymbols)
|
foreach (var classSymbol in classSymbols)
|
||||||
{
|
{
|
||||||
if (!classSymbol.TryGetAttribute(cloneableAttribute!, out var attributes))
|
if (!classSymbol.TryGetAttribute(_cloneableAttribute!, out var attributes))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var attribute = attributes.Single();
|
var attribute = attributes.Single();
|
||||||
var isExplicit = (bool?)attribute.NamedArguments.FirstOrDefault(e => e.Key.Equals(ExplicitDeclarationKeyString)).Value.Value ?? false;
|
var isExplicit = (bool?)attribute.NamedArguments.FirstOrDefault(e => e.Key.Equals(EXPLICIT_DECLARATION_KEY_STRING)).Value.Value ?? false;
|
||||||
context.AddSource($"{classSymbol.Name}_cloneable.g.cs", SourceText.From(CreateCloneableCode(classSymbol, isExplicit), Encoding.UTF8));
|
context.AddSource($"{classSymbol.Name}_cloneable.g.cs", SourceText.From(CreateCloneableCode(classSymbol, isExplicit), Encoding.UTF8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitAttributes(Compilation compilation)
|
private void InitAttributes(Compilation compilation)
|
||||||
{
|
{
|
||||||
cloneableAttribute = compilation.GetTypeByMetadataName($"{CloneableNamespace}.{CloneableAttributeString}")!;
|
_cloneableAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{CLONEABLE_ATTRIBUTE_STRING}")!;
|
||||||
cloneAttribute = compilation.GetTypeByMetadataName($"{CloneableNamespace}.{CloneAttributeString}")!;
|
_cloneAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{CLONE_ATTRIBUTE_STRING}")!;
|
||||||
ignoreCloneAttribute = compilation.GetTypeByMetadataName($"{CloneableNamespace}.{IgnoreCloneAttributeString}")!;
|
_ignoreCloneAttribute = compilation.GetTypeByMetadataName($"{CLONEABLE_NAMESPACE}.{IGNORE_CLONE_ATTRIBUTE_STRING}")!;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Compilation GetCompilation(GeneratorExecutionContext context)
|
private static Compilation GetCompilation(GeneratorExecutionContext context)
|
||||||
{
|
{
|
||||||
var options = context.Compilation.SyntaxTrees.First().Options as CSharpParseOptions;
|
var options = context.Compilation.SyntaxTrees.First().Options as CSharpParseOptions;
|
||||||
|
|
||||||
var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(cloneableAttributeText, Encoding.UTF8), options)).
|
var compilation = context.Compilation.AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(CLONEABLE_ATTRIBUTE_TEXT, Encoding.UTF8), options)).
|
||||||
AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(clonePropertyAttributeText, Encoding.UTF8), options)).
|
AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8), options)).
|
||||||
AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(ignoreClonePropertyAttributeText, Encoding.UTF8), options));
|
AddSyntaxTrees(CSharpSyntaxTree.ParseText(SourceText.From(IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8), options));
|
||||||
return compilation;
|
return compilation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateCloneableCode(INamedTypeSymbol classSymbol, bool isExplicit)
|
private string CreateCloneableCode(INamedTypeSymbol classSymbol, bool isExplicit)
|
||||||
{
|
{
|
||||||
string namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
string namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
|
||||||
var fieldAssignmentsCode = GenerateFieldAssignmentsCode(classSymbol, isExplicit);
|
var fieldAssignmentsCode = GenerateFieldAssignmentsCode(classSymbol, isExplicit).ToList();
|
||||||
var fieldAssignmentsCodeSafe = fieldAssignmentsCode.Select(x =>
|
var fieldAssignmentsCodeSafe = fieldAssignmentsCode.Select(x =>
|
||||||
{
|
{
|
||||||
if (x.isCloneable)
|
if (x.isCloneable)
|
||||||
@@ -187,9 +184,9 @@ namespace {namespaceName}
|
|||||||
{
|
{
|
||||||
var fieldNames = GetCloneableProperties(classSymbol, isExplicit);
|
var fieldNames = GetCloneableProperties(classSymbol, isExplicit);
|
||||||
|
|
||||||
var fieldAssignments = fieldNames.Select(field => IsFieldCloneable(field, classSymbol)).
|
var fieldAssignments = fieldNames.Select(field => IsFieldCloneable(field, classSymbol))
|
||||||
OrderBy(x => x.isCloneable).
|
.OrderBy(x => x.isCloneable)
|
||||||
Select(x => (GenerateAssignmentCode(x.item.Name, x.isCloneable), x.isCloneable));
|
.Select(x => (GenerateAssignmentCode(x.item.Name, x.isCloneable), x.isCloneable));
|
||||||
return fieldAssignments;
|
return fieldAssignments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,19 +207,17 @@ namespace {namespaceName}
|
|||||||
return (x, false);
|
return (x, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!x.Type.TryGetAttribute(cloneableAttribute!, out var attributes))
|
if (!x.Type.TryGetAttribute(_cloneableAttribute!, out var attributes))
|
||||||
{
|
{
|
||||||
return (x, false);
|
return (x, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
var preventDeepCopy = (bool?)attributes.Single().NamedArguments.FirstOrDefault(e => e.Key.Equals(PreventDeepCopyKeyString)).Value.Value ?? false;
|
var preventDeepCopy = (bool?)attributes.Single().NamedArguments.FirstOrDefault(e => e.Key.Equals(PREVENT_DEEP_COPY_KEY_STRING)).Value.Value ?? false;
|
||||||
return (item: x, !preventDeepCopy);
|
return (item: x, !preventDeepCopy);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetAccessModifier(INamedTypeSymbol classSymbol)
|
private string GetAccessModifier(INamedTypeSymbol classSymbol)
|
||||||
{
|
=> classSymbol.DeclaredAccessibility.ToString().ToLowerInvariant();
|
||||||
return classSymbol.DeclaredAccessibility.ToString().ToLowerInvariant();
|
|
||||||
}
|
|
||||||
|
|
||||||
private IEnumerable<IPropertySymbol> GetCloneableProperties(ITypeSymbol classSymbol, bool isExplicit)
|
private IEnumerable<IPropertySymbol> GetCloneableProperties(ITypeSymbol classSymbol, bool isExplicit)
|
||||||
{
|
{
|
||||||
@@ -231,18 +226,16 @@ namespace {namespaceName}
|
|||||||
x.CanBeReferencedByName);
|
x.CanBeReferencedByName);
|
||||||
if (isExplicit)
|
if (isExplicit)
|
||||||
{
|
{
|
||||||
return targetSymbolMembers.Where(x => x.HasAttribute(cloneAttribute!));
|
return targetSymbolMembers.Where(x => x.HasAttribute(_cloneAttribute!));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return targetSymbolMembers.Where(x => !x.HasAttribute(ignoreCloneAttribute!));
|
return targetSymbolMembers.Where(x => !x.HasAttribute(_ignoreCloneAttribute!));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IEnumerable<INamedTypeSymbol> GetClassSymbols(Compilation compilation, SyntaxReceiver receiver)
|
private static IEnumerable<INamedTypeSymbol> GetClassSymbols(Compilation compilation, SyntaxReceiver receiver)
|
||||||
{
|
=> receiver.CandidateClasses.Select(clazz => GetClassSymbol(compilation, clazz));
|
||||||
return receiver.CandidateClasses.Select(clazz => GetClassSymbol(compilation, clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static INamedTypeSymbol GetClassSymbol(Compilation compilation, ClassDeclarationSyntax clazz)
|
private static INamedTypeSymbol GetClassSymbol(Compilation compilation, ClassDeclarationSyntax clazz)
|
||||||
{
|
{
|
||||||
@@ -253,9 +246,9 @@ namespace {namespaceName}
|
|||||||
|
|
||||||
private static void InjectCloneableAttributes(GeneratorExecutionContext context)
|
private static void InjectCloneableAttributes(GeneratorExecutionContext context)
|
||||||
{
|
{
|
||||||
context.AddSource(CloneableAttributeString, SourceText.From(cloneableAttributeText, Encoding.UTF8));
|
context.AddSource(CLONEABLE_ATTRIBUTE_STRING, SourceText.From(CLONEABLE_ATTRIBUTE_TEXT, Encoding.UTF8));
|
||||||
context.AddSource(CloneAttributeString, SourceText.From(clonePropertyAttributeText, Encoding.UTF8));
|
context.AddSource(CLONE_ATTRIBUTE_STRING, SourceText.From(CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8));
|
||||||
context.AddSource(IgnoreCloneAttributeString, SourceText.From(ignoreClonePropertyAttributeText, Encoding.UTF8));
|
context.AddSource(IGNORE_CLONE_ATTRIBUTE_STRING, SourceText.From(IGNORE_CLONE_PROPERTY_ATTRIBUTE_TEXT, Encoding.UTF8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -18,9 +18,7 @@ namespace Cloneable
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType)
|
public static bool HasAttribute(this ISymbol symbol, INamedTypeSymbol attributeType)
|
||||||
{
|
=> symbol.GetAttributes()
|
||||||
return symbol.GetAttributes()
|
|
||||||
.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType));
|
.Any(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -76,14 +76,14 @@ public class CmdAttribute : System.Attribute
|
|||||||
var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
var compilationMethods = context.CompilationProvider.Combine(methods.Collect());
|
||||||
|
|
||||||
context.RegisterSourceOutput(compilationMethods,
|
context.RegisterSourceOutput(compilationMethods,
|
||||||
static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right!));
|
static (ctx, tuple) => RegisterAction(in ctx, tuple.Left, in tuple.Right));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void RegisterAction(in SourceProductionContext ctx,
|
private static void RegisterAction(in SourceProductionContext ctx,
|
||||||
Compilation comp,
|
Compilation comp,
|
||||||
in ImmutableArray<MethodDeclarationSyntax> methods)
|
in ImmutableArray<MethodDeclarationSyntax?> methods)
|
||||||
{
|
{
|
||||||
if (methods.IsDefaultOrEmpty)
|
if (methods is { IsDefaultOrEmpty: true })
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var models = GetModels(comp, methods, ctx.CancellationToken);
|
var models = GetModels(comp, methods, ctx.CancellationToken);
|
||||||
@@ -136,12 +136,17 @@ public class CmdAttribute : System.Attribute
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
private static IReadOnlyCollection<FileModel> GetModels(Compilation compilation,
|
||||||
in ImmutableArray<MethodDeclarationSyntax> methods,
|
in ImmutableArray<MethodDeclarationSyntax?> inputMethods,
|
||||||
CancellationToken cancel)
|
CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var models = new List<FileModel>();
|
var models = new List<FileModel>();
|
||||||
|
|
||||||
var methodModels = methods.Select(x => MethodDeclarationToMethodModel(compilation, x));
|
var methods = inputMethods
|
||||||
|
.Where(static x => x is not null)
|
||||||
|
.Distinct();
|
||||||
|
|
||||||
|
var methodModels = methods
|
||||||
|
.Select(x => MethodDeclarationToMethodModel(compilation, x!));
|
||||||
|
|
||||||
var groups = methodModels
|
var groups = methodModels
|
||||||
.GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
.GroupBy(static x => $"{x.Namespace}.{string.Join(".", x.Classes)}");
|
||||||
@@ -172,6 +177,7 @@ public class CmdAttribute : System.Attribute
|
|||||||
var semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
var semanticModel = comp.GetSemanticModel(decl.SyntaxTree);
|
||||||
var methodModel = new MethodModel(
|
var methodModel = new MethodModel(
|
||||||
@params: decl.ParameterList.Parameters
|
@params: decl.ParameterList.Parameters
|
||||||
|
.Where(p => p.Type is not null)
|
||||||
.Select(p =>
|
.Select(p =>
|
||||||
{
|
{
|
||||||
var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
var prefix = p.Modifiers.Any(static x => x.IsKind(SyntaxKind.ParamsKeyword))
|
||||||
@@ -180,8 +186,8 @@ public class CmdAttribute : System.Attribute
|
|||||||
|
|
||||||
var type = semanticModel
|
var type = semanticModel
|
||||||
.GetTypeInfo(p.Type!)
|
.GetTypeInfo(p.Type!)
|
||||||
.Type!
|
.Type
|
||||||
.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
?.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
|
||||||
|
|
||||||
|
|
||||||
var name = p.Identifier.Text;
|
var name = p.Identifier.Text;
|
||||||
|
@@ -40,7 +40,7 @@ namespace NadekoBot.Tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static string[] GetCommandMethodNames()
|
private static string[] GetCommandMethodNames()
|
||||||
=> typeof(NadekoBot.Bot).Assembly
|
=> typeof(Bot).Assembly
|
||||||
.GetExportedTypes()
|
.GetExportedTypes()
|
||||||
.Where(type => type.IsClass && !type.IsAbstract)
|
.Where(type => type.IsClass && !type.IsAbstract)
|
||||||
.Where(type => typeof(NadekoModule).IsAssignableFrom(type) // if its a top level module
|
.Where(type => typeof(NadekoModule).IsAssignableFrom(type) // if its a top level module
|
||||||
|
@@ -1,5 +1,3 @@
|
|||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using NadekoBot.Extensions;
|
using NadekoBot.Extensions;
|
||||||
@@ -14,9 +12,7 @@ namespace NadekoBot.Tests
|
|||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
=> _grouper = new GreetGrouper<int>();
|
||||||
_grouper = new GreetGrouper<int>();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void CreateTest()
|
public void CreateTest()
|
||||||
|
@@ -115,7 +115,7 @@ namespace NadekoBot.Tests
|
|||||||
[Test]
|
[Test]
|
||||||
public void ContainsTest()
|
public void ContainsTest()
|
||||||
{
|
{
|
||||||
var subCol = new ShopEntry[]
|
var subCol = new[]
|
||||||
{
|
{
|
||||||
new ShopEntry() { Id = 111 },
|
new ShopEntry() { Id = 111 },
|
||||||
new ShopEntry() { Id = 222 },
|
new ShopEntry() { Id = 222 },
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
using System.Linq;
|
using NadekoBot.Common;
|
||||||
using NadekoBot.Common;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace NadekoBot.Tests
|
namespace NadekoBot.Tests
|
||||||
|
@@ -9,10 +9,8 @@ namespace NadekoBot.Tests
|
|||||||
{
|
{
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
{
|
=> Console.OutputEncoding = Encoding.UTF8;
|
||||||
Console.OutputEncoding = Encoding.UTF8;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Utf8CodepointsToEmoji()
|
public void Utf8CodepointsToEmoji()
|
||||||
{
|
{
|
||||||
|
@@ -6,7 +6,6 @@ using Microsoft.AspNetCore.Authentication;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using NadekoBot.VotesApi.Controllers;
|
|
||||||
|
|
||||||
namespace NadekoBot.VotesApi
|
namespace NadekoBot.VotesApi
|
||||||
{
|
{
|
||||||
@@ -24,9 +23,7 @@ namespace NadekoBot.VotesApi
|
|||||||
ISystemClock clock,
|
ISystemClock clock,
|
||||||
IConfiguration conf)
|
IConfiguration conf)
|
||||||
: base(options, logger, encoder, clock)
|
: base(options, logger, encoder, clock)
|
||||||
{
|
=> _conf = conf;
|
||||||
_conf = conf;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
{
|
{
|
||||||
|
@@ -23,7 +23,7 @@
|
|||||||
public bool Weekend { get; set; }
|
public bool Weekend { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Query string params found on the /bot/:ID/vote page. Example: ?a=1&b=2.
|
/// Query string params found on the /bot/:ID/vote page. Example: ?a=1&b=2.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Query { get; set; }
|
public string Query { get; set; }
|
||||||
}
|
}
|
||||||
|
@@ -11,10 +11,10 @@ namespace NadekoBot.VotesApi.Controllers
|
|||||||
[Route("[controller]")]
|
[Route("[controller]")]
|
||||||
public class DiscordsController : ControllerBase
|
public class DiscordsController : ControllerBase
|
||||||
{
|
{
|
||||||
private readonly ILogger<TopGgController> _logger;
|
private readonly ILogger<DiscordsController> _logger;
|
||||||
private readonly IVotesCache _cache;
|
private readonly IVotesCache _cache;
|
||||||
|
|
||||||
public DiscordsController(ILogger<TopGgController> logger, IVotesCache cache)
|
public DiscordsController(ILogger<DiscordsController> logger, IVotesCache cache)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
@@ -26,7 +26,7 @@ namespace NadekoBot.VotesApi.Controllers
|
|||||||
{
|
{
|
||||||
var votes = await _cache.GetNewDiscordsVotesAsync();
|
var votes = await _cache.GetNewDiscordsVotesAsync();
|
||||||
if(votes.Count > 0)
|
if(votes.Count > 0)
|
||||||
_logger.LogInformation("Sending {NewDiscordsVotes} new discords votes.", votes.Count);
|
_logger.LogInformation("Sending {NewDiscordsVotes} new discords votes", votes.Count);
|
||||||
return votes;
|
return votes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ namespace NadekoBot.VotesApi.Controllers
|
|||||||
{
|
{
|
||||||
var votes = await _cache.GetNewTopGgVotesAsync();
|
var votes = await _cache.GetNewTopGgVotesAsync();
|
||||||
if(votes.Count > 0)
|
if(votes.Count > 0)
|
||||||
_logger.LogInformation("Sending {NewTopggVotes} new topgg votes.", votes.Count);
|
_logger.LogInformation("Sending {NewTopggVotes} new topgg votes", votes.Count);
|
||||||
|
|
||||||
return votes;
|
return votes;
|
||||||
}
|
}
|
||||||
|
@@ -1,8 +1,6 @@
|
|||||||
using System;
|
using System.Threading.Tasks;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
using Microsoft.AspNetCore.Authorization;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using NadekoBot.VotesApi.Services;
|
using NadekoBot.VotesApi.Services;
|
||||||
|
|
||||||
@@ -13,13 +11,11 @@ namespace NadekoBot.VotesApi.Controllers
|
|||||||
{
|
{
|
||||||
private readonly ILogger<WebhookController> _logger;
|
private readonly ILogger<WebhookController> _logger;
|
||||||
private readonly IVotesCache _votesCache;
|
private readonly IVotesCache _votesCache;
|
||||||
private readonly IConfiguration _conf;
|
|
||||||
|
|
||||||
public WebhookController(ILogger<WebhookController> logger, IVotesCache votesCache, IConfiguration conf)
|
public WebhookController(ILogger<WebhookController> logger, IVotesCache votesCache)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_votesCache = votesCache;
|
_votesCache = votesCache;
|
||||||
_conf = conf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[HttpPost("/discordswebhook")]
|
[HttpPost("/discordswebhook")]
|
||||||
|
@@ -1,23 +1,9 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
using Microsoft.Extensions.Configuration;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Logging;
|
using NadekoBot.VotesApi;
|
||||||
|
|
||||||
namespace NadekoBot.VotesApi
|
CreateHostBuilder(args).Build().Run();
|
||||||
{
|
|
||||||
public class Program
|
|
||||||
{
|
|
||||||
public static void Main(string[] args)
|
|
||||||
{
|
|
||||||
CreateHostBuilder(args).Build().Run();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IHostBuilder CreateHostBuilder(string[] args) =>
|
static IHostBuilder CreateHostBuilder(string[] args) =>
|
||||||
Host.CreateDefaultBuilder(args)
|
Host.CreateDefaultBuilder(args)
|
||||||
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
|
.ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
|
||||||
}
|
|
||||||
}
|
|
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
@@ -10,37 +9,33 @@ namespace NadekoBot.VotesApi.Services
|
|||||||
{
|
{
|
||||||
public class FileVotesCache : IVotesCache
|
public class FileVotesCache : IVotesCache
|
||||||
{
|
{
|
||||||
private const string statsFile = "store/stats.json";
|
// private const string STATS_FILE = "store/stats.json";
|
||||||
private const string topggFile = "store/topgg.json";
|
private const string TOPGG_FILE = "store/topgg.json";
|
||||||
private const string discordsFile = "store/discords.json";
|
private const string DISCORDS_FILE = "store/discords.json";
|
||||||
|
|
||||||
private readonly SemaphoreSlim locker = new SemaphoreSlim(1, 1);
|
private readonly SemaphoreSlim _locker = new SemaphoreSlim(1, 1);
|
||||||
|
|
||||||
public FileVotesCache()
|
public FileVotesCache()
|
||||||
{
|
{
|
||||||
if (!Directory.Exists("store"))
|
if (!Directory.Exists("store"))
|
||||||
Directory.CreateDirectory("store");
|
Directory.CreateDirectory("store");
|
||||||
|
|
||||||
if(!File.Exists(topggFile))
|
if(!File.Exists(TOPGG_FILE))
|
||||||
File.WriteAllText(topggFile, "[]");
|
File.WriteAllText(TOPGG_FILE, "[]");
|
||||||
|
|
||||||
if(!File.Exists(discordsFile))
|
if(!File.Exists(DISCORDS_FILE))
|
||||||
File.WriteAllText(discordsFile, "[]");
|
File.WriteAllText(DISCORDS_FILE, "[]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public ITask AddNewTopggVote(string userId)
|
public ITask AddNewTopggVote(string userId)
|
||||||
{
|
=> AddNewVote(TOPGG_FILE, userId);
|
||||||
return AddNewVote(topggFile, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ITask AddNewDiscordsVote(string userId)
|
public ITask AddNewDiscordsVote(string userId)
|
||||||
{
|
=> AddNewVote(DISCORDS_FILE, userId);
|
||||||
return AddNewVote(discordsFile, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async ITask AddNewVote(string file, string userId)
|
private async ITask AddNewVote(string file, string userId)
|
||||||
{
|
{
|
||||||
await locker.WaitAsync();
|
await _locker.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var votes = await GetVotesAsync(file);
|
var votes = await GetVotesAsync(file);
|
||||||
@@ -49,7 +44,7 @@ namespace NadekoBot.VotesApi.Services
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
locker.Release();
|
_locker.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,14 +61,14 @@ namespace NadekoBot.VotesApi.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
private ITask<List<Vote>> EvictTopggVotes()
|
private ITask<List<Vote>> EvictTopggVotes()
|
||||||
=> EvictVotes(topggFile);
|
=> EvictVotes(TOPGG_FILE);
|
||||||
|
|
||||||
private ITask<List<Vote>> EvictDiscordsVotes()
|
private ITask<List<Vote>> EvictDiscordsVotes()
|
||||||
=> EvictVotes(discordsFile);
|
=> EvictVotes(DISCORDS_FILE);
|
||||||
|
|
||||||
private async ITask<List<Vote>> EvictVotes(string file)
|
private async ITask<List<Vote>> EvictVotes(string file)
|
||||||
{
|
{
|
||||||
await locker.WaitAsync();
|
await _locker.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -91,7 +86,7 @@ namespace NadekoBot.VotesApi.Services
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
locker.Release();
|
_locker.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,19 +11,18 @@ namespace NadekoBot.VotesApi
|
|||||||
{
|
{
|
||||||
public class Startup
|
public class Startup
|
||||||
{
|
{
|
||||||
public Startup(IConfiguration configuration)
|
|
||||||
{
|
|
||||||
Configuration = configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IConfiguration Configuration { get; }
|
public IConfiguration Configuration { get; }
|
||||||
|
|
||||||
|
public Startup(IConfiguration configuration)
|
||||||
|
=> Configuration = configuration;
|
||||||
|
|
||||||
|
|
||||||
// This method gets called by the runtime. Use this method to add services to the container.
|
// This method gets called by the runtime. Use this method to add services to the container.
|
||||||
public void ConfigureServices(IServiceCollection services)
|
public void ConfigureServices(IServiceCollection services)
|
||||||
{
|
{
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
services.AddSingleton<IVotesCache, FileVotesCache>();
|
services.AddSingleton<IVotesCache, FileVotesCache>();
|
||||||
services.AddSwaggerGen(c =>
|
services.AddSwaggerGen(static c =>
|
||||||
{
|
{
|
||||||
c.SwaggerDoc("v1", new OpenApiInfo { Title = "NadekoBot.VotesApi", Version = "v1" });
|
c.SwaggerDoc("v1", new OpenApiInfo { Title = "NadekoBot.VotesApi", Version = "v1" });
|
||||||
});
|
});
|
||||||
@@ -36,13 +35,13 @@ namespace NadekoBot.VotesApi
|
|||||||
});
|
});
|
||||||
|
|
||||||
services
|
services
|
||||||
.AddAuthorization(opts =>
|
.AddAuthorization(static opts =>
|
||||||
{
|
{
|
||||||
opts.DefaultPolicy = new AuthorizationPolicyBuilder(AuthHandler.SchemeName)
|
opts.DefaultPolicy = new AuthorizationPolicyBuilder(AuthHandler.SchemeName)
|
||||||
.RequireAssertion(x => false)
|
.RequireAssertion(static _ => false)
|
||||||
.Build();
|
.Build();
|
||||||
opts.AddPolicy(Policies.DiscordsAuth, policy => policy.RequireClaim(AuthHandler.DiscordsClaim));
|
opts.AddPolicy(Policies.DiscordsAuth, static policy => policy.RequireClaim(AuthHandler.DiscordsClaim));
|
||||||
opts.AddPolicy(Policies.TopggAuth, policy => policy.RequireClaim(AuthHandler.TopggClaim));
|
opts.AddPolicy(Policies.TopggAuth, static policy => policy.RequireClaim(AuthHandler.TopggClaim));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ namespace NadekoBot.VotesApi
|
|||||||
{
|
{
|
||||||
app.UseDeveloperExceptionPage();
|
app.UseDeveloperExceptionPage();
|
||||||
app.UseSwagger();
|
app.UseSwagger();
|
||||||
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "NadekoBot.VotesApi v1"));
|
app.UseSwaggerUI(static c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "NadekoBot.VotesApi v1"));
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
app.UseHttpsRedirection();
|
||||||
@@ -63,7 +62,7 @@ namespace NadekoBot.VotesApi
|
|||||||
app.UseAuthentication();
|
app.UseAuthentication();
|
||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
|
app.UseEndpoints(static endpoints => { endpoints.MapControllers(); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -1,5 +1,3 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace NadekoBot.VotesApi
|
namespace NadekoBot.VotesApi
|
||||||
{
|
{
|
||||||
public class Vote
|
public class Vote
|
||||||
|
@@ -196,7 +196,7 @@ public sealed class Bot
|
|||||||
|
|
||||||
Task SetClientReady()
|
Task SetClientReady()
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
clientReady.TrySetResult(true);
|
clientReady.TrySetResult(true);
|
||||||
try
|
try
|
||||||
@@ -248,7 +248,7 @@ public sealed class Bot
|
|||||||
private Task Client_JoinedGuild(SocketGuild arg)
|
private Task Client_JoinedGuild(SocketGuild arg)
|
||||||
{
|
{
|
||||||
Log.Information("Joined server: {GuildName} [{GuildId}]", arg.Name, arg.Id);
|
Log.Information("Joined server: {GuildName} [{GuildId}]", arg.Name, arg.Id);
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
GuildConfig gc;
|
GuildConfig gc;
|
||||||
await using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
#nullable disable
|
#nullable disable
|
||||||
|
#pragma warning disable all
|
||||||
// License MIT
|
// License MIT
|
||||||
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
// Source: https://github.com/i3arnon/ConcurrentHashSet
|
||||||
|
|
||||||
@@ -17,8 +18,8 @@ namespace System.Collections.Generic;
|
|||||||
[DebuggerDisplay("Count = {Count}")]
|
[DebuggerDisplay("Count = {Count}")]
|
||||||
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T>
|
public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T>
|
||||||
{
|
{
|
||||||
private const int DefaultCapacity = 31;
|
private const int DEFAULT_CAPACITY = 31;
|
||||||
private const int MaxLockNumber = 1024;
|
private const int MAX_LOCK_NUMBER = 1024;
|
||||||
|
|
||||||
private static int DefaultConcurrencyLevel
|
private static int DefaultConcurrencyLevel
|
||||||
=> PlatformHelper.ProcessorCount;
|
=> PlatformHelper.ProcessorCount;
|
||||||
@@ -39,8 +40,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
{
|
{
|
||||||
AcquireAllLocks(ref acquiredLocks);
|
AcquireAllLocks(ref acquiredLocks);
|
||||||
|
|
||||||
for (var i = 0; i < _tables.CountPerLock.Length; i++)
|
for (var i = 0; i < tables.CountPerLock.Length; i++)
|
||||||
if (_tables.CountPerLock[i] != 0)
|
if (tables.CountPerLock[i] != 0)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
@@ -83,7 +84,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
{
|
{
|
||||||
AcquireAllLocks(ref acquiredLocks);
|
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
|
finally
|
||||||
{
|
{
|
||||||
@@ -97,8 +98,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
private readonly IEqualityComparer<T> _comparer;
|
private readonly IEqualityComparer<T> _comparer;
|
||||||
private readonly bool _growLockArray;
|
private readonly bool _growLockArray;
|
||||||
|
|
||||||
private int _budget;
|
private int budget;
|
||||||
private volatile Tables _tables;
|
private volatile Tables tables;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the
|
/// Initializes a new instance of the
|
||||||
@@ -108,7 +109,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
/// uses the default comparer for the item type.
|
/// uses the default comparer for the item type.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public ConcurrentHashSet()
|
public ConcurrentHashSet()
|
||||||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, EqualityComparer<T>.Default)
|
: this(DefaultConcurrencyLevel, DEFAULT_CAPACITY, true, EqualityComparer<T>.Default)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
/// </param>
|
/// </param>
|
||||||
/// <exception cref="T:System.ArgumentNullException"><paramref name="comparer" /> is a null reference.</exception>
|
/// <exception cref="T:System.ArgumentNullException"><paramref name="comparer" /> is a null reference.</exception>
|
||||||
public ConcurrentHashSet(IEqualityComparer<T> comparer)
|
public ConcurrentHashSet(IEqualityComparer<T> comparer)
|
||||||
: this(DefaultConcurrencyLevel, DefaultCapacity, true, comparer)
|
: this(DefaultConcurrencyLevel, DEFAULT_CAPACITY, true, comparer)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,7 +242,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
/// <paramref name="concurrencyLevel" /> is less than 1.
|
/// <paramref name="concurrencyLevel" /> is less than 1.
|
||||||
/// </exception>
|
/// </exception>
|
||||||
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer)
|
public ConcurrentHashSet(int concurrencyLevel, IEnumerable<T> collection, IEqualityComparer<T> comparer)
|
||||||
: this(concurrencyLevel, DefaultCapacity, false, comparer)
|
: this(concurrencyLevel, DEFAULT_CAPACITY, false, comparer)
|
||||||
{
|
{
|
||||||
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
if (collection is null) throw new ArgumentNullException(nameof(collection));
|
||||||
if (comparer is null) throw new ArgumentNullException(nameof(comparer));
|
if (comparer is null) throw new ArgumentNullException(nameof(comparer));
|
||||||
@@ -296,10 +297,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
|
|
||||||
var countPerLock = new int[locks.Length];
|
var countPerLock = new int[locks.Length];
|
||||||
var buckets = new Node[capacity];
|
var buckets = new Node[capacity];
|
||||||
_tables = new(buckets, locks, countPerLock);
|
tables = new(buckets, locks, countPerLock);
|
||||||
|
|
||||||
_growLockArray = growLockArray;
|
_growLockArray = growLockArray;
|
||||||
_budget = buckets.Length / locks.Length;
|
budget = buckets.Length / locks.Length;
|
||||||
_comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
|
_comparer = comparer ?? throw new ArgumentNullException(nameof(comparer));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,9 +314,9 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
{
|
{
|
||||||
AcquireAllLocks(ref locksAcquired);
|
AcquireAllLocks(ref locksAcquired);
|
||||||
|
|
||||||
var newTables = new Tables(new Node[DefaultCapacity], _tables.Locks, new int[_tables.CountPerLock.Length]);
|
var newTables = new Tables(new Node[DEFAULT_CAPACITY], tables.Locks, new int[tables.CountPerLock.Length]);
|
||||||
_tables = newTables;
|
tables = newTables;
|
||||||
_budget = Math.Max(1, newTables.Buckets.Length / newTables.Locks.Length);
|
budget = Math.Max(1, newTables.Buckets.Length / newTables.Locks.Length);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -334,7 +335,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
var hashcode = _comparer.GetHashCode(item);
|
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.
|
// We must capture the _buckets field in a local variable. It is set to a new table on each table resize.
|
||||||
var tables = _tables;
|
var tables = this.tables;
|
||||||
|
|
||||||
var bucketNo = GetBucket(hashcode, tables.Buckets.Length);
|
var bucketNo = GetBucket(hashcode, tables.Buckets.Length);
|
||||||
|
|
||||||
@@ -368,7 +369,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
|
|
||||||
var count = 0;
|
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
|
if (array.Length - count < arrayIndex || count < 0) //"count" itself or "count + arrayIndex" can overflow
|
||||||
throw new ArgumentException(
|
throw new ArgumentException(
|
||||||
@@ -403,7 +404,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
/// </remarks>
|
/// </remarks>
|
||||||
public IEnumerator<T> GetEnumerator()
|
public IEnumerator<T> GetEnumerator()
|
||||||
{
|
{
|
||||||
var buckets = _tables.Buckets;
|
var buckets = tables.Buckets;
|
||||||
|
|
||||||
for (var i = 0; i < buckets.Length; i++)
|
for (var i = 0; i < buckets.Length; i++)
|
||||||
{
|
{
|
||||||
@@ -443,7 +444,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
var hashcode = _comparer.GetHashCode(item);
|
var hashcode = _comparer.GetHashCode(item);
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var tables = _tables;
|
var tables = this.tables;
|
||||||
|
|
||||||
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
|
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
|
||||||
|
|
||||||
@@ -451,7 +452,7 @@ 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.
|
// If the table just got resized, we may not be holding the right lock, and must retry.
|
||||||
// This should be a rare occurrence.
|
// This should be a rare occurrence.
|
||||||
if (tables != _tables) continue;
|
if (tables != this.tables) continue;
|
||||||
|
|
||||||
Node previous = null;
|
Node previous = null;
|
||||||
for (var current = tables.Buckets[bucketNo]; current is not null; current = current.Next)
|
for (var current = tables.Buckets[bucketNo]; current is not null; current = current.Next)
|
||||||
@@ -481,14 +482,14 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
{
|
{
|
||||||
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)
|
private bool AddInternal(T item, int hashcode, bool acquireLock)
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
var tables = _tables;
|
var tables = this.tables;
|
||||||
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
|
GetBucketAndLockNo(hashcode, out var bucketNo, out var lockNo, tables.Buckets.Length, tables.Locks.Length);
|
||||||
|
|
||||||
var resizeDesired = false;
|
var resizeDesired = false;
|
||||||
@@ -500,7 +501,7 @@ 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.
|
// If the table just got resized, we may not be holding the right lock, and must retry.
|
||||||
// This should be a rare occurrence.
|
// This should be a rare occurrence.
|
||||||
if (tables != _tables) continue;
|
if (tables != this.tables) continue;
|
||||||
|
|
||||||
// Try to find this item in the bucket
|
// Try to find this item in the bucket
|
||||||
Node previous = null;
|
Node previous = null;
|
||||||
@@ -525,7 +526,7 @@ 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.
|
// 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.
|
// That happens if the bucket table is found to be poorly utilized due to a bad hash function.
|
||||||
//
|
//
|
||||||
if (tables.CountPerLock[lockNo] > _budget) resizeDesired = true;
|
if (tables.CountPerLock[lockNo] > budget) resizeDesired = true;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -578,7 +579,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
AcquireLocks(0, 1, ref locksAcquired);
|
AcquireLocks(0, 1, ref locksAcquired);
|
||||||
|
|
||||||
// Make sure nobody resized the table while we were waiting for lock 0:
|
// Make sure nobody resized the table while we were waiting for lock 0:
|
||||||
if (tables != _tables)
|
if (tables != this.tables)
|
||||||
// We assume that since the table reference is different, it was already resized (or the budget
|
// 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,
|
// was adjusted). If we ever decide to do table shrinking, or replace the table for other reasons,
|
||||||
// we will have to revisit this logic.
|
// we will have to revisit this logic.
|
||||||
@@ -593,8 +594,8 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
//
|
//
|
||||||
if (approxCount < tables.Buckets.Length / 4)
|
if (approxCount < tables.Buckets.Length / 4)
|
||||||
{
|
{
|
||||||
_budget = 2 * _budget;
|
budget = 2 * budget;
|
||||||
if (_budget < 0) _budget = int.MaxValue;
|
if (budget < 0) budget = int.MaxValue;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -633,7 +634,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
//
|
//
|
||||||
// (There is one special case that would allow GrowTable() to be called in the future:
|
// (There is one special case that would allow GrowTable() to be called in the future:
|
||||||
// calling Clear() on the ConcurrentHashSet will shrink the table and lower the budget.)
|
// calling Clear() on the ConcurrentHashSet will shrink the table and lower the budget.)
|
||||||
_budget = int.MaxValue;
|
budget = int.MaxValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now acquire all other locks for the table
|
// Now acquire all other locks for the table
|
||||||
@@ -642,7 +643,7 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
var newLocks = tables.Locks;
|
var newLocks = tables.Locks;
|
||||||
|
|
||||||
// Add more locks
|
// Add more locks
|
||||||
if (_growLockArray && tables.Locks.Length < MaxLockNumber)
|
if (_growLockArray && tables.Locks.Length < MAX_LOCK_NUMBER)
|
||||||
{
|
{
|
||||||
newLocks = new object[tables.Locks.Length * 2];
|
newLocks = new object[tables.Locks.Length * 2];
|
||||||
Array.Copy(tables.Locks, 0, newLocks, 0, tables.Locks.Length);
|
Array.Copy(tables.Locks, 0, newLocks, 0, tables.Locks.Length);
|
||||||
@@ -677,10 +678,10 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Adjust the budget
|
// Adjust the budget
|
||||||
_budget = Math.Max(1, newBuckets.Length / newLocks.Length);
|
budget = Math.Max(1, newBuckets.Length / newLocks.Length);
|
||||||
|
|
||||||
// Replace tables with the new versions
|
// Replace tables with the new versions
|
||||||
_tables = new(newBuckets, newLocks, newCountPerLock);
|
this.tables = new(newBuckets, newLocks, newCountPerLock);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -707,14 +708,14 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
|
|
||||||
// Now that we have lock 0, the _locks array will not change (i.e., grow),
|
// Now that we have lock 0, the _locks array will not change (i.e., grow),
|
||||||
// and so we can safely read _locks.Length.
|
// and so we can safely read _locks.Length.
|
||||||
AcquireLocks(1, _tables.Locks.Length, ref locksAcquired);
|
AcquireLocks(1, tables.Locks.Length, ref locksAcquired);
|
||||||
Debug.Assert(locksAcquired == _tables.Locks.Length);
|
Debug.Assert(locksAcquired == tables.Locks.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
|
private void AcquireLocks(int fromInclusive, int toExclusive, ref int locksAcquired)
|
||||||
{
|
{
|
||||||
Debug.Assert(fromInclusive <= toExclusive);
|
Debug.Assert(fromInclusive <= toExclusive);
|
||||||
var locks = _tables.Locks;
|
var locks = tables.Locks;
|
||||||
|
|
||||||
for (var i = fromInclusive; i < toExclusive; i++)
|
for (var i = fromInclusive; i < toExclusive; i++)
|
||||||
{
|
{
|
||||||
@@ -734,12 +735,12 @@ public sealed class ConcurrentHashSet<T> : IReadOnlyCollection<T>, ICollection<T
|
|||||||
{
|
{
|
||||||
Debug.Assert(fromInclusive <= toExclusive);
|
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)
|
private void CopyToItems(T[] array, int index)
|
||||||
{
|
{
|
||||||
var buckets = _tables.Buckets;
|
var buckets = tables.Buckets;
|
||||||
for (var i = 0; i < buckets.Length; i++)
|
for (var i = 0; i < buckets.Length; i++)
|
||||||
for (var current = buckets[i]; current is not null; current = current.Next)
|
for (var current = buckets[i]; current is not null; current = current.Next)
|
||||||
{
|
{
|
||||||
|
@@ -5,7 +5,7 @@ using System.Collections;
|
|||||||
namespace NadekoBot.Common.Collections;
|
namespace NadekoBot.Common.Collections;
|
||||||
|
|
||||||
public class IndexedCollection<T> : IList<T>
|
public class IndexedCollection<T> : IList<T>
|
||||||
where T : class, IIndexed
|
where T : class, IIndexed
|
||||||
{
|
{
|
||||||
public List<T> Source { get; }
|
public List<T> Source { get; }
|
||||||
|
|
||||||
@@ -53,6 +53,8 @@ public class IndexedCollection<T> : IList<T>
|
|||||||
|
|
||||||
public void Add(T item)
|
public void Add(T item)
|
||||||
{
|
{
|
||||||
|
ArgumentNullException.ThrowIfNull(item);
|
||||||
|
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
item.Index = Source.Count;
|
item.Index = Source.Count;
|
||||||
|
@@ -26,6 +26,6 @@ public enum LogType
|
|||||||
ChannelUpdated,
|
ChannelUpdated,
|
||||||
UserPresence,
|
UserPresence,
|
||||||
VoicePresence,
|
VoicePresence,
|
||||||
VoicePresenceTTS,
|
VoicePresenceTts,
|
||||||
UserMuted
|
UserMuted
|
||||||
}
|
}
|
@@ -86,7 +86,7 @@ public abstract class NadekoModule : ModuleBase
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() => msg.DeleteAsync());
|
_= Task.Run(() => msg.DeleteAsync());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ public abstract class NadekoModule : ModuleBase
|
|||||||
|
|
||||||
Task MessageReceived(SocketMessage arg)
|
Task MessageReceived(SocketMessage arg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (arg is not SocketUserMessage userMsg
|
if (arg is not SocketUserMessage userMsg
|
||||||
|| userMsg.Channel is not ITextChannel
|
|| userMsg.Channel is not ITextChannel
|
||||||
|
@@ -20,7 +20,6 @@ public class StoopidTime
|
|||||||
|
|
||||||
if (m.Length == 0) throw new ArgumentException("Invalid string input format.");
|
if (m.Length == 0) throw new ArgumentException("Invalid string input format.");
|
||||||
|
|
||||||
var output = string.Empty;
|
|
||||||
var namesAndValues = new Dictionary<string, int>();
|
var namesAndValues = new Dictionary<string, int>();
|
||||||
|
|
||||||
foreach (var groupName in _regex.GetGroupNames())
|
foreach (var groupName in _regex.GetGroupNames())
|
||||||
@@ -35,7 +34,6 @@ public class StoopidTime
|
|||||||
if (value < 1) throw new ArgumentException($"Invalid {groupName} value.");
|
if (value < 1) throw new ArgumentException($"Invalid {groupName} value.");
|
||||||
|
|
||||||
namesAndValues[groupName] = value;
|
namesAndValues[groupName] = value;
|
||||||
output += m.Groups[groupName].Value + " " + groupName + " ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var ts = new TimeSpan((30 * namesAndValues["months"]) + (7 * namesAndValues["weeks"]) + namesAndValues["days"],
|
var ts = new TimeSpan((30 * namesAndValues["months"]) + (7 * namesAndValues["weeks"]) + namesAndValues["days"],
|
||||||
|
@@ -7,59 +7,59 @@ namespace NadekoBot.Common.Yml;
|
|||||||
|
|
||||||
public class CommentGatheringTypeInspector : TypeInspectorSkeleton
|
public class CommentGatheringTypeInspector : TypeInspectorSkeleton
|
||||||
{
|
{
|
||||||
private readonly ITypeInspector innerTypeDescriptor;
|
private readonly ITypeInspector _innerTypeDescriptor;
|
||||||
|
|
||||||
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
|
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
|
||||||
=> this.innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor");
|
=> this._innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException("innerTypeDescriptor");
|
||||||
|
|
||||||
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
|
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
|
||||||
=> innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
|
=> _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
|
||||||
|
|
||||||
private sealed class CommentsPropertyDescriptor : IPropertyDescriptor
|
private sealed class CommentsPropertyDescriptor : IPropertyDescriptor
|
||||||
{
|
{
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
public Type Type
|
public Type Type
|
||||||
=> baseDescriptor.Type;
|
=> _baseDescriptor.Type;
|
||||||
|
|
||||||
public Type TypeOverride
|
public Type TypeOverride
|
||||||
{
|
{
|
||||||
get => baseDescriptor.TypeOverride;
|
get => _baseDescriptor.TypeOverride;
|
||||||
set => baseDescriptor.TypeOverride = value;
|
set => _baseDescriptor.TypeOverride = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int Order { get; set; }
|
public int Order { get; set; }
|
||||||
|
|
||||||
public ScalarStyle ScalarStyle
|
public ScalarStyle ScalarStyle
|
||||||
{
|
{
|
||||||
get => baseDescriptor.ScalarStyle;
|
get => _baseDescriptor.ScalarStyle;
|
||||||
set => baseDescriptor.ScalarStyle = value;
|
set => _baseDescriptor.ScalarStyle = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanWrite
|
public bool CanWrite
|
||||||
=> baseDescriptor.CanWrite;
|
=> _baseDescriptor.CanWrite;
|
||||||
|
|
||||||
private readonly IPropertyDescriptor baseDescriptor;
|
private readonly IPropertyDescriptor _baseDescriptor;
|
||||||
|
|
||||||
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
|
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
|
||||||
{
|
{
|
||||||
this.baseDescriptor = baseDescriptor;
|
this._baseDescriptor = baseDescriptor;
|
||||||
Name = baseDescriptor.Name;
|
Name = baseDescriptor.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(object target, object value)
|
public void Write(object target, object value)
|
||||||
=> baseDescriptor.Write(target, value);
|
=> _baseDescriptor.Write(target, value);
|
||||||
|
|
||||||
public T GetCustomAttribute<T>()
|
public T GetCustomAttribute<T>()
|
||||||
where T : Attribute
|
where T : Attribute
|
||||||
=> baseDescriptor.GetCustomAttribute<T>();
|
=> _baseDescriptor.GetCustomAttribute<T>();
|
||||||
|
|
||||||
public IObjectDescriptor Read(object target)
|
public IObjectDescriptor Read(object target)
|
||||||
{
|
{
|
||||||
var comment = baseDescriptor.GetCustomAttribute<CommentAttribute>();
|
var comment = _baseDescriptor.GetCustomAttribute<CommentAttribute>();
|
||||||
return comment is not null
|
return comment is not null
|
||||||
? new CommentsObjectDescriptor(baseDescriptor.Read(target), comment.Comment)
|
? new CommentsObjectDescriptor(_baseDescriptor.Read(target), comment.Comment)
|
||||||
: baseDescriptor.Read(target);
|
: _baseDescriptor.Read(target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -9,22 +9,22 @@ public sealed class CommentsObjectDescriptor : IObjectDescriptor
|
|||||||
public string Comment { get; }
|
public string Comment { get; }
|
||||||
|
|
||||||
public object Value
|
public object Value
|
||||||
=> innerDescriptor.Value;
|
=> _innerDescriptor.Value;
|
||||||
|
|
||||||
public Type Type
|
public Type Type
|
||||||
=> innerDescriptor.Type;
|
=> _innerDescriptor.Type;
|
||||||
|
|
||||||
public Type StaticType
|
public Type StaticType
|
||||||
=> innerDescriptor.StaticType;
|
=> _innerDescriptor.StaticType;
|
||||||
|
|
||||||
public ScalarStyle ScalarStyle
|
public ScalarStyle ScalarStyle
|
||||||
=> innerDescriptor.ScalarStyle;
|
=> _innerDescriptor.ScalarStyle;
|
||||||
|
|
||||||
private readonly IObjectDescriptor innerDescriptor;
|
private readonly IObjectDescriptor _innerDescriptor;
|
||||||
|
|
||||||
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
|
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
|
||||||
{
|
{
|
||||||
this.innerDescriptor = innerDescriptor;
|
this._innerDescriptor = innerDescriptor;
|
||||||
Comment = comment;
|
Comment = comment;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -17,6 +17,6 @@ public static class SelfAssignableRolesExtensions
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static IEnumerable<SelfAssignedRole> GetFromGuild(this DbSet<SelfAssignedRole> roles, ulong guildId)
|
public static IReadOnlyCollection<SelfAssignedRole> GetFromGuild(this DbSet<SelfAssignedRole> roles, ulong guildId)
|
||||||
=> roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray();
|
=> roles.AsQueryable().Where(s => s.GuildId == guildId).ToArray();
|
||||||
}
|
}
|
@@ -7,7 +7,7 @@ public class GCChannelId : DbEntity
|
|||||||
public ulong ChannelId { get; set; }
|
public ulong ChannelId { get; set; }
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public override bool Equals(object obj)
|
||||||
=> obj is GCChannelId gc ? gc.ChannelId == ChannelId : false;
|
=> obj is GCChannelId gc && gc.ChannelId == ChannelId;
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
=> ChannelId.GetHashCode();
|
=> ChannelId.GetHashCode();
|
||||||
|
@@ -87,8 +87,8 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
channels.Select(x =>
|
channels.Select(x =>
|
||||||
{
|
{
|
||||||
var ch = guild.GetChannel(x.ChannelId)?.ToString() ?? x.ChannelId.ToString();
|
var ch = guild.GetChannel(x.ChannelId)?.ToString() ?? x.ChannelId.ToString();
|
||||||
var prefix = x.State ? "✅ " : "❌ ";
|
var prefixSign = x.State ? "✅ " : "❌ ";
|
||||||
return prefix + ch;
|
return prefixSign + ch;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(str))
|
if (string.IsNullOrWhiteSpace(str))
|
||||||
@@ -319,7 +319,7 @@ public partial class Administration : NadekoModule<AdministrationService>
|
|||||||
}
|
}
|
||||||
else if (time.Time <= TimeSpan.FromDays(7))
|
else if (time.Time <= TimeSpan.FromDays(7))
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(time.Time);
|
await Task.Delay(time.Time);
|
||||||
await msg.DeleteAsync();
|
await msg.DeleteAsync();
|
||||||
|
@@ -41,7 +41,7 @@ public class AdministrationService : INService
|
|||||||
|
|
||||||
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
private Task DelMsgOnCmd_Handler(IUserMessage msg, CommandInfo cmd)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (msg.Channel is not SocketTextChannel channel)
|
if (msg.Channel is not SocketTextChannel channel)
|
||||||
return;
|
return;
|
||||||
|
@@ -63,7 +63,7 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifus()
|
public partial Task DeleteWaifus()
|
||||||
=> SqlExec(DangerousCommandsService.WaifusDeleteSql);
|
=> SqlExec(DangerousCommandsService.WAIFUS_DELETE_SQL);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
@@ -73,22 +73,22 @@ namespace NadekoBot.Modules.Administration
|
|||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteWaifu(ulong userId)
|
public partial Task DeleteWaifu(ulong userId)
|
||||||
=> InternalExecSql(DangerousCommandsService.WaifuDeleteSql, userId);
|
=> InternalExecSql(DangerousCommandsService.WAIFU_DELETE_SQL, userId);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteCurrency()
|
public partial Task DeleteCurrency()
|
||||||
=> SqlExec(DangerousCommandsService.CurrencyDeleteSql);
|
=> SqlExec(DangerousCommandsService.CURRENCY_DELETE_SQL);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeletePlaylists()
|
public partial Task DeletePlaylists()
|
||||||
=> SqlExec(DangerousCommandsService.MusicPlaylistDeleteSql);
|
=> SqlExec(DangerousCommandsService.MUSIC_PLAYLIST_DELETE_SQL);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public partial Task DeleteXp()
|
public partial Task DeleteXp()
|
||||||
=> SqlExec(DangerousCommandsService.XpDeleteSql);
|
=> SqlExec(DangerousCommandsService.XP_DELETE_SQL);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
|
@@ -8,22 +8,22 @@ namespace NadekoBot.Modules.Administration.Services;
|
|||||||
|
|
||||||
public class DangerousCommandsService : INService
|
public class DangerousCommandsService : INService
|
||||||
{
|
{
|
||||||
public const string WaifusDeleteSql = @"DELETE FROM WaifuUpdates;
|
public const string WAIFUS_DELETE_SQL = @"DELETE FROM WaifuUpdates;
|
||||||
DELETE FROM WaifuItem;
|
DELETE FROM WaifuItem;
|
||||||
DELETE FROM WaifuInfo;";
|
DELETE FROM WaifuInfo;";
|
||||||
|
|
||||||
public const string WaifuDeleteSql =
|
public const string WAIFU_DELETE_SQL =
|
||||||
@"DELETE FROM WaifuUpdates WHERE UserId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
@"DELETE FROM WaifuUpdates WHERE UserId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
||||||
DELETE FROM WaifuItem WHERE WaifuInfoId=(SELECT Id FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0}));
|
DELETE FROM WaifuItem WHERE WaifuInfoId=(SELECT Id FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0}));
|
||||||
UPDATE WaifuInfo SET ClaimerId=NULL WHERE ClaimerId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
UPDATE WaifuInfo SET ClaimerId=NULL WHERE ClaimerId=(SELECT Id FROM DiscordUser WHERE UserId={0});
|
||||||
DELETE FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0});";
|
DELETE FROM WaifuInfo WHERE WaifuId=(SELECT Id FROM DiscordUser WHERE UserId={0});";
|
||||||
|
|
||||||
public const string CurrencyDeleteSql =
|
public const string CURRENCY_DELETE_SQL =
|
||||||
"UPDATE DiscordUser SET CurrencyAmount=0; DELETE FROM CurrencyTransactions; DELETE FROM PlantedCurrency;";
|
"UPDATE DiscordUser SET CurrencyAmount=0; DELETE FROM CurrencyTransactions; DELETE FROM PlantedCurrency;";
|
||||||
|
|
||||||
public const string MusicPlaylistDeleteSql = "DELETE FROM MusicPlaylists;";
|
public const string MUSIC_PLAYLIST_DELETE_SQL = "DELETE FROM MusicPlaylists;";
|
||||||
|
|
||||||
public const string XpDeleteSql = @"DELETE FROM UserXpStats;
|
public const string XP_DELETE_SQL = @"DELETE FROM UserXpStats;
|
||||||
UPDATE DiscordUser
|
UPDATE DiscordUser
|
||||||
SET ClubId=NULL,
|
SET ClubId=NULL,
|
||||||
IsClubAdmin=0,
|
IsClubAdmin=0,
|
||||||
|
@@ -27,7 +27,7 @@ public class GameVoiceChannelService : INService
|
|||||||
|
|
||||||
private Task OnPresenceUpdate(SocketUser socketUser, SocketPresence before, SocketPresence after)
|
private Task OnPresenceUpdate(SocketUser socketUser, SocketPresence before, SocketPresence after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -83,7 +83,7 @@ public class GameVoiceChannelService : INService
|
|||||||
|
|
||||||
private Task OnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
private Task OnUserVoiceStateUpdated(SocketUser usr, SocketVoiceState oldState, SocketVoiceState newState)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -107,7 +107,7 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
|
|
||||||
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
private Task OnUserLeft(SocketGuild guild, SocketUser user)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -271,7 +271,7 @@ public class GreetService : INService, IReadyExecutor
|
|||||||
|
|
||||||
private Task OnUserJoined(IGuildUser user)
|
private Task OnUserJoined(IGuildUser user)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -31,7 +31,7 @@ public sealed class ImageOnlyChannelService : IEarlyBehavior
|
|||||||
var uow = _db.GetDbContext();
|
var uow = _db.GetDbContext();
|
||||||
_enabledOn = uow.ImageOnlyChannels.ToList()
|
_enabledOn = uow.ImageOnlyChannels.ToList()
|
||||||
.GroupBy(x => x.GuildId)
|
.GroupBy(x => x.GuildId)
|
||||||
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(x => x.ChannelId)))
|
.ToDictionary(x => x.Key, x => new ConcurrentHashSet<ulong>(x.Select(y => y.ChannelId)))
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
_ = Task.Run(DeleteQueueRunner);
|
_ = Task.Run(DeleteQueueRunner);
|
||||||
|
@@ -126,7 +126,7 @@ public class MuteService : INService
|
|||||||
if (string.IsNullOrWhiteSpace(reason))
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
_= Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
||||||
.WithDescription(
|
.WithDescription(
|
||||||
$"You've been muted in {user.Guild} server")
|
$"You've been muted in {user.Guild} server")
|
||||||
.AddField("Mute Type", type.ToString())
|
.AddField("Mute Type", type.ToString())
|
||||||
@@ -144,7 +144,7 @@ public class MuteService : INService
|
|||||||
if (string.IsNullOrWhiteSpace(reason))
|
if (string.IsNullOrWhiteSpace(reason))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var _ = Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
_= Task.Run(() => user.SendMessageAsync(embed: _eb.Create()
|
||||||
.WithDescription(
|
.WithDescription(
|
||||||
$"You've been unmuted in {user.Guild} server")
|
$"You've been unmuted in {user.Guild} server")
|
||||||
.AddField("Unmute Type", type.ToString())
|
.AddField("Unmute Type", type.ToString())
|
||||||
@@ -161,7 +161,7 @@ public class MuteService : INService
|
|||||||
|
|
||||||
if (muted is null || !muted.Contains(usr.Id))
|
if (muted is null || !muted.Contains(usr.Id))
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
var _ = Task.Run(() => MuteUser(usr, _client.CurrentUser, reason: "Sticky mute"));
|
_= Task.Run(() => MuteUser(usr, _client.CurrentUser, reason: "Sticky mute"));
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
@@ -417,6 +417,9 @@ public class MuteService : INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (roleId is null)
|
||||||
|
return;
|
||||||
|
|
||||||
RemoveTimerFromDb(guildId, userId, type);
|
RemoveTimerFromDb(guildId, userId, type);
|
||||||
StopTimer(guildId, userId, type);
|
StopTimer(guildId, userId, type);
|
||||||
var guild = _client.GetGuild(guildId);
|
var guild = _client.GetGuild(guildId);
|
||||||
|
@@ -20,36 +20,36 @@ public partial class Administration
|
|||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public partial Task Prefix(Set _, [Leftover] string prefix)
|
public partial Task Prefix(Set _, [Leftover] string newPrefix)
|
||||||
=> Prefix(prefix);
|
=> Prefix(newPrefix);
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[RequireContext(ContextType.Guild)]
|
[RequireContext(ContextType.Guild)]
|
||||||
[UserPerm(GuildPerm.Administrator)]
|
[UserPerm(GuildPerm.Administrator)]
|
||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task Prefix([Leftover] string prefix)
|
public async partial Task Prefix([Leftover] string toSet)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(prefix))
|
if (string.IsNullOrWhiteSpace(prefix))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var oldPrefix = base.prefix;
|
var oldPrefix = prefix;
|
||||||
var newPrefix = CmdHandler.SetPrefix(ctx.Guild, prefix);
|
var newPrefix = CmdHandler.SetPrefix(ctx.Guild, toSet);
|
||||||
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
await ReplyConfirmLocalizedAsync(strs.prefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Cmd]
|
[Cmd]
|
||||||
[OwnerOnly]
|
[OwnerOnly]
|
||||||
public async partial Task DefPrefix([Leftover] string prefix = null)
|
public async partial Task DefPrefix([Leftover] string toSet = null)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(prefix))
|
if (string.IsNullOrWhiteSpace(toSet))
|
||||||
{
|
{
|
||||||
await ReplyConfirmLocalizedAsync(strs.defprefix_current(CmdHandler.GetPrefix()));
|
await ReplyConfirmLocalizedAsync(strs.defprefix_current(CmdHandler.GetPrefix()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var oldPrefix = CmdHandler.GetPrefix();
|
var oldPrefix = CmdHandler.GetPrefix();
|
||||||
var newPrefix = CmdHandler.SetDefaultPrefix(prefix);
|
var newPrefix = CmdHandler.SetDefaultPrefix(toSet);
|
||||||
|
|
||||||
await ReplyConfirmLocalizedAsync(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
await ReplyConfirmLocalizedAsync(strs.defprefix_new(Format.Code(oldPrefix), Format.Code(newPrefix)));
|
||||||
}
|
}
|
||||||
|
@@ -94,7 +94,7 @@ public class ProtectionService : INService
|
|||||||
|
|
||||||
private Task _client_LeftGuild(SocketGuild guild)
|
private Task _client_LeftGuild(SocketGuild guild)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
TryStopAntiRaid(guild.Id);
|
TryStopAntiRaid(guild.Id);
|
||||||
TryStopAntiSpam(guild.Id);
|
TryStopAntiSpam(guild.Id);
|
||||||
@@ -202,7 +202,7 @@ public class ProtectionService : INService
|
|||||||
|
|
||||||
if (msg.Channel is not ITextChannel channel)
|
if (msg.Channel is not ITextChannel channel)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -38,15 +38,15 @@ public class AntiAltStats
|
|||||||
=> _setting.MinAge;
|
=> _setting.MinAge;
|
||||||
|
|
||||||
public int Counter
|
public int Counter
|
||||||
=> _counter;
|
=> counter;
|
||||||
|
|
||||||
private readonly AntiAltSetting _setting;
|
private readonly AntiAltSetting _setting;
|
||||||
|
|
||||||
private int _counter;
|
private int counter;
|
||||||
|
|
||||||
public AntiAltStats(AntiAltSetting setting)
|
public AntiAltStats(AntiAltSetting setting)
|
||||||
=> _setting = setting;
|
=> _setting = setting;
|
||||||
|
|
||||||
public void Increment()
|
public void Increment()
|
||||||
=> Interlocked.Increment(ref _counter);
|
=> Interlocked.Increment(ref counter);
|
||||||
}
|
}
|
@@ -8,7 +8,7 @@ public partial class Administration
|
|||||||
[Group]
|
[Group]
|
||||||
public partial class PruneCommands : NadekoSubmodule<PruneService>
|
public partial class PruneCommands : NadekoSubmodule<PruneService>
|
||||||
{
|
{
|
||||||
private static readonly TimeSpan twoWeeks = TimeSpan.FromDays(14);
|
private static readonly TimeSpan _twoWeeks = TimeSpan.FromDays(14);
|
||||||
|
|
||||||
//delets her own messages, no perm required
|
//delets her own messages, no perm required
|
||||||
[Cmd]
|
[Cmd]
|
||||||
@@ -73,11 +73,11 @@ public partial class Administration
|
|||||||
if (parameter is "-s" or "--safe")
|
if (parameter is "-s" or "--safe")
|
||||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||||
count,
|
count,
|
||||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks && !m.IsPinned);
|
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks && !m.IsPinned);
|
||||||
else
|
else
|
||||||
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
await _service.PruneWhere((ITextChannel)ctx.Channel,
|
||||||
count,
|
count,
|
||||||
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < twoWeeks);
|
m => m.Author.Id == userId && DateTime.UtcNow - m.CreatedAt < _twoWeeks);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -13,7 +13,7 @@ public partial class Administration
|
|||||||
{
|
{
|
||||||
public enum Exclude { Excl }
|
public enum Exclude { Excl }
|
||||||
|
|
||||||
private IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
|
|
||||||
public RoleCommands(IServiceProvider services)
|
public RoleCommands(IServiceProvider services)
|
||||||
=> _services = services;
|
=> _services = services;
|
||||||
@@ -24,7 +24,7 @@ public partial class Administration
|
|||||||
? await ctx.Channel.GetMessageAsync(msgId)
|
? await ctx.Channel.GetMessageAsync(msgId)
|
||||||
: (await ctx.Channel.GetMessagesAsync(2).FlattenAsync()).Skip(1).FirstOrDefault();
|
: (await ctx.Channel.GetMessagesAsync(2).FlattenAsync()).Skip(1).FirstOrDefault();
|
||||||
|
|
||||||
if (input.Length % 2 != 0)
|
if (input.Length % 2 != 0 || target is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var all = await input.Chunk(input.Length / 2)
|
var all = await input.Chunk(input.Length / 2)
|
||||||
@@ -35,7 +35,7 @@ public partial class Administration
|
|||||||
var roleResult = await roleReader.ReadAsync(ctx, inputRoleStr, _services);
|
var roleResult = await roleReader.ReadAsync(ctx, inputRoleStr, _services);
|
||||||
if (!roleResult.IsSuccess)
|
if (!roleResult.IsSuccess)
|
||||||
{
|
{
|
||||||
Log.Warning("Role {0} not found.", inputRoleStr);
|
Log.Warning("Role {Role} not found", inputRoleStr);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -163,7 +163,6 @@ public partial class Administration
|
|||||||
if (index < 1 || !_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any() || rrs.Count < index)
|
if (index < 1 || !_service.Get(ctx.Guild.Id, out var rrs) || !rrs.Any() || rrs.Count < index)
|
||||||
return;
|
return;
|
||||||
index--;
|
index--;
|
||||||
var rr = rrs[index];
|
|
||||||
_service.Remove(ctx.Guild.Id, index);
|
_service.Remove(ctx.Guild.Id, index);
|
||||||
await ReplyConfirmLocalizedAsync(strs.reaction_role_removed(index + 1));
|
await ReplyConfirmLocalizedAsync(strs.reaction_role_removed(index + 1));
|
||||||
}
|
}
|
||||||
|
@@ -90,7 +90,7 @@ public class RoleCommandsService : INService
|
|||||||
await dl.RemoveReactionAsync(reaction.Emote,
|
await dl.RemoveReactionAsync(reaction.Emote,
|
||||||
dl.Author,
|
dl.Author,
|
||||||
new() { RetryMode = RetryMode.RetryRatelimit | RetryMode.Retry502 });
|
new() { RetryMode = RetryMode.RetryRatelimit | RetryMode.Retry502 });
|
||||||
Log.Warning("User {0} is adding unrelated reactions to the reaction roles message.", dl.Author);
|
Log.Warning("User {Author} is adding unrelated reactions to the reaction roles message", dl.Author);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -58,8 +58,6 @@ public partial class Administration
|
|||||||
[Priority(0)]
|
[Priority(0)]
|
||||||
public async partial Task Sargn(int group, [Leftover] string name = null)
|
public async partial Task Sargn(int group, [Leftover] string name = null)
|
||||||
{
|
{
|
||||||
var guser = (IGuildUser)ctx.User;
|
|
||||||
|
|
||||||
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
|
var set = await _service.SetNameAsync(ctx.Guild.Id, group, name);
|
||||||
|
|
||||||
if (set)
|
if (set)
|
||||||
@@ -106,7 +104,7 @@ public partial class Administration
|
|||||||
|
|
||||||
foreach (var kvp in roleGroups)
|
foreach (var kvp in roleGroups)
|
||||||
{
|
{
|
||||||
var groupNameText = string.Empty;
|
string groupNameText;
|
||||||
if (!groups.TryGetValue(kvp.Key, out var name))
|
if (!groups.TryGetValue(kvp.Key, out var name))
|
||||||
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
groupNameText = Format.Bold(GetText(strs.self_assign_group(kvp.Key)));
|
||||||
else
|
else
|
||||||
|
@@ -158,7 +158,7 @@ public class SelfAssignedRolesService : INService
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (bool AutoDelete, bool Exclusive, IEnumerable<SelfAssignedRole>) GetAdAndRoles(ulong guildId)
|
public (bool AutoDelete, bool Exclusive, IReadOnlyCollection<SelfAssignedRole>) GetAdAndRoles(ulong guildId)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var gc = uow.GuildConfigsForId(guildId, set => set);
|
var gc = uow.GuildConfigsForId(guildId, set => set);
|
||||||
@@ -198,12 +198,12 @@ public class SelfAssignedRolesService : INService
|
|||||||
return areExclusive;
|
return areExclusive;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (bool Exclusive, IEnumerable<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string> GroupNames
|
public (bool Exclusive, IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> Roles, IDictionary<int, string> GroupNames
|
||||||
) GetRoles(IGuild guild)
|
) GetRoles(IGuild guild)
|
||||||
{
|
{
|
||||||
var exclusive = false;
|
var exclusive = false;
|
||||||
|
|
||||||
IEnumerable<(SelfAssignedRole Model, IRole Role)> roles;
|
IReadOnlyCollection<(SelfAssignedRole Model, IRole Role)> roles;
|
||||||
IDictionary<int, string> groupNames;
|
IDictionary<int, string> groupNames;
|
||||||
using (var uow = _db.GetDbContext())
|
using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
@@ -211,11 +211,12 @@ public class SelfAssignedRolesService : INService
|
|||||||
exclusive = gc.ExclusiveSelfAssignedRoles;
|
exclusive = gc.ExclusiveSelfAssignedRoles;
|
||||||
groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name);
|
groupNames = gc.SelfAssignableRoleGroupNames.ToDictionary(x => x.Number, x => x.Name);
|
||||||
var roleModels = uow.SelfAssignableRoles.GetFromGuild(guild.Id);
|
var roleModels = uow.SelfAssignableRoles.GetFromGuild(guild.Id);
|
||||||
roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)));
|
roles = roleModels.Select(x => (Model: x, Role: guild.GetRole(x.RoleId)))
|
||||||
|
.ToList();
|
||||||
uow.SelfAssignableRoles.RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray());
|
uow.SelfAssignableRoles.RemoveRange(roles.Where(x => x.Role is null).Select(x => x.Model).ToArray());
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (exclusive, roles.Where(x => x.Role is not null), groupNames);
|
return (exclusive, roles.Where(x => x.Role is not null).ToList(), groupNames);
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -183,7 +183,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserUpdated(SocketUser before, SocketUser uAfter)
|
private Task _client_UserUpdated(SocketUser before, SocketUser uAfter)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -292,7 +292,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
case LogType.VoicePresence:
|
case LogType.VoicePresence:
|
||||||
channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default;
|
channelId = logSetting.LogVoicePresenceId = logSetting.LogVoicePresenceId is null ? cid : default;
|
||||||
break;
|
break;
|
||||||
case LogType.VoicePresenceTTS:
|
case LogType.VoicePresenceTts:
|
||||||
channelId = logSetting.LogVoicePresenceTTSId =
|
channelId = logSetting.LogVoicePresenceTTSId =
|
||||||
logSetting.LogVoicePresenceTTSId is null ? cid : default;
|
logSetting.LogVoicePresenceTTSId is null ? cid : default;
|
||||||
break;
|
break;
|
||||||
@@ -306,7 +306,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
private Task _client_UserVoiceStateUpdated_TTS(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -324,7 +324,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
ITextChannel? logChannel;
|
ITextChannel? logChannel;
|
||||||
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTTS)) is null)
|
if ((logChannel = await TryGetLogChannel(usr.Guild, logSetting, LogType.VoicePresenceTts)) is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var str = string.Empty;
|
var str = string.Empty;
|
||||||
@@ -351,8 +351,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
IUser mod,
|
IUser mod,
|
||||||
MuteType muteType,
|
MuteType muteType,
|
||||||
string reason)
|
string reason)
|
||||||
{
|
=> _= Task.Run(async () =>
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -391,15 +390,13 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
private void MuteCommands_UserUnmuted(
|
private void MuteCommands_UserUnmuted(
|
||||||
IGuildUser usr,
|
IGuildUser usr,
|
||||||
IUser mod,
|
IUser mod,
|
||||||
MuteType muteType,
|
MuteType muteType,
|
||||||
string reason)
|
string reason)
|
||||||
{
|
=> _= Task.Run(async () =>
|
||||||
var _ = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -443,11 +440,10 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public Task TriggeredAntiProtection(PunishmentAction action, ProtectionType protection, params IGuildUser[] users)
|
public Task TriggeredAntiProtection(PunishmentAction action, ProtectionType protection, params IGuildUser[] users)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -517,7 +513,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_GuildUserUpdated(Cacheable<SocketGuildUser, ulong> optBefore, SocketGuildUser after)
|
private Task _client_GuildUserUpdated(Cacheable<SocketGuildUser, ulong> optBefore, SocketGuildUser after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -620,7 +616,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
|
private Task _client_ChannelUpdated(IChannel cbefore, IChannel cafter)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -668,7 +664,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_ChannelDestroyed(IChannel ich)
|
private Task _client_ChannelDestroyed(IChannel ich)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -706,7 +702,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_ChannelCreated(IChannel ich)
|
private Task _client_ChannelCreated(IChannel ich)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -742,7 +738,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
private Task _client_UserVoiceStateUpdated(SocketUser iusr, SocketVoiceState before, SocketVoiceState after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -805,7 +801,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserLeft(SocketGuild guild, SocketUser usr)
|
private Task _client_UserLeft(SocketGuild guild, SocketUser usr)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -840,7 +836,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserJoined(IGuildUser usr)
|
private Task _client_UserJoined(IGuildUser usr)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -879,7 +875,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserUnbanned(IUser usr, IGuild guild)
|
private Task _client_UserUnbanned(IUser usr, IGuild guild)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -914,7 +910,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_UserBanned(IUser usr, IGuild guild)
|
private Task _client_UserBanned(IUser usr, IGuild guild)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -951,7 +947,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
|
|
||||||
private Task _client_MessageDeleted(Cacheable<IMessage, ulong> optMsg, Cacheable<IMessageChannel, ulong> optCh)
|
private Task _client_MessageDeleted(Cacheable<IMessage, ulong> optMsg, Cacheable<IMessageChannel, ulong> optCh)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1005,7 +1001,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
SocketMessage imsg2,
|
SocketMessage imsg2,
|
||||||
ISocketMessageChannel ch)
|
ISocketMessageChannel ch)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -1104,7 +1100,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
case LogType.VoicePresence:
|
case LogType.VoicePresence:
|
||||||
id = logSetting.LogVoicePresenceId;
|
id = logSetting.LogVoicePresenceId;
|
||||||
break;
|
break;
|
||||||
case LogType.VoicePresenceTTS:
|
case LogType.VoicePresenceTts:
|
||||||
id = logSetting.LogVoicePresenceTTSId;
|
id = logSetting.LogVoicePresenceTTSId;
|
||||||
break;
|
break;
|
||||||
case LogType.UserMuted:
|
case LogType.UserMuted:
|
||||||
@@ -1177,7 +1173,7 @@ public sealed class LogCommandService : ILogCommandService, IReadyExecutor
|
|||||||
case LogType.VoicePresence:
|
case LogType.VoicePresence:
|
||||||
newLogSetting.LogVoicePresenceId = null;
|
newLogSetting.LogVoicePresenceId = null;
|
||||||
break;
|
break;
|
||||||
case LogType.VoicePresenceTTS:
|
case LogType.VoicePresenceTts:
|
||||||
newLogSetting.LogVoicePresenceTTSId = null;
|
newLogSetting.LogVoicePresenceTTSId = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -131,7 +131,7 @@ public partial class Administration
|
|||||||
return l.LogUserPresenceId;
|
return l.LogUserPresenceId;
|
||||||
case LogType.VoicePresence:
|
case LogType.VoicePresence:
|
||||||
return l.LogVoicePresenceId;
|
return l.LogVoicePresenceId;
|
||||||
case LogType.VoicePresenceTTS:
|
case LogType.VoicePresenceTts:
|
||||||
return l.LogVoicePresenceTTSId;
|
return l.LogVoicePresenceTTSId;
|
||||||
case LogType.UserMuted:
|
case LogType.UserMuted:
|
||||||
return l.UserMutedId;
|
return l.UserMutedId;
|
||||||
|
@@ -315,6 +315,9 @@ WHERE GuildId={guildId}
|
|||||||
if (number <= 0 || (time is not null && time.Time > TimeSpan.FromDays(49)))
|
if (number <= 0 || (time is not null && time.Time > TimeSpan.FromDays(49)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (punish is PunishmentAction.AddRole && role is null)
|
||||||
|
return false;
|
||||||
|
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
var ps = uow.GuildConfigsForId(guildId, set => set.Include(x => x.WarnPunishments)).WarnPunishments;
|
||||||
var toDelete = ps.Where(x => x.Count == number);
|
var toDelete = ps.Where(x => x.Count == number);
|
||||||
@@ -326,7 +329,7 @@ WHERE GuildId={guildId}
|
|||||||
Count = number,
|
Count = number,
|
||||||
Punishment = punish,
|
Punishment = punish,
|
||||||
Time = (int?)time?.Time.TotalMinutes ?? 0,
|
Time = (int?)time?.Time.TotalMinutes ?? 0,
|
||||||
RoleId = punish == PunishmentAction.AddRole ? role.Id : default(ulong?)
|
RoleId = punish == PunishmentAction.AddRole ? role!.Id : default(ulong?)
|
||||||
});
|
});
|
||||||
uow.SaveChanges();
|
uow.SaveChanges();
|
||||||
return true;
|
return true;
|
||||||
|
@@ -80,7 +80,7 @@ public class VcRoleService : INService
|
|||||||
using (var uow = _db.GetDbContext())
|
using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
var configWithVcRole = uow.GuildConfigsForId(arg.GuildId, set => set.Include(x => x.VcRoleInfos));
|
var configWithVcRole = uow.GuildConfigsForId(arg.GuildId, set => set.Include(x => x.VcRoleInfos));
|
||||||
var _ = InitializeVcRole(configWithVcRole);
|
_= InitializeVcRole(configWithVcRole);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
@@ -166,7 +166,7 @@ public class VcRoleService : INService
|
|||||||
|
|
||||||
var oldVc = oldState.VoiceChannel;
|
var oldVc = oldState.VoiceChannel;
|
||||||
var newVc = newState.VoiceChannel;
|
var newVc = newState.VoiceChannel;
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -55,15 +55,15 @@ public static class NadekoExpressionExtensions
|
|||||||
|
|
||||||
if (wordIndex == 0)
|
if (wordIndex == 0)
|
||||||
{
|
{
|
||||||
if (word.Length < str.Length && str.isValidWordDivider(word.Length))
|
if (word.Length < str.Length && str.IsValidWordDivider(word.Length))
|
||||||
return WordPosition.Start;
|
return WordPosition.Start;
|
||||||
}
|
}
|
||||||
else if (wordIndex + word.Length == str.Length)
|
else if (wordIndex + word.Length == str.Length)
|
||||||
{
|
{
|
||||||
if (str.isValidWordDivider(wordIndex - 1))
|
if (str.IsValidWordDivider(wordIndex - 1))
|
||||||
return WordPosition.End;
|
return WordPosition.End;
|
||||||
}
|
}
|
||||||
else if (str.isValidWordDivider(wordIndex - 1) && str.isValidWordDivider(wordIndex + word.Length))
|
else if (str.IsValidWordDivider(wordIndex - 1) && str.IsValidWordDivider(wordIndex + word.Length))
|
||||||
{
|
{
|
||||||
return WordPosition.Middle;
|
return WordPosition.Middle;
|
||||||
}
|
}
|
||||||
@@ -71,7 +71,7 @@ public static class NadekoExpressionExtensions
|
|||||||
return WordPosition.None;
|
return WordPosition.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool isValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
private static bool IsValidWordDivider(this in ReadOnlySpan<char> str, int index)
|
||||||
{
|
{
|
||||||
var ch = str[index];
|
var ch = str[index];
|
||||||
if (ch is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '1' and <= '9')
|
if (ch is >= 'a' and <= 'z' or >= 'A' and <= 'Z' or >= '1' and <= '9')
|
||||||
|
@@ -44,8 +44,7 @@ public sealed class AnimalRace : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize() //lame name
|
public void Initialize() //lame name
|
||||||
{
|
=> _ = Task.Run(async () =>
|
||||||
var _t = Task.Run(async () =>
|
|
||||||
{
|
{
|
||||||
await Task.Delay(_options.StartTime * 1000);
|
await Task.Delay(_options.StartTime * 1000);
|
||||||
|
|
||||||
@@ -59,7 +58,6 @@ public sealed class AnimalRace : IDisposable
|
|||||||
}
|
}
|
||||||
finally { _locker.Release(); }
|
finally { _locker.Release(); }
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<AnimalRacingUser> JoinRace(ulong userId, string userName, long bet = 0)
|
public async Task<AnimalRacingUser> JoinRace(ulong userId, string userName, long bet = 0)
|
||||||
{
|
{
|
||||||
@@ -104,13 +102,13 @@ public sealed class AnimalRace : IDisposable
|
|||||||
if (user.Bet > 0)
|
if (user.Bet > 0)
|
||||||
await _currency.AddAsync(user.UserId, "Race refund", user.Bet);
|
await _currency.AddAsync(user.UserId, "Race refund", user.Bet);
|
||||||
|
|
||||||
var _sf = OnStartingFailed?.Invoke(this);
|
_ = OnStartingFailed?.Invoke(this);
|
||||||
CurrentPhase = Phase.Ended;
|
CurrentPhase = Phase.Ended;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = OnStarted?.Invoke(this);
|
_ = OnStarted?.Invoke(this);
|
||||||
var _t = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var rng = new NadekoRandom();
|
var rng = new NadekoRandom();
|
||||||
while (!_users.All(x => x.Progress >= 60))
|
while (!_users.All(x => x.Progress >= 60))
|
||||||
@@ -126,7 +124,7 @@ public sealed class AnimalRace : IDisposable
|
|||||||
|
|
||||||
FinishedUsers.AddRange(finished);
|
FinishedUsers.AddRange(finished);
|
||||||
|
|
||||||
var _ignore = OnStateUpdate?.Invoke(this);
|
_ = OnStateUpdate?.Invoke(this);
|
||||||
await Task.Delay(2500);
|
await Task.Delay(2500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,7 +133,7 @@ public sealed class AnimalRace : IDisposable
|
|||||||
"Won a Race",
|
"Won a Race",
|
||||||
FinishedUsers[0].Bet * (_users.Count - 1));
|
FinishedUsers[0].Bet * (_users.Count - 1));
|
||||||
|
|
||||||
var _ended = OnEnded?.Invoke(this);
|
_ = OnEnded?.Invoke(this);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -48,7 +48,7 @@ public partial class Gambling
|
|||||||
|
|
||||||
Task _client_MessageReceived(SocketMessage arg)
|
Task _client_MessageReceived(SocketMessage arg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -18,7 +18,7 @@ public partial class Gambling
|
|||||||
|
|
||||||
private readonly ICurrencyService _cs;
|
private readonly ICurrencyService _cs;
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private IUserMessage _msg;
|
private IUserMessage msg;
|
||||||
|
|
||||||
public BlackJackCommands(ICurrencyService cs, DbService db, GamblingConfigService gamblingConf)
|
public BlackJackCommands(ICurrencyService cs, DbService db, GamblingConfigService gamblingConf)
|
||||||
: base(gamblingConf)
|
: base(gamblingConf)
|
||||||
@@ -74,12 +74,13 @@ public partial class Gambling
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_msg is not null)
|
if (msg is not null)
|
||||||
{
|
{
|
||||||
var _ = _msg.DeleteAsync();
|
_= msg.DeleteAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
var c = bj.Dealer.Cards.Select(x => x.GetEmojiString());
|
var c = bj.Dealer.Cards.Select(x => x.GetEmojiString())
|
||||||
|
.ToList();
|
||||||
var dealerIcon = "❔ ";
|
var dealerIcon = "❔ ";
|
||||||
if (bj.State == Blackjack.GameState.Ended)
|
if (bj.State == Blackjack.GameState.Ended)
|
||||||
{
|
{
|
||||||
@@ -102,7 +103,7 @@ public partial class Gambling
|
|||||||
|
|
||||||
foreach (var p in bj.Players)
|
foreach (var p in bj.Players)
|
||||||
{
|
{
|
||||||
c = p.Cards.Select(x => x.GetEmojiString());
|
c = p.Cards.Select(x => x.GetEmojiString()).ToList();
|
||||||
cStr = "-\t" + string.Concat(c.Select(x => x[..^1] + " "));
|
cStr = "-\t" + string.Concat(c.Select(x => x[..^1] + " "));
|
||||||
cStr += "\n-\t" + string.Concat(c.Select(x => x.Last() + " "));
|
cStr += "\n-\t" + string.Concat(c.Select(x => x.Last() + " "));
|
||||||
var full = $"{p.DiscordUser.ToString().TrimTo(20)} | Bet: {p.Bet} | Value: {p.GetHandValue()}";
|
var full = $"{p.DiscordUser.ToString().TrimTo(20)} | Bet: {p.Bet} | Value: {p.GetHandValue()}";
|
||||||
@@ -133,7 +134,7 @@ public partial class Gambling
|
|||||||
embed.AddField(full, cStr);
|
embed.AddField(full, cStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
_msg = await ctx.Channel.EmbedAsync(embed);
|
msg = await ctx.Channel.EmbedAsync(embed);
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
@@ -146,7 +147,7 @@ public partial class Gambling
|
|||||||
? Format.Strikethrough(x.DiscordUser.ToString().TrimTo(30))
|
? Format.Strikethrough(x.DiscordUser.ToString().TrimTo(30))
|
||||||
: x.DiscordUser.ToString();
|
: x.DiscordUser.ToString();
|
||||||
|
|
||||||
var hand = $"{string.Concat(x.Cards.Select(y => "〖" + y.GetEmojiString() + "〗"))}";
|
// var hand = $"{string.Concat(x.Cards.Select(y => "〖" + y.GetEmojiString() + "〗"))}";
|
||||||
|
|
||||||
|
|
||||||
return $"{playerName} | Bet: {x.Bet}\n";
|
return $"{playerName} | Bet: {x.Bet}\n";
|
||||||
|
@@ -35,9 +35,7 @@ public class Blackjack
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void Start()
|
public void Start()
|
||||||
{
|
=> _= GameLoop();
|
||||||
var _ = GameLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task GameLoop()
|
public async Task GameLoop()
|
||||||
{
|
{
|
||||||
@@ -89,13 +87,13 @@ public class Blackjack
|
|||||||
Log.Information("Dealer moves");
|
Log.Information("Dealer moves");
|
||||||
await DealerMoves();
|
await DealerMoves();
|
||||||
await PrintState();
|
await PrintState();
|
||||||
var _ = GameEnded?.Invoke(this);
|
_= GameEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex, "REPORT THE MESSAGE BELOW IN #NadekoLog SERVER PLEASE");
|
Log.Error(ex, "REPORT THE MESSAGE BELOW IN #NadekoLog SERVER PLEASE");
|
||||||
State = GameState.Ended;
|
State = GameState.Ended;
|
||||||
var _ = GameEnded?.Invoke(this);
|
_= GameEnded?.Invoke(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -127,7 +125,7 @@ public class Blackjack
|
|||||||
if (!await _cs.RemoveAsync(user, "BlackJack-gamble", bet, gamble: true)) return false;
|
if (!await _cs.RemoveAsync(user, "BlackJack-gamble", bet, gamble: true)) return false;
|
||||||
|
|
||||||
Players.Add(new(user, bet));
|
Players.Add(new(user, bet));
|
||||||
var _ = PrintState();
|
_= PrintState();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
@@ -28,8 +28,8 @@ public sealed class Connect4Game : IDisposable
|
|||||||
OtherPlayerWon
|
OtherPlayerWon
|
||||||
}
|
}
|
||||||
|
|
||||||
public const int NumberOfColumns = 7;
|
public const int NUMBER_OF_COLUMNS = 7;
|
||||||
public const int NumberOfRows = 6;
|
public const int NUMBER_OF_ROWS = 6;
|
||||||
|
|
||||||
//public event Func<Connect4Game, Task> OnGameStarted;
|
//public event Func<Connect4Game, Task> OnGameStarted;
|
||||||
public event Func<Connect4Game, Task> OnGameStateUpdated;
|
public event Func<Connect4Game, Task> OnGameStateUpdated;
|
||||||
@@ -51,7 +51,7 @@ public sealed class Connect4Game : IDisposable
|
|||||||
=> CurrentPhase == Phase.P2Move ? _players[0].Value : _players[1].Value;
|
=> CurrentPhase == Phase.P2Move ? _players[0].Value : _players[1].Value;
|
||||||
|
|
||||||
//state is bottom to top, left to right
|
//state is bottom to top, left to right
|
||||||
private readonly Field[] _gameState = new Field[NumberOfRows * NumberOfColumns];
|
private readonly Field[] _gameState = new Field[NUMBER_OF_ROWS * NUMBER_OF_COLUMNS];
|
||||||
private readonly (ulong UserId, string Username)?[] _players = new (ulong, string)?[2];
|
private readonly (ulong UserId, string Username)?[] _players = new (ulong, string)?[2];
|
||||||
|
|
||||||
private readonly SemaphoreSlim _locker = new(1, 1);
|
private readonly SemaphoreSlim _locker = new(1, 1);
|
||||||
@@ -81,14 +81,14 @@ public sealed class Connect4Game : IDisposable
|
|||||||
_cs = cs;
|
_cs = cs;
|
||||||
|
|
||||||
_rng = new();
|
_rng = new();
|
||||||
for (var i = 0; i < NumberOfColumns * NumberOfRows; i++) _gameState[i] = Field.Empty;
|
for (var i = 0; i < NUMBER_OF_COLUMNS * NUMBER_OF_ROWS; i++) _gameState[i] = Field.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
if (CurrentPhase != Phase.Joining)
|
if (CurrentPhase != Phase.Joining)
|
||||||
return;
|
return;
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(15000);
|
await Task.Delay(15000);
|
||||||
await _locker.WaitAsync();
|
await _locker.WaitAsync();
|
||||||
@@ -165,14 +165,14 @@ public sealed class Connect4Game : IDisposable
|
|||||||
|| (_players[1].Value.UserId == userId && CurrentPhase == Phase.P2Move)))
|
|| (_players[1].Value.UserId == userId && CurrentPhase == Phase.P2Move)))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (inputCol is < 0 or > NumberOfColumns) //invalid input
|
if (inputCol is < 0 or > NUMBER_OF_COLUMNS) //invalid input
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (IsColumnFull(inputCol)) //can't play there event?
|
if (IsColumnFull(inputCol)) //can't play there event?
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var start = NumberOfRows * inputCol;
|
var start = NUMBER_OF_ROWS * inputCol;
|
||||||
for (var i = start; i < start + NumberOfRows; i++)
|
for (var i = start; i < start + NUMBER_OF_ROWS; i++)
|
||||||
if (_gameState[i] == Field.Empty)
|
if (_gameState[i] == Field.Empty)
|
||||||
{
|
{
|
||||||
_gameState[i] = GetPlayerPiece(userId);
|
_gameState[i] = GetPlayerPiece(userId);
|
||||||
@@ -182,21 +182,21 @@ public sealed class Connect4Game : IDisposable
|
|||||||
//check winnning condition
|
//check winnning condition
|
||||||
// ok, i'll go from [0-2] in rows (and through all columns) and check upward if 4 are connected
|
// ok, i'll go from [0-2] in rows (and through all columns) and check upward if 4 are connected
|
||||||
|
|
||||||
for (var i = 0; i < NumberOfRows - 3; i++)
|
for (var i = 0; i < NUMBER_OF_ROWS - 3; i++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (var j = 0; j < NumberOfColumns; j++)
|
for (var j = 0; j < NUMBER_OF_COLUMNS; j++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var first = _gameState[i + (j * NumberOfRows)];
|
var first = _gameState[i + (j * NUMBER_OF_ROWS)];
|
||||||
if (first != Field.Empty)
|
if (first != Field.Empty)
|
||||||
for (var k = 1; k < 4; k++)
|
for (var k = 1; k < 4; k++)
|
||||||
{
|
{
|
||||||
var next = _gameState[i + k + (j * NumberOfRows)];
|
var next = _gameState[i + k + (j * NUMBER_OF_ROWS)];
|
||||||
if (next == first)
|
if (next == first)
|
||||||
{
|
{
|
||||||
if (k == 3)
|
if (k == 3)
|
||||||
@@ -213,21 +213,21 @@ public sealed class Connect4Game : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
// i'll go [0-1] in columns (and through all rows) and check to the right if 4 are connected
|
// i'll go [0-1] in columns (and through all rows) and check to the right if 4 are connected
|
||||||
for (var i = 0; i < NumberOfColumns - 3; i++)
|
for (var i = 0; i < NUMBER_OF_COLUMNS - 3; i++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (var j = 0; j < NumberOfRows; j++)
|
for (var j = 0; j < NUMBER_OF_ROWS; j++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var first = _gameState[j + (i * NumberOfRows)];
|
var first = _gameState[j + (i * NUMBER_OF_ROWS)];
|
||||||
if (first != Field.Empty)
|
if (first != Field.Empty)
|
||||||
for (var k = 1; k < 4; k++)
|
for (var k = 1; k < 4; k++)
|
||||||
{
|
{
|
||||||
var next = _gameState[j + ((i + k) * NumberOfRows)];
|
var next = _gameState[j + ((i + k) * NUMBER_OF_ROWS)];
|
||||||
if (next == first)
|
if (next == first)
|
||||||
if (k == 3)
|
if (k == 3)
|
||||||
EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId);
|
EndGame(Result.CurrentPlayerWon, CurrentPlayer.UserId);
|
||||||
@@ -239,17 +239,17 @@ public sealed class Connect4Game : IDisposable
|
|||||||
}
|
}
|
||||||
|
|
||||||
//need to check diagonal now
|
//need to check diagonal now
|
||||||
for (var col = 0; col < NumberOfColumns; col++)
|
for (var col = 0; col < NUMBER_OF_COLUMNS; col++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
for (var row = 0; row < NumberOfRows; row++)
|
for (var row = 0; row < NUMBER_OF_ROWS; row++)
|
||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var first = _gameState[row + (col * NumberOfRows)];
|
var first = _gameState[row + (col * NUMBER_OF_ROWS)];
|
||||||
|
|
||||||
if (first != Field.Empty)
|
if (first != Field.Empty)
|
||||||
{
|
{
|
||||||
@@ -263,12 +263,12 @@ public sealed class Connect4Game : IDisposable
|
|||||||
var curCol = col - i;
|
var curCol = col - i;
|
||||||
|
|
||||||
//check if current values are in range
|
//check if current values are in range
|
||||||
if (curRow is >= NumberOfRows or < 0)
|
if (curRow is >= NUMBER_OF_ROWS or < 0)
|
||||||
break;
|
break;
|
||||||
if (curCol is < 0 or >= NumberOfColumns)
|
if (curCol is < 0 or >= NUMBER_OF_COLUMNS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var cur = _gameState[curRow + (curCol * NumberOfRows)];
|
var cur = _gameState[curRow + (curCol * NUMBER_OF_ROWS)];
|
||||||
if (cur == first)
|
if (cur == first)
|
||||||
same++;
|
same++;
|
||||||
else break;
|
else break;
|
||||||
@@ -290,12 +290,12 @@ public sealed class Connect4Game : IDisposable
|
|||||||
var curCol = col + i;
|
var curCol = col + i;
|
||||||
|
|
||||||
//check if current values are in range
|
//check if current values are in range
|
||||||
if (curRow is >= NumberOfRows or < 0)
|
if (curRow is >= NUMBER_OF_ROWS or < 0)
|
||||||
break;
|
break;
|
||||||
if (curCol is < 0 or >= NumberOfColumns)
|
if (curCol is < 0 or >= NUMBER_OF_COLUMNS)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
var cur = _gameState[curRow + (curCol * NumberOfRows)];
|
var cur = _gameState[curRow + (curCol * NUMBER_OF_ROWS)];
|
||||||
if (cur == first)
|
if (cur == first)
|
||||||
same++;
|
same++;
|
||||||
else break;
|
else break;
|
||||||
@@ -323,7 +323,7 @@ public sealed class Connect4Game : IDisposable
|
|||||||
ResetTimer();
|
ResetTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ = OnGameStateUpdated?.Invoke(this);
|
_= OnGameStateUpdated?.Invoke(this);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
finally { _locker.Release(); }
|
finally { _locker.Release(); }
|
||||||
@@ -337,7 +337,7 @@ public sealed class Connect4Game : IDisposable
|
|||||||
{
|
{
|
||||||
if (CurrentPhase == Phase.Ended)
|
if (CurrentPhase == Phase.Ended)
|
||||||
return;
|
return;
|
||||||
var _ = OnGameEnded?.Invoke(this, result);
|
_= OnGameEnded?.Invoke(this, result);
|
||||||
CurrentPhase = Phase.Ended;
|
CurrentPhase = Phase.Ended;
|
||||||
|
|
||||||
if (result == Result.Draw)
|
if (result == Result.Draw)
|
||||||
@@ -357,8 +357,8 @@ public sealed class Connect4Game : IDisposable
|
|||||||
//column is full if there are no empty fields
|
//column is full if there are no empty fields
|
||||||
private bool IsColumnFull(int column)
|
private bool IsColumnFull(int column)
|
||||||
{
|
{
|
||||||
var start = NumberOfRows * column;
|
var start = NUMBER_OF_ROWS * column;
|
||||||
for (var i = start; i < start + NumberOfRows; i++)
|
for (var i = start; i < start + NUMBER_OF_ROWS; i++)
|
||||||
if (_gameState[i] == Field.Empty)
|
if (_gameState[i] == Field.Empty)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
|
@@ -88,7 +88,7 @@ public partial class Gambling
|
|||||||
if (ctx.Channel.Id != arg.Channel.Id)
|
if (ctx.Channel.Id != arg.Channel.Id)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
var success = false;
|
var success = false;
|
||||||
if (int.TryParse(arg.Content, out var col)) success = await game.Input(arg.Author.Id, col);
|
if (int.TryParse(arg.Content, out var col)) success = await game.Input(arg.Author.Id, col);
|
||||||
@@ -168,11 +168,11 @@ public partial class Gambling
|
|||||||
if (game.CurrentPhase is Connect4Game.Phase.P1Move or Connect4Game.Phase.P2Move)
|
if (game.CurrentPhase is Connect4Game.Phase.P1Move or Connect4Game.Phase.P2Move)
|
||||||
sb.AppendLine(GetText(strs.connect4_player_to_move(Format.Bold(game.CurrentPlayer.Username))));
|
sb.AppendLine(GetText(strs.connect4_player_to_move(Format.Bold(game.CurrentPlayer.Username))));
|
||||||
|
|
||||||
for (var i = Connect4Game.NumberOfRows; i > 0; i--)
|
for (var i = Connect4Game.NUMBER_OF_ROWS; i > 0; i--)
|
||||||
{
|
{
|
||||||
for (var j = 0; j < Connect4Game.NumberOfColumns; j++)
|
for (var j = 0; j < Connect4Game.NUMBER_OF_COLUMNS; j++)
|
||||||
{
|
{
|
||||||
var cur = game.GameState[i + (j * Connect4Game.NumberOfRows) - 1];
|
var cur = game.GameState[i + (j * Connect4Game.NUMBER_OF_ROWS) - 1];
|
||||||
|
|
||||||
if (cur == Connect4Game.Field.Empty)
|
if (cur == Connect4Game.Field.Empty)
|
||||||
sb.Append("⚫"); //black circle
|
sb.Append("⚫"); //black circle
|
||||||
@@ -185,7 +185,7 @@ public partial class Gambling
|
|||||||
sb.AppendLine();
|
sb.AppendLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < Connect4Game.NumberOfColumns; i++) sb.Append(numbers[i]);
|
for (var i = 0; i < Connect4Game.NUMBER_OF_COLUMNS; i++) sb.Append(numbers[i]);
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -68,10 +68,10 @@ public partial class Gambling
|
|||||||
if (num > 10)
|
if (num > 10)
|
||||||
num = 10;
|
num = 10;
|
||||||
|
|
||||||
var (ImageStream, ToSend) = await InternalDraw(num, ctx.Guild.Id);
|
var (imageStream, toSend) = await InternalDraw(num, ctx.Guild.Id);
|
||||||
await using (ImageStream)
|
await using (imageStream)
|
||||||
{
|
{
|
||||||
await ctx.Channel.SendFileAsync(ImageStream, num + " cards.jpg", ToSend);
|
await ctx.Channel.SendFileAsync(imageStream, num + " cards.jpg", toSend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,10 +83,10 @@ public partial class Gambling
|
|||||||
if (num > 10)
|
if (num > 10)
|
||||||
num = 10;
|
num = 10;
|
||||||
|
|
||||||
var (ImageStream, ToSend) = await InternalDraw(num);
|
var (imageStream, toSend) = await InternalDraw(num);
|
||||||
await using (ImageStream)
|
await using (imageStream)
|
||||||
{
|
{
|
||||||
await ctx.Channel.SendFileAsync(ImageStream, num + " cards.jpg", ToSend);
|
await ctx.Channel.SendFileAsync(imageStream, num + " cards.jpg", toSend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,7 +11,7 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
public bool PotEmptied { get; private set; }
|
public bool PotEmptied { get; private set; }
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IGuild _guild;
|
private readonly IGuild _guild;
|
||||||
private IUserMessage _msg;
|
private IUserMessage msg;
|
||||||
private readonly ICurrencyService _cs;
|
private readonly ICurrencyService _cs;
|
||||||
private readonly long _amount;
|
private readonly long _amount;
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
.Select(x => (char)x)
|
.Select(x => (char)x)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
private readonly object stopLock = new();
|
private readonly object _stopLock = new();
|
||||||
|
|
||||||
private readonly object potLock = new();
|
private readonly object _potLock = new();
|
||||||
|
|
||||||
public GameStatusEvent(
|
public GameStatusEvent(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
@@ -62,9 +62,7 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void EventTimeout(object state)
|
private void EventTimeout(object state)
|
||||||
{
|
=> _ = StopEvent();
|
||||||
var _ = StopEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnTimerTick(object state)
|
private async void OnTimerTick(object state)
|
||||||
{
|
{
|
||||||
@@ -83,20 +81,20 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
true);
|
true);
|
||||||
|
|
||||||
if (_isPotLimited)
|
if (_isPotLimited)
|
||||||
await _msg.ModifyAsync(m =>
|
await msg.ModifyAsync(m =>
|
||||||
{
|
{
|
||||||
m.Embed = GetEmbed(PotSize).Build();
|
m.Embed = GetEmbed(PotSize).Build();
|
||||||
},
|
},
|
||||||
new() { RetryMode = RetryMode.AlwaysRetry });
|
new() { RetryMode = RetryMode.AlwaysRetry });
|
||||||
|
|
||||||
Log.Information("Awarded {0} users {1} currency.{2}",
|
Log.Information("Awarded {Count} users {Amount} currency.{Remaining}",
|
||||||
toAward.Count,
|
toAward.Count,
|
||||||
_amount,
|
_amount,
|
||||||
_isPotLimited ? $" {PotSize} left." : "");
|
_isPotLimited ? $" {PotSize} left." : "");
|
||||||
|
|
||||||
if (potEmpty)
|
if (potEmpty)
|
||||||
{
|
{
|
||||||
var _ = StopEvent();
|
_= StopEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -107,7 +105,7 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
|
|
||||||
public async Task StartEvent()
|
public async Task StartEvent()
|
||||||
{
|
{
|
||||||
_msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize));
|
msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize));
|
||||||
await _client.SetGameAsync(_code);
|
await _client.SetGameAsync(_code);
|
||||||
_client.MessageDeleted += OnMessageDeleted;
|
_client.MessageDeleted += OnMessageDeleted;
|
||||||
_client.MessageReceived += HandleMessage;
|
_client.MessageReceived += HandleMessage;
|
||||||
@@ -117,55 +115,55 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
private IEmbedBuilder GetEmbed(long pot)
|
private IEmbedBuilder GetEmbed(long pot)
|
||||||
=> _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot);
|
=> _embedFunc(CurrencyEvent.Type.GameStatus, _opts, pot);
|
||||||
|
|
||||||
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, Cacheable<IMessageChannel, ulong> cacheable)
|
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
|
||||||
{
|
{
|
||||||
if (msg.Id == _msg.Id) await StopEvent();
|
if (message.Id == this.msg.Id) await StopEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopEvent()
|
public async Task StopEvent()
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
lock (stopLock)
|
lock (_stopLock)
|
||||||
{
|
{
|
||||||
if (Stopped)
|
if (Stopped)
|
||||||
return;
|
return;
|
||||||
Stopped = true;
|
Stopped = true;
|
||||||
_client.MessageDeleted -= OnMessageDeleted;
|
_client.MessageDeleted -= OnMessageDeleted;
|
||||||
_client.MessageReceived -= HandleMessage;
|
_client.MessageReceived -= HandleMessage;
|
||||||
_client.SetGameAsync(null);
|
|
||||||
_t.Change(Timeout.Infinite, Timeout.Infinite);
|
_t.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
_timeout?.Change(Timeout.Infinite, Timeout.Infinite);
|
_timeout?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
|
_ = _client.SetGameAsync(null);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var _ = _msg.DeleteAsync();
|
_= msg.DeleteAsync();
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
var os = OnEnded(_guild.Id);
|
_ = OnEnded?.Invoke(_guild.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task HandleMessage(SocketMessage msg)
|
private Task HandleMessage(SocketMessage message)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (msg.Author is not IGuildUser gu // no unknown users, as they could be bots, or alts
|
if (message.Author is not IGuildUser gu // no unknown users, as they could be bots, or alts
|
||||||
|| gu.IsBot // no bots
|
|| gu.IsBot // no bots
|
||||||
|| msg.Content != _code // code has to be the same
|
|| message.Content != _code // code has to be the same
|
||||||
|| (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5) // no recently created accounts
|
|| (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5) // no recently created accounts
|
||||||
return;
|
return;
|
||||||
// there has to be money left in the pot
|
// there has to be money left in the pot
|
||||||
// and the user wasn't rewarded
|
// and the user wasn't rewarded
|
||||||
if (_awardedUsers.Add(msg.Author.Id) && TryTakeFromPot())
|
if (_awardedUsers.Add(message.Author.Id) && TryTakeFromPot())
|
||||||
{
|
{
|
||||||
_toAward.Enqueue(msg.Author.Id);
|
_toAward.Enqueue(message.Author.Id);
|
||||||
if (_isPotLimited && PotSize < _amount)
|
if (_isPotLimited && PotSize < _amount)
|
||||||
PotEmptied = true;
|
PotEmptied = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await msg.DeleteAsync(new() { RetryMode = RetryMode.AlwaysFail });
|
await message.DeleteAsync(new() { RetryMode = RetryMode.AlwaysFail });
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
});
|
});
|
||||||
@@ -175,7 +173,7 @@ public class GameStatusEvent : ICurrencyEvent
|
|||||||
private bool TryTakeFromPot()
|
private bool TryTakeFromPot()
|
||||||
{
|
{
|
||||||
if (_isPotLimited)
|
if (_isPotLimited)
|
||||||
lock (potLock)
|
lock (_potLock)
|
||||||
{
|
{
|
||||||
if (PotSize < _amount)
|
if (PotSize < _amount)
|
||||||
return false;
|
return false;
|
||||||
|
@@ -11,8 +11,8 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
public bool PotEmptied { get; private set; }
|
public bool PotEmptied { get; private set; }
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly IGuild _guild;
|
private readonly IGuild _guild;
|
||||||
private IUserMessage _msg;
|
private IUserMessage msg;
|
||||||
private IEmote _emote;
|
private IEmote emote;
|
||||||
private readonly ICurrencyService _cs;
|
private readonly ICurrencyService _cs;
|
||||||
private readonly long _amount;
|
private readonly long _amount;
|
||||||
|
|
||||||
@@ -27,9 +27,9 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
private readonly EventOptions _opts;
|
private readonly EventOptions _opts;
|
||||||
private readonly GamblingConfig _config;
|
private readonly GamblingConfig _config;
|
||||||
|
|
||||||
private readonly object stopLock = new();
|
private readonly object _stopLock = new();
|
||||||
|
|
||||||
private readonly object potLock = new();
|
private readonly object _potLock = new();
|
||||||
|
|
||||||
public ReactionEvent(
|
public ReactionEvent(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
@@ -58,9 +58,7 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void EventTimeout(object state)
|
private void EventTimeout(object state)
|
||||||
{
|
=> _= StopEvent();
|
||||||
var _ = StopEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnTimerTick(object state)
|
private async void OnTimerTick(object state)
|
||||||
{
|
{
|
||||||
@@ -76,20 +74,20 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
await _cs.AddBulkAsync(toAward, toAward.Select(_ => "Reaction Event"), toAward.Select(_ => _amount), true);
|
await _cs.AddBulkAsync(toAward, toAward.Select(_ => "Reaction Event"), toAward.Select(_ => _amount), true);
|
||||||
|
|
||||||
if (_isPotLimited)
|
if (_isPotLimited)
|
||||||
await _msg.ModifyAsync(m =>
|
await msg.ModifyAsync(m =>
|
||||||
{
|
{
|
||||||
m.Embed = GetEmbed(PotSize).Build();
|
m.Embed = GetEmbed(PotSize).Build();
|
||||||
},
|
},
|
||||||
new() { RetryMode = RetryMode.AlwaysRetry });
|
new() { RetryMode = RetryMode.AlwaysRetry });
|
||||||
|
|
||||||
Log.Information("Awarded {0} users {1} currency.{2}",
|
Log.Information("Awarded {Count} users {Amount} currency.{Remaining}",
|
||||||
toAward.Count,
|
toAward.Count,
|
||||||
_amount,
|
_amount,
|
||||||
_isPotLimited ? $" {PotSize} left." : "");
|
_isPotLimited ? $" {PotSize} left." : "");
|
||||||
|
|
||||||
if (potEmpty)
|
if (potEmpty)
|
||||||
{
|
{
|
||||||
var _ = StopEvent();
|
_= StopEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -100,12 +98,12 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
|
|
||||||
public async Task StartEvent()
|
public async Task StartEvent()
|
||||||
{
|
{
|
||||||
if (Emote.TryParse(_config.Currency.Sign, out var emote))
|
if (Emote.TryParse(_config.Currency.Sign, out var parsedEmote))
|
||||||
_emote = emote;
|
this.emote = parsedEmote;
|
||||||
else
|
else
|
||||||
_emote = new Emoji(_config.Currency.Sign);
|
this.emote = new Emoji(_config.Currency.Sign);
|
||||||
_msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize));
|
msg = await _channel.EmbedAsync(GetEmbed(_opts.PotSize));
|
||||||
await _msg.AddReactionAsync(_emote);
|
await msg.AddReactionAsync(this.emote);
|
||||||
_client.MessageDeleted += OnMessageDeleted;
|
_client.MessageDeleted += OnMessageDeleted;
|
||||||
_client.ReactionAdded += HandleReaction;
|
_client.ReactionAdded += HandleReaction;
|
||||||
_t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
|
_t.Change(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));
|
||||||
@@ -114,15 +112,15 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
private IEmbedBuilder GetEmbed(long pot)
|
private IEmbedBuilder GetEmbed(long pot)
|
||||||
=> _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot);
|
=> _embedFunc(CurrencyEvent.Type.Reaction, _opts, pot);
|
||||||
|
|
||||||
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> msg, Cacheable<IMessageChannel, ulong> cacheable)
|
private async Task OnMessageDeleted(Cacheable<IMessage, ulong> message, Cacheable<IMessageChannel, ulong> cacheable)
|
||||||
{
|
{
|
||||||
if (msg.Id == _msg.Id) await StopEvent();
|
if (message.Id == this.msg.Id) await StopEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task StopEvent()
|
public async Task StopEvent()
|
||||||
{
|
{
|
||||||
await Task.Yield();
|
await Task.Yield();
|
||||||
lock (stopLock)
|
lock (_stopLock)
|
||||||
{
|
{
|
||||||
if (Stopped)
|
if (Stopped)
|
||||||
return;
|
return;
|
||||||
@@ -133,27 +131,27 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
_timeout?.Change(Timeout.Infinite, Timeout.Infinite);
|
_timeout?.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var _ = _msg.DeleteAsync();
|
_= msg.DeleteAsync();
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
var os = OnEnded(_guild.Id);
|
_ = OnEnded?.Invoke(_guild.Id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Task HandleReaction(
|
private Task HandleReaction(
|
||||||
Cacheable<IUserMessage, ulong> msg,
|
Cacheable<IUserMessage, ulong> message,
|
||||||
Cacheable<IMessageChannel, ulong> cacheable,
|
Cacheable<IMessageChannel, ulong> cacheable,
|
||||||
SocketReaction r)
|
SocketReaction r)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (_emote.Name != r.Emote.Name)
|
if (emote.Name != r.Emote.Name)
|
||||||
return;
|
return;
|
||||||
if ((r.User.IsSpecified
|
if ((r.User.IsSpecified
|
||||||
? r.User.Value
|
? r.User.Value
|
||||||
: null) is not IGuildUser gu // no unknown users, as they could be bots, or alts
|
: null) is not IGuildUser gu // no unknown users, as they could be bots, or alts
|
||||||
|| msg.Id != _msg.Id // same message
|
|| message.Id != this.msg.Id // same message
|
||||||
|| gu.IsBot // no bots
|
|| gu.IsBot // no bots
|
||||||
|| (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5 // no recently created accounts
|
|| (DateTime.UtcNow - gu.CreatedAt).TotalDays <= 5 // no recently created accounts
|
||||||
|| (_noRecentlyJoinedServer
|
|| (_noRecentlyJoinedServer
|
||||||
@@ -177,7 +175,7 @@ public class ReactionEvent : ICurrencyEvent
|
|||||||
private bool TryTakeFromPot()
|
private bool TryTakeFromPot()
|
||||||
{
|
{
|
||||||
if (_isPotLimited)
|
if (_isPotLimited)
|
||||||
lock (potLock)
|
lock (_potLock)
|
||||||
{
|
{
|
||||||
if (PotSize < _amount)
|
if (PotSize < _amount)
|
||||||
return false;
|
return false;
|
||||||
|
@@ -26,8 +26,8 @@ public class PlantPickService : INService
|
|||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly GamblingConfigService _gss;
|
private readonly GamblingConfigService _gss;
|
||||||
|
|
||||||
public readonly ConcurrentHashSet<ulong> _generationChannels = new();
|
private readonly ConcurrentHashSet<ulong> _generationChannels;
|
||||||
private readonly SemaphoreSlim pickLock = new(1, 1);
|
private readonly SemaphoreSlim _pickLock = new(1, 1);
|
||||||
|
|
||||||
public PlantPickService(
|
public PlantPickService(
|
||||||
DbService db,
|
DbService db,
|
||||||
@@ -101,6 +101,7 @@ public class PlantPickService : INService
|
|||||||
/// Get a random currency image stream, with an optional password sticked onto it.
|
/// Get a random currency image stream, with an optional password sticked onto it.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pass">Optional password to add to top left corner.</param>
|
/// <param name="pass">Optional password to add to top left corner.</param>
|
||||||
|
/// <param name="extension">Extension of the file, defaults to png</param>
|
||||||
/// <returns>Stream of the currency image</returns>
|
/// <returns>Stream of the currency image</returns>
|
||||||
public Stream GetRandomCurrencyImage(string pass, out string extension)
|
public Stream GetRandomCurrencyImage(string pass, out string extension)
|
||||||
{
|
{
|
||||||
@@ -140,7 +141,7 @@ public class PlantPickService : INService
|
|||||||
pass = pass.TrimTo(10, true).ToLowerInvariant();
|
pass = pass.TrimTo(10, true).ToLowerInvariant();
|
||||||
using var img = Image.Load<Rgba32>(curImg, out var format);
|
using var img = Image.Load<Rgba32>(curImg, out var format);
|
||||||
// choose font size based on the image height, so that it's visible
|
// choose font size based on the image height, so that it's visible
|
||||||
var font = _fonts.NotoSans.CreateFont(img.Height / 12, FontStyle.Bold);
|
var font = _fonts.NotoSans.CreateFont(img.Height / 12.0f, FontStyle.Bold);
|
||||||
img.Mutate(x =>
|
img.Mutate(x =>
|
||||||
{
|
{
|
||||||
// measure the size of the text to be drawing
|
// measure the size of the text to be drawing
|
||||||
@@ -171,7 +172,7 @@ public class PlantPickService : INService
|
|||||||
if (!_generationChannels.Contains(channel.Id))
|
if (!_generationChannels.Contains(channel.Id))
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -245,7 +246,7 @@ public class PlantPickService : INService
|
|||||||
ulong uid,
|
ulong uid,
|
||||||
string pass)
|
string pass)
|
||||||
{
|
{
|
||||||
await pickLock.WaitAsync();
|
await _pickLock.WaitAsync();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
long amount;
|
long amount;
|
||||||
@@ -276,7 +277,7 @@ public class PlantPickService : INService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// delete all of the plant messages which have just been picked
|
// delete all of the plant messages which have just been picked
|
||||||
var _ = ch.DeleteMessagesAsync(ids);
|
_= ch.DeleteMessagesAsync(ids);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
@@ -285,7 +286,7 @@ public class PlantPickService : INService
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
pickLock.Release();
|
_pickLock.Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,14 +13,10 @@ public class CurrencyRaffleService : INService
|
|||||||
|
|
||||||
public Dictionary<ulong, CurrencyRaffleGame> Games { get; } = new();
|
public Dictionary<ulong, CurrencyRaffleGame> Games { get; } = new();
|
||||||
private readonly SemaphoreSlim _locker = new(1, 1);
|
private readonly SemaphoreSlim _locker = new(1, 1);
|
||||||
private readonly DbService _db;
|
|
||||||
private readonly ICurrencyService _cs;
|
private readonly ICurrencyService _cs;
|
||||||
|
|
||||||
public CurrencyRaffleService(DbService db, ICurrencyService cs)
|
public CurrencyRaffleService(ICurrencyService cs)
|
||||||
{
|
=> _cs = cs;
|
||||||
_db = db;
|
|
||||||
_cs = cs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(
|
public async Task<(CurrencyRaffleGame, JoinErrorType?)> JoinOrCreateGame(
|
||||||
ulong channelId,
|
ulong channelId,
|
||||||
@@ -57,7 +53,7 @@ public class CurrencyRaffleService : INService
|
|||||||
|
|
||||||
if (newGame)
|
if (newGame)
|
||||||
{
|
{
|
||||||
var _t = Task.Run(async () =>
|
_ = Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(60000);
|
await Task.Delay(60000);
|
||||||
await _locker.WaitAsync();
|
await _locker.WaitAsync();
|
||||||
@@ -68,7 +64,7 @@ public class CurrencyRaffleService : INService
|
|||||||
|
|
||||||
await _cs.AddAsync(winner.DiscordUser.Id, "Currency Raffle Win", won);
|
await _cs.AddAsync(winner.DiscordUser.Id, "Currency Raffle Win", won);
|
||||||
Games.Remove(channelId, out _);
|
Games.Remove(channelId, out _);
|
||||||
var oe = onEnded(winner.DiscordUser, won);
|
_ = onEnded(winner.DiscordUser, won);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
finally { _locker.Release(); }
|
finally { _locker.Release(); }
|
||||||
|
@@ -211,7 +211,7 @@ public partial class Gambling
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(1000);
|
await Task.Delay(1000);
|
||||||
_runningUsers.Remove(ctx.User.Id);
|
_runningUsers.Remove(ctx.User.Id);
|
||||||
|
@@ -127,7 +127,7 @@ public sealed class AcrophobiaGame : IDisposable
|
|||||||
|| !_usersWhoVoted.Add(userId))
|
|| !_usersWhoVoted.Add(userId))
|
||||||
break;
|
break;
|
||||||
++submissions[toVoteFor];
|
++submissions[toVoteFor];
|
||||||
var _ = Task.Run(() => OnUserVoted(userName));
|
_= Task.Run(() => OnUserVoted(userName));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -48,7 +48,7 @@ public partial class Games
|
|||||||
if (msg.Channel.Id != ctx.Channel.Id)
|
if (msg.Channel.Id != ctx.Channel.Id)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -85,7 +85,7 @@ public sealed class NunchiGame : IDisposable
|
|||||||
_killTimeout);
|
_killTimeout);
|
||||||
|
|
||||||
CurrentPhase = Phase.Playing;
|
CurrentPhase = Phase.Playing;
|
||||||
var _ = OnGameStarted?.Invoke(this);
|
_= OnGameStarted?.Invoke(this);
|
||||||
var __ = OnRoundStarted?.Invoke(this, CurrentNumber);
|
var __ = OnRoundStarted?.Invoke(this, CurrentNumber);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -122,7 +122,7 @@ public sealed class NunchiGame : IDisposable
|
|||||||
{
|
{
|
||||||
_killTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
_killTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
CurrentPhase = Phase.Ended;
|
CurrentPhase = Phase.Ended;
|
||||||
var _ = OnGameEnded?.Invoke(this, userTuple.Name);
|
_= OnGameEnded?.Invoke(this, userTuple.Name);
|
||||||
}
|
}
|
||||||
else // else just start the new round without the user who was the last
|
else // else just start the new round without the user who was the last
|
||||||
{
|
{
|
||||||
@@ -159,7 +159,7 @@ public sealed class NunchiGame : IDisposable
|
|||||||
{
|
{
|
||||||
_killTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
_killTimer.Change(Timeout.Infinite, Timeout.Infinite);
|
||||||
CurrentPhase = Phase.Ended;
|
CurrentPhase = Phase.Ended;
|
||||||
var _ = OnGameEnded?.Invoke(this, _participants.Count > 0 ? _participants.First().Name : null);
|
_= OnGameEnded?.Invoke(this, _participants.Count > 0 ? _participants.First().Name : null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -55,7 +55,7 @@ public partial class Games
|
|||||||
|
|
||||||
Task _client_MessageReceived(SocketMessage arg)
|
Task _client_MessageReceived(SocketMessage arg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
if (arg.Channel.Id != ctx.Channel.Id)
|
if (arg.Channel.Id != ctx.Channel.Id)
|
||||||
return;
|
return;
|
||||||
|
@@ -43,7 +43,7 @@ public class PollRunner
|
|||||||
if (!Poll.Votes.Add(voteObj))
|
if (!Poll.Votes.Add(voteObj))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var _ = OnVoted?.Invoke(msg, usr);
|
_= OnVoted?.Invoke(msg, usr);
|
||||||
}
|
}
|
||||||
finally { _locker.Release(); }
|
finally { _locker.Release(); }
|
||||||
|
|
||||||
|
@@ -117,7 +117,7 @@ public class TypingGame
|
|||||||
|
|
||||||
private Task AnswerReceived(SocketMessage imsg)
|
private Task AnswerReceived(SocketMessage imsg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -182,7 +182,7 @@ public class TicTacToe
|
|||||||
|
|
||||||
private Task Client_MessageReceived(SocketMessage msg)
|
private Task Client_MessageReceived(SocketMessage msg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await _moveLock.WaitAsync();
|
await _moveLock.WaitAsync();
|
||||||
try
|
try
|
||||||
|
@@ -28,7 +28,7 @@ public partial class Games
|
|||||||
{
|
{
|
||||||
if (_service.TicTacToeGames.TryGetValue(channel.Id, out var game))
|
if (_service.TicTacToeGames.TryGetValue(channel.Id, out var game))
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await game.Start((IGuildUser)ctx.User);
|
await game.Start((IGuildUser)ctx.User);
|
||||||
});
|
});
|
||||||
|
@@ -24,10 +24,10 @@ public class TriviaGame
|
|||||||
private readonly ICurrencyService _cs;
|
private readonly ICurrencyService _cs;
|
||||||
private readonly TriviaOptions _options;
|
private readonly TriviaOptions _options;
|
||||||
|
|
||||||
private CancellationTokenSource _triviaCancelSource;
|
private CancellationTokenSource triviaCancelSource;
|
||||||
|
|
||||||
private readonly TriviaQuestionPool _questionPool;
|
private readonly TriviaQuestionPool _questionPool;
|
||||||
private int _timeoutCount;
|
private int timeoutCount;
|
||||||
private readonly string _quitCommand;
|
private readonly string _quitCommand;
|
||||||
private readonly IEmbedBuilderService _eb;
|
private readonly IEmbedBuilderService _eb;
|
||||||
|
|
||||||
@@ -66,7 +66,7 @@ public class TriviaGame
|
|||||||
while (!ShouldStopGame)
|
while (!ShouldStopGame)
|
||||||
{
|
{
|
||||||
// reset the cancellation source
|
// reset the cancellation source
|
||||||
_triviaCancelSource = new();
|
triviaCancelSource = new();
|
||||||
showHowToQuit = !showHowToQuit;
|
showHowToQuit = !showHowToQuit;
|
||||||
|
|
||||||
// load question
|
// load question
|
||||||
@@ -121,7 +121,7 @@ public class TriviaGame
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
//hint
|
//hint
|
||||||
await Task.Delay(_options.QuestionTimer * 1000 / 2, _triviaCancelSource.Token);
|
await Task.Delay(_options.QuestionTimer * 1000 / 2, triviaCancelSource.Token);
|
||||||
if (!_options.NoHint)
|
if (!_options.NoHint)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -136,9 +136,9 @@ public class TriviaGame
|
|||||||
catch (Exception ex) { Log.Warning(ex, "Error editing triva message"); }
|
catch (Exception ex) { Log.Warning(ex, "Error editing triva message"); }
|
||||||
|
|
||||||
//timeout
|
//timeout
|
||||||
await Task.Delay(_options.QuestionTimer * 1000 / 2, _triviaCancelSource.Token);
|
await Task.Delay(_options.QuestionTimer * 1000 / 2, triviaCancelSource.Token);
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException) { _timeoutCount = 0; } //means someone guessed the answer
|
catch (TaskCanceledException) { timeoutCount = 0; } //means someone guessed the answer
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
@@ -146,7 +146,7 @@ public class TriviaGame
|
|||||||
_client.MessageReceived -= PotentialGuess;
|
_client.MessageReceived -= PotentialGuess;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_triviaCancelSource.IsCancellationRequested)
|
if (!triviaCancelSource.IsCancellationRequested)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
@@ -158,7 +158,7 @@ public class TriviaGame
|
|||||||
|
|
||||||
await Channel.EmbedAsync(embed);
|
await Channel.EmbedAsync(embed);
|
||||||
|
|
||||||
if (_options.Timeout != 0 && ++_timeoutCount >= _options.Timeout)
|
if (_options.Timeout != 0 && ++timeoutCount >= _options.Timeout)
|
||||||
await StopGame();
|
await StopGame();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
@@ -198,7 +198,7 @@ public class TriviaGame
|
|||||||
|
|
||||||
private Task PotentialGuess(SocketMessage imsg)
|
private Task PotentialGuess(SocketMessage imsg)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -218,7 +218,7 @@ public class TriviaGame
|
|||||||
{
|
{
|
||||||
if (GameActive
|
if (GameActive
|
||||||
&& CurrentQuestion.IsAnswerCorrect(umsg.Content)
|
&& CurrentQuestion.IsAnswerCorrect(umsg.Content)
|
||||||
&& !_triviaCancelSource.IsCancellationRequested)
|
&& !triviaCancelSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
Users.AddOrUpdate(guildUser, 1, (_, old) => ++old);
|
Users.AddOrUpdate(guildUser, 1, (_, old) => ++old);
|
||||||
guess = true;
|
guess = true;
|
||||||
@@ -227,7 +227,7 @@ public class TriviaGame
|
|||||||
finally { _guessLock.Release(); }
|
finally { _guessLock.Release(); }
|
||||||
|
|
||||||
if (!guess) return;
|
if (!guess) return;
|
||||||
_triviaCancelSource.Cancel();
|
triviaCancelSource.Cancel();
|
||||||
|
|
||||||
|
|
||||||
if (_options.WinRequirement != 0 && Users[guildUser] == _options.WinRequirement)
|
if (_options.WinRequirement != 0 && Users[guildUser] == _options.WinRequirement)
|
||||||
|
@@ -21,9 +21,9 @@ public class TriviaQuestion
|
|||||||
public string Answer { get; set; }
|
public string Answer { get; set; }
|
||||||
|
|
||||||
public string CleanAnswer
|
public string CleanAnswer
|
||||||
=> _cleanAnswer ?? (_cleanAnswer = Clean(Answer));
|
=> cleanAnswer ?? (cleanAnswer = Clean(Answer));
|
||||||
|
|
||||||
private string _cleanAnswer;
|
private string cleanAnswer;
|
||||||
|
|
||||||
public TriviaQuestion(
|
public TriviaQuestion(
|
||||||
string q,
|
string q,
|
||||||
|
@@ -52,7 +52,7 @@ public sealed partial class YtLoader
|
|||||||
|
|
||||||
public sealed class YtTrackInfo : TrackInfo
|
public sealed class YtTrackInfo : TrackInfo
|
||||||
{
|
{
|
||||||
private const string BaseYoutubeUrl = "https://youtube.com/watch?v=";
|
private const string BASE_YOUTUBE_URL = "https://youtube.com/watch?v=";
|
||||||
public override string Url { get; }
|
public override string Url { get; }
|
||||||
public override string Title { get; }
|
public override string Title { get; }
|
||||||
public override TimeSpan Duration { get; }
|
public override TimeSpan Duration { get; }
|
||||||
@@ -62,7 +62,7 @@ public sealed partial class YtLoader
|
|||||||
public YtTrackInfo(string title, string videoId, TimeSpan duration)
|
public YtTrackInfo(string title, string videoId, TimeSpan duration)
|
||||||
{
|
{
|
||||||
Title = title;
|
Title = title;
|
||||||
Url = BaseYoutubeUrl + videoId;
|
Url = BASE_YOUTUBE_URL + videoId;
|
||||||
Duration = duration;
|
Duration = duration;
|
||||||
|
|
||||||
_videoId = videoId;
|
_videoId = videoId;
|
||||||
|
@@ -7,10 +7,10 @@ namespace NadekoBot.Modules.Music.Services;
|
|||||||
|
|
||||||
public sealed partial class YtLoader
|
public sealed partial class YtLoader
|
||||||
{
|
{
|
||||||
private static readonly byte[] YT_RESULT_INITIAL_DATA = Encoding.UTF8.GetBytes("var ytInitialData = ");
|
private static readonly byte[] _ytResultInitialData = Encoding.UTF8.GetBytes("var ytInitialData = ");
|
||||||
private static readonly byte[] YT_RESULT_JSON_END = Encoding.UTF8.GetBytes(";<");
|
private static readonly byte[] _ytResultJsonEnd = Encoding.UTF8.GetBytes(";<");
|
||||||
|
|
||||||
private static readonly string[] durationFormats =
|
private static readonly string[] _durationFormats =
|
||||||
{
|
{
|
||||||
@"m\:ss", @"mm\:ss", @"h\:mm\:ss", @"hh\:mm\:ss", @"hhh\:mm\:ss"
|
@"m\:ss", @"mm\:ss", @"h\:mm\:ss", @"hh\:mm\:ss", @"hhh\:mm\:ss"
|
||||||
};
|
};
|
||||||
@@ -98,7 +98,7 @@ public sealed partial class YtLoader
|
|||||||
var durationString = elem.GetProperty("lengthText").GetProperty("simpleText").GetString();
|
var durationString = elem.GetProperty("lengthText").GetProperty("simpleText").GetString();
|
||||||
|
|
||||||
if (!TimeSpan.TryParseExact(durationString,
|
if (!TimeSpan.TryParseExact(durationString,
|
||||||
durationFormats,
|
_durationFormats,
|
||||||
CultureInfo.InvariantCulture,
|
CultureInfo.InvariantCulture,
|
||||||
out var duration))
|
out var duration))
|
||||||
{
|
{
|
||||||
@@ -117,13 +117,13 @@ public sealed partial class YtLoader
|
|||||||
private Memory<byte> GetScriptResponseSpan(byte[] response)
|
private Memory<byte> GetScriptResponseSpan(byte[] response)
|
||||||
{
|
{
|
||||||
var responseSpan = response.AsSpan()[140_000..];
|
var responseSpan = response.AsSpan()[140_000..];
|
||||||
var startIndex = responseSpan.IndexOf(YT_RESULT_INITIAL_DATA);
|
var startIndex = responseSpan.IndexOf(_ytResultInitialData);
|
||||||
if (startIndex == -1)
|
if (startIndex == -1)
|
||||||
return null; // todo future try selecting html
|
return null; // todo future try selecting html
|
||||||
startIndex += YT_RESULT_INITIAL_DATA.Length;
|
startIndex += _ytResultInitialData.Length;
|
||||||
|
|
||||||
var endIndex =
|
var endIndex =
|
||||||
140_000 + startIndex + responseSpan[(startIndex + 20_000)..].IndexOf(YT_RESULT_JSON_END) + 20_000;
|
140_000 + startIndex + responseSpan[(startIndex + 20_000)..].IndexOf(_ytResultJsonEnd) + 20_000;
|
||||||
startIndex += 140_000;
|
startIndex += 140_000;
|
||||||
return response.AsMemory(startIndex, endIndex - startIndex);
|
return response.AsMemory(startIndex, endIndex - startIndex);
|
||||||
}
|
}
|
||||||
|
@@ -42,9 +42,9 @@ public sealed partial class MusicQueue : IMusicQueue
|
|||||||
{
|
{
|
||||||
// just make sure the internal logic runs first
|
// just make sure the internal logic runs first
|
||||||
// to make sure that some potential indermediate value is not returned
|
// to make sure that some potential indermediate value is not returned
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
return _index;
|
return index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,128 +53,128 @@ public sealed partial class MusicQueue : IMusicQueue
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
return _tracks.Count;
|
return tracks.Count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private LinkedList<QueuedTrackInfo> _tracks;
|
private LinkedList<QueuedTrackInfo> tracks;
|
||||||
|
|
||||||
private int _index;
|
private int index;
|
||||||
|
|
||||||
private readonly object locker = new();
|
private readonly object _locker = new();
|
||||||
|
|
||||||
public MusicQueue()
|
public MusicQueue()
|
||||||
{
|
{
|
||||||
_index = 0;
|
index = 0;
|
||||||
_tracks = new();
|
tracks = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQueuedTrackInfo Enqueue(ITrackInfo trackInfo, string queuer, out int index)
|
public IQueuedTrackInfo Enqueue(ITrackInfo trackInfo, string queuer, out int enqueuedAt)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
var added = new QueuedTrackInfo(trackInfo, queuer);
|
var added = new QueuedTrackInfo(trackInfo, queuer);
|
||||||
index = _tracks.Count;
|
enqueuedAt = tracks.Count;
|
||||||
_tracks.AddLast(added);
|
tracks.AddLast(added);
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQueuedTrackInfo EnqueueNext(ITrackInfo trackInfo, string queuer, out int index)
|
public IQueuedTrackInfo EnqueueNext(ITrackInfo trackInfo, string queuer, out int trackIndex)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
if (_tracks.Count == 0) return Enqueue(trackInfo, queuer, out index);
|
if (tracks.Count == 0) return Enqueue(trackInfo, queuer, out trackIndex);
|
||||||
|
|
||||||
var currentNode = _tracks.First!;
|
var currentNode = tracks.First!;
|
||||||
int i;
|
int i;
|
||||||
for (i = 1; i <= _index; i++)
|
for (i = 1; i <= this.index; i++)
|
||||||
currentNode = currentNode.Next!; // can't be null because index is always in range of the count
|
currentNode = currentNode.Next!; // can't be null because index is always in range of the count
|
||||||
|
|
||||||
var added = new QueuedTrackInfo(trackInfo, queuer);
|
var added = new QueuedTrackInfo(trackInfo, queuer);
|
||||||
index = i;
|
trackIndex = i;
|
||||||
|
|
||||||
_tracks.AddAfter(currentNode, added);
|
tracks.AddAfter(currentNode, added);
|
||||||
|
|
||||||
return added;
|
return added;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void EnqueueMany(IEnumerable<ITrackInfo> tracks, string queuer)
|
public void EnqueueMany(IEnumerable<ITrackInfo> toEnqueue, string queuer)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
foreach (var track in tracks)
|
foreach (var track in toEnqueue)
|
||||||
{
|
{
|
||||||
var added = new QueuedTrackInfo(track, queuer);
|
var added = new QueuedTrackInfo(track, queuer);
|
||||||
_tracks.AddLast(added);
|
this.tracks.AddLast(added);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyCollection<IQueuedTrackInfo> List()
|
public IReadOnlyCollection<IQueuedTrackInfo> List()
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
return _tracks.ToList();
|
return tracks.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQueuedTrackInfo? GetCurrent(out int index)
|
public IQueuedTrackInfo? GetCurrent(out int currentIndex)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
index = _index;
|
currentIndex = index;
|
||||||
return _tracks.ElementAtOrDefault(_index);
|
return tracks.ElementAtOrDefault(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Advance()
|
public void Advance()
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
if (++_index >= _tracks.Count)
|
if (++index >= tracks.Count)
|
||||||
_index = 0;
|
index = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
public void Clear()
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
_tracks.Clear();
|
tracks.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SetIndex(int index)
|
public bool SetIndex(int newIndex)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= _tracks.Count)
|
if (newIndex < 0 || newIndex >= tracks.Count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
_index = index;
|
this.index = newIndex;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RemoveAtInternal(int index, out IQueuedTrackInfo trackInfo)
|
private void RemoveAtInternal(int remoteAtIndex, out IQueuedTrackInfo trackInfo)
|
||||||
{
|
{
|
||||||
var removedNode = _tracks.First!;
|
var removedNode = tracks.First!;
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < index; i++) removedNode = removedNode.Next!;
|
for (i = 0; i < remoteAtIndex; i++) removedNode = removedNode.Next!;
|
||||||
|
|
||||||
trackInfo = removedNode.Value;
|
trackInfo = removedNode.Value;
|
||||||
_tracks.Remove(removedNode);
|
tracks.Remove(removedNode);
|
||||||
|
|
||||||
if (i <= _index)
|
if (i <= this.index)
|
||||||
--_index;
|
--this.index;
|
||||||
|
|
||||||
if (_index < 0)
|
if (this.index < 0)
|
||||||
_index = Count;
|
this.index = Count;
|
||||||
|
|
||||||
// if it was the last song in the queue
|
// if it was the last song in the queue
|
||||||
// // wrap back to start
|
// // wrap back to start
|
||||||
@@ -188,10 +188,10 @@ public sealed partial class MusicQueue : IMusicQueue
|
|||||||
|
|
||||||
public void RemoveCurrent()
|
public void RemoveCurrent()
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
if (_index < _tracks.Count)
|
if (index < tracks.Count)
|
||||||
RemoveAtInternal(_index, out _);
|
RemoveAtInternal(index, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,29 +204,29 @@ public sealed partial class MusicQueue : IMusicQueue
|
|||||||
if (to == from)
|
if (to == from)
|
||||||
throw new ArgumentException($"{nameof(from)} and {nameof(to)} must be different");
|
throw new ArgumentException($"{nameof(from)} and {nameof(to)} must be different");
|
||||||
|
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
if (from >= Count || to >= Count)
|
if (from >= Count || to >= Count)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// update current track index
|
// update current track index
|
||||||
if (from == _index)
|
if (from == index)
|
||||||
{
|
{
|
||||||
// if the song being moved is the current track
|
// if the song being moved is the current track
|
||||||
// it means that it will for sure end up on the destination
|
// it means that it will for sure end up on the destination
|
||||||
_index = to;
|
index = to;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// moving a track from below the current track means
|
// moving a track from below the current track means
|
||||||
// means it will drop down
|
// means it will drop down
|
||||||
if (from < _index)
|
if (from < index)
|
||||||
_index--;
|
index--;
|
||||||
|
|
||||||
// moving a track to below the current track
|
// moving a track to below the current track
|
||||||
// means it will rise up
|
// means it will rise up
|
||||||
if (to <= _index)
|
if (to <= index)
|
||||||
_index++;
|
index++;
|
||||||
|
|
||||||
|
|
||||||
// if both from and to are below _index - net change is + 1 - 1 = 0
|
// if both from and to are below _index - net change is + 1 - 1 = 0
|
||||||
@@ -236,78 +236,76 @@ public sealed partial class MusicQueue : IMusicQueue
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the node which needs to be moved
|
// get the node which needs to be moved
|
||||||
var fromNode = _tracks.First!;
|
var fromNode = tracks.First!;
|
||||||
for (var i = 0; i < from; i++)
|
for (var i = 0; i < from; i++)
|
||||||
fromNode = fromNode.Next!;
|
fromNode = fromNode.Next!;
|
||||||
|
|
||||||
// remove it from the queue
|
// remove it from the queue
|
||||||
_tracks.Remove(fromNode);
|
tracks.Remove(fromNode);
|
||||||
|
|
||||||
// if it needs to be added as a first node,
|
// if it needs to be added as a first node,
|
||||||
// add it directly and return
|
// add it directly and return
|
||||||
if (to == 0)
|
if (to == 0)
|
||||||
{
|
{
|
||||||
_tracks.AddFirst(fromNode);
|
tracks.AddFirst(fromNode);
|
||||||
return fromNode.Value;
|
return fromNode.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// else find the node at the index before the specified target
|
// else find the node at the index before the specified target
|
||||||
var addAfterNode = _tracks.First!;
|
var addAfterNode = tracks.First!;
|
||||||
for (var i = 1; i < to; i++)
|
for (var i = 1; i < to; i++)
|
||||||
addAfterNode = addAfterNode.Next!;
|
addAfterNode = addAfterNode.Next!;
|
||||||
|
|
||||||
// and add after it
|
// and add after it
|
||||||
_tracks.AddAfter(addAfterNode, fromNode);
|
tracks.AddAfter(addAfterNode, fromNode);
|
||||||
return fromNode.Value;
|
return fromNode.Value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Shuffle(Random rng)
|
public void Shuffle(Random rng)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
var list = _tracks.ToList();
|
var list = tracks.ToList();
|
||||||
|
|
||||||
for (var i = 0; i < list.Count; i++)
|
for (var i = 0; i < list.Count; i++)
|
||||||
{
|
{
|
||||||
var struck = rng.Next(i, list.Count);
|
var struck = rng.Next(i, list.Count);
|
||||||
var temp = list[struck];
|
(list[struck], list[i]) = (list[i], list[struck]);
|
||||||
list[struck] = list[i];
|
|
||||||
list[i] = temp;
|
|
||||||
|
|
||||||
// could preserving the index during shuffling be done better?
|
// could preserving the index during shuffling be done better?
|
||||||
if (i == _index)
|
if (i == index)
|
||||||
_index = struck;
|
index = struck;
|
||||||
else if (struck == _index)
|
else if (struck == index)
|
||||||
_index = i;
|
index = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
_tracks = new(list);
|
tracks = new(list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsLast()
|
public bool IsLast()
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
return _index == _tracks.Count // if there are no tracks
|
return index == tracks.Count // if there are no tracks
|
||||||
|| _index == _tracks.Count - 1;
|
|| index == tracks.Count - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryRemoveAt(int index, out IQueuedTrackInfo? trackInfo, out bool isCurrent)
|
public bool TryRemoveAt(int remoteAt, out IQueuedTrackInfo? trackInfo, out bool isCurrent)
|
||||||
{
|
{
|
||||||
lock (locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
isCurrent = false;
|
isCurrent = false;
|
||||||
trackInfo = null;
|
trackInfo = null;
|
||||||
|
|
||||||
if (index < 0 || index >= _tracks.Count)
|
if (remoteAt < 0 || remoteAt >= tracks.Count)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (index == _index) isCurrent = true;
|
if (remoteAt == this.index) isCurrent = true;
|
||||||
|
|
||||||
RemoveAtInternal(index, out trackInfo);
|
RemoveAtInternal(remoteAt, out trackInfo);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,7 @@ public sealed class VoiceProxy : IVoiceProxy
|
|||||||
private const int DELAY_ON_ERROR_MILISECONDS = 200;
|
private const int DELAY_ON_ERROR_MILISECONDS = 200;
|
||||||
|
|
||||||
public VoiceProxyState State
|
public VoiceProxyState State
|
||||||
=> _gateway switch
|
=> gateway switch
|
||||||
{
|
{
|
||||||
{ Started: true, Stopped: false } => VoiceProxyState.Started,
|
{ Started: true, Stopped: false } => VoiceProxyState.Started,
|
||||||
{ Stopped: false } => VoiceProxyState.Created,
|
{ Stopped: false } => VoiceProxyState.Created,
|
||||||
@@ -25,16 +25,16 @@ public sealed class VoiceProxy : IVoiceProxy
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
private VoiceGateway _gateway;
|
private VoiceGateway gateway;
|
||||||
|
|
||||||
public VoiceProxy(VoiceGateway initial)
|
public VoiceProxy(VoiceGateway initial)
|
||||||
=> _gateway = initial;
|
=> gateway = initial;
|
||||||
|
|
||||||
public bool SendPcmFrame(VoiceClient vc, Span<byte> data, int length)
|
public bool SendPcmFrame(VoiceClient vc, Span<byte> data, int length)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gw = _gateway;
|
var gw = gateway;
|
||||||
if (gw is null || gw.Stopped || !gw.Started) return false;
|
if (gw is null || gw.Stopped || !gw.Started) return false;
|
||||||
|
|
||||||
vc.SendPcmFrame(gw, data, 0, length);
|
vc.SendPcmFrame(gw, data, 0, length);
|
||||||
@@ -55,7 +55,7 @@ public sealed class VoiceProxy : IVoiceProxy
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var gw = _gateway;
|
var gw = gateway;
|
||||||
if (gw is null || !gw.ConnectingFinished.Task.IsCompleted)
|
if (gw is null || !gw.ConnectingFinished.Task.IsCompleted)
|
||||||
{
|
{
|
||||||
++errorCount;
|
++errorCount;
|
||||||
@@ -78,8 +78,8 @@ public sealed class VoiceProxy : IVoiceProxy
|
|||||||
return State != VoiceProxyState.Stopped && errorCount <= MAX_ERROR_COUNT;
|
return State != VoiceProxyState.Stopped && errorCount <= MAX_ERROR_COUNT;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetGateway(VoiceGateway gateway)
|
public void SetGateway(VoiceGateway newGateway)
|
||||||
=> _gateway = gateway;
|
=> gateway = newGateway;
|
||||||
|
|
||||||
public Task StartSpeakingAsync()
|
public Task StartSpeakingAsync()
|
||||||
=> RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.Microphone));
|
=> RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.Microphone));
|
||||||
@@ -88,11 +88,11 @@ public sealed class VoiceProxy : IVoiceProxy
|
|||||||
=> RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.None));
|
=> RunGatewayAction(gw => gw.SendSpeakingAsync(VoiceSpeaking.State.None));
|
||||||
|
|
||||||
public async Task StartGateway()
|
public async Task StartGateway()
|
||||||
=> await _gateway.Start();
|
=> await gateway.Start();
|
||||||
|
|
||||||
public Task StopGateway()
|
public Task StopGateway()
|
||||||
{
|
{
|
||||||
if (_gateway is { } gw)
|
if (gateway is { } gw)
|
||||||
return gw.StopAsync();
|
return gw.StopAsync();
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@@ -45,7 +45,8 @@ public sealed class LocalTrackResolver : ILocalTrackResolver
|
|||||||
if (!x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)
|
if (!x.Attributes.HasFlag(FileAttributes.Hidden | FileAttributes.System)
|
||||||
&& _musicExtensions.Contains(x.Extension.ToUpperInvariant())) return true;
|
&& _musicExtensions.Contains(x.Extension.ToUpperInvariant())) return true;
|
||||||
return false;
|
return false;
|
||||||
});
|
})
|
||||||
|
.ToList();
|
||||||
|
|
||||||
var firstFile = files.FirstOrDefault()?.FullName;
|
var firstFile = files.FirstOrDefault()?.FullName;
|
||||||
if (firstFile is null)
|
if (firstFile is null)
|
||||||
|
@@ -5,7 +5,7 @@ namespace NadekoBot.Modules.Nsfw.Common;
|
|||||||
|
|
||||||
public class SearchImageCacher : INService
|
public class SearchImageCacher : INService
|
||||||
{
|
{
|
||||||
private static readonly ISet<string> defaultTagBlacklist = new HashSet<string>
|
private static readonly ISet<string> _defaultTagBlacklist = new HashSet<string>
|
||||||
{
|
{
|
||||||
"loli",
|
"loli",
|
||||||
"lolicon",
|
"lolicon",
|
||||||
@@ -21,7 +21,7 @@ public class SearchImageCacher : INService
|
|||||||
private readonly Dictionary<Booru, HashSet<string>> _usedTags = new();
|
private readonly Dictionary<Booru, HashSet<string>> _usedTags = new();
|
||||||
private readonly IMemoryCache _cache;
|
private readonly IMemoryCache _cache;
|
||||||
|
|
||||||
private readonly ConcurrentDictionary<(Booru, string), int> maxPages = new();
|
private readonly ConcurrentDictionary<(Booru, string), int> _maxPages = new();
|
||||||
|
|
||||||
public SearchImageCacher(IHttpClientFactory httpFactory, IMemoryCache cache)
|
public SearchImageCacher(IHttpClientFactory httpFactory, IMemoryCache cache)
|
||||||
{
|
{
|
||||||
@@ -59,7 +59,7 @@ public class SearchImageCacher : INService
|
|||||||
// Log.Warning("Got no images for {0}, tags: {1}", type, string.Join(", ", tags));
|
// Log.Warning("Got no images for {0}, tags: {1}", type, string.Join(", ", tags));
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Log.Information("Updating {0}...", type);
|
Log.Information("Updating {Type}...", type);
|
||||||
lock (_typeLocks[type])
|
lock (_typeLocks[type])
|
||||||
{
|
{
|
||||||
var typeUsedTags = _usedTags[type];
|
var typeUsedTags = _usedTags[type];
|
||||||
@@ -75,7 +75,7 @@ public class SearchImageCacher : INService
|
|||||||
{
|
{
|
||||||
// if any of the tags is a tag banned by discord
|
// if any of the tags is a tag banned by discord
|
||||||
// do not put that image in the cache
|
// do not put that image in the cache
|
||||||
if (defaultTagBlacklist.Overlaps(img.Tags))
|
if (_defaultTagBlacklist.Overlaps(img.Tags))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// if image doesn't have a proper absolute uri, skip it
|
// if image doesn't have a proper absolute uri, skip it
|
||||||
@@ -190,7 +190,7 @@ public class SearchImageCacher : INService
|
|||||||
tags = tags[..2];
|
tags = tags[..2];
|
||||||
|
|
||||||
// use both tags banned by discord and tags banned on the server
|
// use both tags banned by discord and tags banned on the server
|
||||||
if (blacklistedTags.Overlaps(tags) || defaultTagBlacklist.Overlaps(tags))
|
if (blacklistedTags.Overlaps(tags) || _defaultTagBlacklist.Overlaps(tags))
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
// query for an image
|
// query for an image
|
||||||
@@ -223,16 +223,16 @@ public class SearchImageCacher : INService
|
|||||||
CancellationToken cancel)
|
CancellationToken cancel)
|
||||||
{
|
{
|
||||||
var tagStr = string.Join(' ', tags.OrderByDescending(x => x));
|
var tagStr = string.Join(' ', tags.OrderByDescending(x => x));
|
||||||
var page = 0;
|
|
||||||
|
|
||||||
var attempt = 0;
|
var attempt = 0;
|
||||||
while (attempt++ <= 10)
|
while (attempt++ <= 10)
|
||||||
{
|
{
|
||||||
if (maxPages.TryGetValue((type, tagStr), out var maxPage))
|
int page;
|
||||||
|
if (_maxPages.TryGetValue((type, tagStr), out var maxPage))
|
||||||
{
|
{
|
||||||
if (maxPage == 0)
|
if (maxPage == 0)
|
||||||
{
|
{
|
||||||
Log.Information("Tag {0} yields no result on {1}, skipping.", tagStr, type);
|
Log.Information("Tag {Tags} yields no result on {Type}, skipping", tagStr, type);
|
||||||
return new();
|
return new();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -247,7 +247,7 @@ public class SearchImageCacher : INService
|
|||||||
|
|
||||||
if (result is null or { Count: 0 })
|
if (result is null or { Count: 0 })
|
||||||
{
|
{
|
||||||
Log.Information("Tag {0}, page {1} has no result on {2}.",
|
Log.Information("Tag {Tags}, page {Page} has no result on {Type}",
|
||||||
string.Join(", ", tags),
|
string.Join(", ", tags),
|
||||||
page,
|
page,
|
||||||
type.ToString());
|
type.ToString());
|
||||||
@@ -284,7 +284,7 @@ public class SearchImageCacher : INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.Information("Downloading from {0} (page {1})...", type, page);
|
Log.Information("Downloading from {Type} (page {Page})...", type, page);
|
||||||
|
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var downloader = GetImageDownloader(type, http);
|
var downloader = GetImageDownloader(type, http);
|
||||||
@@ -293,7 +293,7 @@ public class SearchImageCacher : INService
|
|||||||
if (images.Count == 0)
|
if (images.Count == 0)
|
||||||
{
|
{
|
||||||
var tagStr = string.Join(' ', tags.OrderByDescending(x => x));
|
var tagStr = string.Join(' ', tags.OrderByDescending(x => x));
|
||||||
maxPages[(type, tagStr)] = page;
|
_maxPages[(type, tagStr)] = page;
|
||||||
}
|
}
|
||||||
|
|
||||||
return images;
|
return images;
|
||||||
@@ -305,7 +305,7 @@ public class SearchImageCacher : INService
|
|||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
Log.Error(ex,
|
Log.Error(ex,
|
||||||
"Error downloading an image:\nTags: {0}\nType: {1}\nPage: {2}\nMessage: {3}",
|
"Error downloading an image:\nTags: {Tags}\nType: {Type}\nPage: {Page}\nMessage: {Message}",
|
||||||
string.Join(", ", tags),
|
string.Join(", ", tags),
|
||||||
type,
|
type,
|
||||||
page,
|
page,
|
||||||
|
@@ -14,9 +14,9 @@ public sealed class BlacklistService : IEarlyBehavior
|
|||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly IPubSub _pubSub;
|
private readonly IPubSub _pubSub;
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
private IReadOnlyList<BlacklistEntry> _blacklist;
|
private IReadOnlyList<BlacklistEntry> blacklist;
|
||||||
|
|
||||||
private readonly TypedKey<BlacklistEntry[]> blPubKey = new("blacklist.reload");
|
private readonly TypedKey<BlacklistEntry[]> _blPubKey = new("blacklist.reload");
|
||||||
|
|
||||||
public BlacklistService(DbService db, IPubSub pubSub, IBotCredentials creds)
|
public BlacklistService(DbService db, IPubSub pubSub, IBotCredentials creds)
|
||||||
{
|
{
|
||||||
@@ -25,18 +25,18 @@ public sealed class BlacklistService : IEarlyBehavior
|
|||||||
_creds = creds;
|
_creds = creds;
|
||||||
|
|
||||||
Reload(false);
|
Reload(false);
|
||||||
_pubSub.Sub(blPubKey, OnReload);
|
_pubSub.Sub(_blPubKey, OnReload);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTask OnReload(BlacklistEntry[] blacklist)
|
private ValueTask OnReload(BlacklistEntry[] newBlacklist)
|
||||||
{
|
{
|
||||||
_blacklist = blacklist;
|
this.blacklist = newBlacklist;
|
||||||
return default;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> RunBehavior(IGuild guild, IUserMessage usrMsg)
|
public Task<bool> RunBehavior(IGuild guild, IUserMessage usrMsg)
|
||||||
{
|
{
|
||||||
foreach (var bl in _blacklist)
|
foreach (var bl in blacklist)
|
||||||
{
|
{
|
||||||
if (guild is not null && bl.Type == BlacklistType.Server && bl.ItemId == guild.Id)
|
if (guild is not null && bl.Type == BlacklistType.Server && bl.ItemId == guild.Id)
|
||||||
{
|
{
|
||||||
@@ -68,14 +68,14 @@ public sealed class BlacklistService : IEarlyBehavior
|
|||||||
}
|
}
|
||||||
|
|
||||||
public IReadOnlyList<BlacklistEntry> GetBlacklist()
|
public IReadOnlyList<BlacklistEntry> GetBlacklist()
|
||||||
=> _blacklist;
|
=> blacklist;
|
||||||
|
|
||||||
public void Reload(bool publish = true)
|
public void Reload(bool publish = true)
|
||||||
{
|
{
|
||||||
using var uow = _db.GetDbContext();
|
using var uow = _db.GetDbContext();
|
||||||
var toPublish = uow.Blacklist.AsNoTracking().ToArray();
|
var toPublish = uow.Blacklist.AsNoTracking().ToArray();
|
||||||
_blacklist = toPublish;
|
blacklist = toPublish;
|
||||||
if (publish) _pubSub.Pub(blPubKey, toPublish);
|
if (publish) _pubSub.Pub(_blPubKey, toPublish);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Blacklist(BlacklistType type, ulong id)
|
public void Blacklist(BlacklistType type, ulong id)
|
||||||
|
@@ -30,7 +30,7 @@ public class CmdCdService : ILateBlocker, INService
|
|||||||
|
|
||||||
activeCdsForGuild.Add(new() { UserId = user.Id, Command = commandName });
|
activeCdsForGuild.Add(new() { UserId = user.Id, Command = commandName });
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@@ -62,7 +62,7 @@ public sealed class FilterService : IEarlyBehavior
|
|||||||
|
|
||||||
client.MessageUpdated += (oldData, newMsg, channel) =>
|
client.MessageUpdated += (oldData, newMsg, channel) =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
var guild = (channel as ITextChannel)?.Guild;
|
var guild = (channel as ITextChannel)?.Guild;
|
||||||
|
|
||||||
|
@@ -60,8 +60,8 @@ public class CryptoService : INService
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var _http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var strData = await _http.GetStringAsync(
|
var strData = await http.GetStringAsync(
|
||||||
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?"
|
"https://pro-api.coinmarketcap.com/v1/cryptocurrency/listings/latest?"
|
||||||
+ $"CMC_PRO_API_KEY={_creds.CoinmarketcapApiKey}"
|
+ $"CMC_PRO_API_KEY={_creds.CoinmarketcapApiKey}"
|
||||||
+ "&start=1"
|
+ "&start=1"
|
||||||
|
@@ -40,7 +40,7 @@ public class FeedsService : INService
|
|||||||
_client = client;
|
_client = client;
|
||||||
_eb = eb;
|
_eb = eb;
|
||||||
|
|
||||||
var _ = Task.Run(TrackFeeds);
|
_= Task.Run(TrackFeeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<EmbedBuilder> TrackFeeds()
|
public async Task<EmbedBuilder> TrackFeeds()
|
||||||
|
@@ -477,7 +477,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
|||||||
if (!await ValidateQuery(word))
|
if (!await ValidateQuery(word))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using var _http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
string res;
|
string res;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -485,7 +485,7 @@ public partial class Searches : NadekoModule<SearchesService>
|
|||||||
e =>
|
e =>
|
||||||
{
|
{
|
||||||
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
|
e.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(12);
|
||||||
return _http.GetStringAsync("https://api.pearson.com/v2/dictionaries/entries?headword="
|
return http.GetStringAsync("https://api.pearson.com/v2/dictionaries/entries?headword="
|
||||||
+ WebUtility.UrlEncode(word));
|
+ WebUtility.UrlEncode(word));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@@ -430,8 +430,8 @@ public class SearchesService : INService
|
|||||||
{
|
{
|
||||||
var redis = _cache.Redis;
|
var redis = _cache.Redis;
|
||||||
var db = redis.GetDatabase();
|
var db = redis.GetDatabase();
|
||||||
const string STEAM_GAME_IDS_KEY = "steam_names_to_appid";
|
const string steamGameIdsKey = "steam_names_to_appid";
|
||||||
var exists = await db.KeyExistsAsync(STEAM_GAME_IDS_KEY);
|
// var exists = await db.KeyExistsAsync(steamGameIdsKey);
|
||||||
|
|
||||||
// if we didn't get steam name to id map already, get it
|
// if we didn't get steam name to id map already, get it
|
||||||
//if (!exists)
|
//if (!exists)
|
||||||
@@ -448,7 +448,7 @@ public class SearchesService : INService
|
|||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
var gamesMap = await _cache.GetOrAddCachedDataAsync(STEAM_GAME_IDS_KEY,
|
var gamesMap = await _cache.GetOrAddCachedDataAsync(steamGameIdsKey,
|
||||||
async _ =>
|
async _ =>
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
|
@@ -8,7 +8,7 @@ public partial class Searches
|
|||||||
[Group]
|
[Group]
|
||||||
public partial class XkcdCommands : NadekoSubmodule
|
public partial class XkcdCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private const string _xkcdUrl = "https://xkcd.com";
|
private const string XKCD_URL = "https://xkcd.com";
|
||||||
private readonly IHttpClientFactory _httpFactory;
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
|
|
||||||
public XkcdCommands(IHttpClientFactory factory)
|
public XkcdCommands(IHttpClientFactory factory)
|
||||||
@@ -23,12 +23,12 @@ public partial class Searches
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var res = await http.GetStringAsync($"{_xkcdUrl}/info.0.json");
|
var res = await http.GetStringAsync($"{XKCD_URL}/info.0.json");
|
||||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithImageUrl(comic.ImageLink)
|
.WithImageUrl(comic.ImageLink)
|
||||||
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{_xkcdUrl}/{comic.Num}")
|
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{comic.Num}")
|
||||||
.AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
|
.AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
|
||||||
.AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
|
.AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
|
||||||
var sent = await ctx.Channel.EmbedAsync(embed);
|
var sent = await ctx.Channel.EmbedAsync(embed);
|
||||||
@@ -57,13 +57,13 @@ public partial class Searches
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
using var http = _httpFactory.CreateClient();
|
using var http = _httpFactory.CreateClient();
|
||||||
var res = await http.GetStringAsync($"{_xkcdUrl}/{num}/info.0.json");
|
var res = await http.GetStringAsync($"{XKCD_URL}/{num}/info.0.json");
|
||||||
|
|
||||||
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
var comic = JsonConvert.DeserializeObject<XkcdComic>(res);
|
||||||
var embed = _eb.Create()
|
var embed = _eb.Create()
|
||||||
.WithOkColor()
|
.WithOkColor()
|
||||||
.WithImageUrl(comic.ImageLink)
|
.WithImageUrl(comic.ImageLink)
|
||||||
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{_xkcdUrl}/{num}")
|
.WithAuthor(comic.Title, "https://xkcd.com/s/919f27.ico", $"{XKCD_URL}/{num}")
|
||||||
.AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
|
.AddField(GetText(strs.comic_number), comic.Num.ToString(), true)
|
||||||
.AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
|
.AddField(GetText(strs.date), $"{comic.Month}/{comic.Year}", true);
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ public class CommandMapService : IInputTransformer, INService
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
|
var toDelete = await channel.SendConfirmAsync(_eb, $"{input} => {newInput}");
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
await Task.Delay(1500);
|
await Task.Delay(1500);
|
||||||
await toDelete.DeleteAsync(new() { RetryMode = RetryMode.AlwaysRetry });
|
await toDelete.DeleteAsync(new() { RetryMode = RetryMode.AlwaysRetry });
|
||||||
|
@@ -12,7 +12,7 @@ public partial class Utility
|
|||||||
[Group]
|
[Group]
|
||||||
public partial class QuoteCommands : NadekoSubmodule
|
public partial class QuoteCommands : NadekoSubmodule
|
||||||
{
|
{
|
||||||
private const string _prependExport =
|
private const string PREPEND_EXPORT =
|
||||||
@"# Keys are keywords, Each key has a LIST of quotes in the following format:
|
@"# Keys are keywords, Each key has a LIST of quotes in the following format:
|
||||||
# - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
|
# - id: Alphanumeric id used for commands related to the quote. (Note, when using .quotesimport, a new id will be generated.)
|
||||||
# an: Author name
|
# an: Author name
|
||||||
@@ -279,7 +279,7 @@ public partial class Utility
|
|||||||
var exprsDict = quotes.GroupBy(x => x.Keyword)
|
var exprsDict = quotes.GroupBy(x => x.Keyword)
|
||||||
.ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
|
.ToDictionary(x => x.Key, x => x.Select(ExportedQuote.FromModel));
|
||||||
|
|
||||||
var text = _prependExport + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints();
|
var text = PREPEND_EXPORT + _exportSerializer.Serialize(exprsDict).UnescapeUnicodeCodePoints();
|
||||||
|
|
||||||
await using var stream = await text.ToStream();
|
await using var stream = await text.ToStream();
|
||||||
await ctx.Channel.SendFileAsync(stream, "quote-export.yml");
|
await ctx.Channel.SendFileAsync(stream, "quote-export.yml");
|
||||||
|
@@ -11,20 +11,20 @@ public class StreamRoleService : INService
|
|||||||
{
|
{
|
||||||
private readonly DbService _db;
|
private readonly DbService _db;
|
||||||
private readonly DiscordSocketClient _client;
|
private readonly DiscordSocketClient _client;
|
||||||
private readonly ConcurrentDictionary<ulong, StreamRoleSettings> guildSettings;
|
private readonly ConcurrentDictionary<ulong, StreamRoleSettings> _guildSettings;
|
||||||
|
|
||||||
public StreamRoleService(DiscordSocketClient client, DbService db, Bot bot)
|
public StreamRoleService(DiscordSocketClient client, DbService db, Bot bot)
|
||||||
{
|
{
|
||||||
_db = db;
|
_db = db;
|
||||||
_client = client;
|
_client = client;
|
||||||
|
|
||||||
guildSettings = bot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.StreamRole)
|
_guildSettings = bot.AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.StreamRole)
|
||||||
.Where(x => x.Value is { Enabled: true })
|
.Where(x => x.Value is { Enabled: true })
|
||||||
.ToConcurrent();
|
.ToConcurrent();
|
||||||
|
|
||||||
_client.GuildMemberUpdated += Client_GuildMemberUpdated;
|
_client.GuildMemberUpdated += Client_GuildMemberUpdated;
|
||||||
|
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -39,10 +39,10 @@ public class StreamRoleService : INService
|
|||||||
|
|
||||||
private Task Client_GuildMemberUpdated(Cacheable<SocketGuildUser, ulong> cacheable, SocketGuildUser after)
|
private Task Client_GuildMemberUpdated(Cacheable<SocketGuildUser, ulong> cacheable, SocketGuildUser after)
|
||||||
{
|
{
|
||||||
var _ = Task.Run(async () =>
|
_= Task.Run(async () =>
|
||||||
{
|
{
|
||||||
//if user wasn't streaming or didn't have a game status at all
|
//if user wasn't streaming or didn't have a game status at all
|
||||||
if (guildSettings.TryGetValue(after.Guild.Id, out var setting)) await RescanUser(after, setting);
|
if (_guildSettings.TryGetValue(after.Guild.Id, out var setting)) await RescanUser(after, setting);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
@@ -51,6 +51,7 @@ public class StreamRoleService : INService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds or removes a user from a blacklist or a whitelist in the specified guild.
|
/// Adds or removes a user from a blacklist or a whitelist in the specified guild.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <param name="listType">List type</param>
|
||||||
/// <param name="guild">Guild</param>
|
/// <param name="guild">Guild</param>
|
||||||
/// <param name="action">Add or rem action</param>
|
/// <param name="action">Add or rem action</param>
|
||||||
/// <param name="userId">User's Id</param>
|
/// <param name="userId">User's Id</param>
|
||||||
@@ -97,7 +98,6 @@ public class StreamRoleService : INService
|
|||||||
var toRemove = streamRoleSettings.Blacklist.FirstOrDefault(x => x.Equals(userObj));
|
var toRemove = streamRoleSettings.Blacklist.FirstOrDefault(x => x.Equals(userObj));
|
||||||
if (toRemove is not null)
|
if (toRemove is not null)
|
||||||
{
|
{
|
||||||
success = true;
|
|
||||||
success = streamRoleSettings.Blacklist.Remove(toRemove);
|
success = streamRoleSettings.Blacklist.Remove(toRemove);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,7 +123,7 @@ public class StreamRoleService : INService
|
|||||||
/// <returns>The keyword set</returns>
|
/// <returns>The keyword set</returns>
|
||||||
public async Task<string> SetKeyword(IGuild guild, string keyword)
|
public async Task<string> SetKeyword(IGuild guild, string keyword)
|
||||||
{
|
{
|
||||||
keyword = keyword?.Trim()?.ToLowerInvariant();
|
keyword = keyword?.Trim().ToLowerInvariant();
|
||||||
|
|
||||||
await using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
{
|
{
|
||||||
@@ -145,7 +145,7 @@ public class StreamRoleService : INService
|
|||||||
/// <returns>The keyword set</returns>
|
/// <returns>The keyword set</returns>
|
||||||
public string GetKeyword(ulong guildId)
|
public string GetKeyword(ulong guildId)
|
||||||
{
|
{
|
||||||
if (guildSettings.TryGetValue(guildId, out var outSetting))
|
if (_guildSettings.TryGetValue(guildId, out var outSetting))
|
||||||
return outSetting.Keyword;
|
return outSetting.Keyword;
|
||||||
|
|
||||||
StreamRoleSettings setting;
|
StreamRoleSettings setting;
|
||||||
@@ -193,7 +193,8 @@ public class StreamRoleService : INService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Stops the stream role feature on the specified guild.
|
/// Stops the stream role feature on the specified guild.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="guildId">Guild's Id</param>
|
/// <param name="guild">Guild</param>
|
||||||
|
/// <param name="cleanup">Whether to rescan users</param>
|
||||||
public async Task StopStreamRole(IGuild guild, bool cleanup = false)
|
public async Task StopStreamRole(IGuild guild, bool cleanup = false)
|
||||||
{
|
{
|
||||||
await using (var uow = _db.GetDbContext())
|
await using (var uow = _db.GetDbContext())
|
||||||
@@ -205,7 +206,7 @@ public class StreamRoleService : INService
|
|||||||
await uow.SaveChangesAsync();
|
await uow.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guildSettings.TryRemove(guild.Id, out var setting) && cleanup)
|
if (_guildSettings.TryRemove(guild.Id, out _) && cleanup)
|
||||||
await RescanUsers(guild);
|
await RescanUsers(guild);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ public class StreamRoleService : INService
|
|||||||
if (addRole is null)
|
if (addRole is null)
|
||||||
{
|
{
|
||||||
await StopStreamRole(user.Guild);
|
await StopStreamRole(user.Guild);
|
||||||
Log.Warning("Stream role in server {0} no longer exists. Stopping.", setting.AddRoleId);
|
Log.Warning("Stream role in server {RoleId} no longer exists. Stopping", setting.AddRoleId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,7 +240,7 @@ public class StreamRoleService : INService
|
|||||||
if (!user.RoleIds.Contains(addRole.Id))
|
if (!user.RoleIds.Contains(addRole.Id))
|
||||||
{
|
{
|
||||||
await user.AddRoleAsync(addRole);
|
await user.AddRoleAsync(addRole);
|
||||||
Log.Information("Added stream role to user {0} in {1} server",
|
Log.Information("Added stream role to user {User} in {Server} server",
|
||||||
user.ToString(),
|
user.ToString(),
|
||||||
user.Guild.ToString());
|
user.Guild.ToString());
|
||||||
}
|
}
|
||||||
@@ -266,7 +267,7 @@ public class StreamRoleService : INService
|
|||||||
throw new StreamRoleNotFoundException();
|
throw new StreamRoleNotFoundException();
|
||||||
|
|
||||||
await user.RemoveRoleAsync(addRole);
|
await user.RemoveRoleAsync(addRole);
|
||||||
Log.Information("Removed stream role from the user {0} in {1} server",
|
Log.Information("Removed stream role from the user {User} in {Server} server",
|
||||||
user.ToString(),
|
user.ToString(),
|
||||||
user.Guild.ToString());
|
user.Guild.ToString());
|
||||||
}
|
}
|
||||||
@@ -281,7 +282,7 @@ public class StreamRoleService : INService
|
|||||||
|
|
||||||
private async Task RescanUsers(IGuild guild)
|
private async Task RescanUsers(IGuild guild)
|
||||||
{
|
{
|
||||||
if (!guildSettings.TryGetValue(guild.Id, out var setting))
|
if (!_guildSettings.TryGetValue(guild.Id, out var setting))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var addRole = guild.GetRole(setting.AddRoleId);
|
var addRole = guild.GetRole(setting.AddRoleId);
|
||||||
@@ -299,5 +300,5 @@ public class StreamRoleService : INService
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCache(ulong guildId, StreamRoleSettings setting)
|
private void UpdateCache(ulong guildId, StreamRoleSettings setting)
|
||||||
=> guildSettings.AddOrUpdate(guildId, _ => setting, (_, _) => setting);
|
=> _guildSettings.AddOrUpdate(guildId, _ => setting, (_, _) => setting);
|
||||||
}
|
}
|
@@ -11,17 +11,14 @@ public class ConverterService : INService
|
|||||||
|
|
||||||
private readonly Timer _currencyUpdater;
|
private readonly Timer _currencyUpdater;
|
||||||
private readonly TimeSpan _updateInterval = new(12, 0, 0);
|
private readonly TimeSpan _updateInterval = new(12, 0, 0);
|
||||||
private readonly DbService _db;
|
|
||||||
private readonly IDataCache _cache;
|
private readonly IDataCache _cache;
|
||||||
private readonly IHttpClientFactory _httpFactory;
|
private readonly IHttpClientFactory _httpFactory;
|
||||||
|
|
||||||
public ConverterService(
|
public ConverterService(
|
||||||
DiscordSocketClient client,
|
DiscordSocketClient client,
|
||||||
DbService db,
|
|
||||||
IDataCache cache,
|
IDataCache cache,
|
||||||
IHttpClientFactory factory)
|
IHttpClientFactory factory)
|
||||||
{
|
{
|
||||||
_db = db;
|
|
||||||
_cache = cache;
|
_cache = cache;
|
||||||
_httpFactory = factory;
|
_httpFactory = factory;
|
||||||
|
|
||||||
|
@@ -81,7 +81,7 @@ public partial class Utility : NadekoModule
|
|||||||
|
|
||||||
if (ctx.Guild is not SocketGuild socketGuild)
|
if (ctx.Guild is not SocketGuild socketGuild)
|
||||||
{
|
{
|
||||||
Log.Warning("Can't cast guild to socket guild.");
|
Log.Warning("Can't cast guild to socket guild");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,7 +154,15 @@ public partial class Utility : NadekoModule
|
|||||||
var builder = new StringBuilder();
|
var builder = new StringBuilder();
|
||||||
var user = who == MeOrBot.Me ? (IGuildUser)ctx.User : ((SocketGuild)ctx.Guild).CurrentUser;
|
var user = who == MeOrBot.Me ? (IGuildUser)ctx.User : ((SocketGuild)ctx.Guild).CurrentUser;
|
||||||
var perms = user.GetPermissions((ITextChannel)ctx.Channel);
|
var perms = user.GetPermissions((ITextChannel)ctx.Channel);
|
||||||
foreach (var p in perms.GetType().GetProperties().Where(p => !p.GetGetMethod().GetParameters().Any()))
|
foreach (var p in perms.GetType()
|
||||||
|
.GetProperties()
|
||||||
|
.Where(static p =>
|
||||||
|
{
|
||||||
|
var method = p.GetGetMethod();
|
||||||
|
if (method is null)
|
||||||
|
return false;
|
||||||
|
return !method.GetParameters().Any();
|
||||||
|
}))
|
||||||
builder.AppendLine($"{p.Name} : {p.GetValue(perms, null)}");
|
builder.AppendLine($"{p.Name} : {p.GetValue(perms, null)}");
|
||||||
await SendConfirmAsync(builder.ToString());
|
await SendConfirmAsync(builder.ToString());
|
||||||
}
|
}
|
||||||
@@ -355,7 +363,10 @@ public partial class Utility : NadekoModule
|
|||||||
if (page < 0)
|
if (page < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var guilds = await Task.Run(() => _client.Guilds.OrderBy(g => g.Name).Skip(page * 15).Take(15));
|
var guilds = _client.Guilds.OrderBy(g => g.Name)
|
||||||
|
.Skip(page * 15)
|
||||||
|
.Take(15)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
if (!guilds.Any())
|
if (!guilds.Any())
|
||||||
{
|
{
|
||||||
|
@@ -422,7 +422,7 @@ public class XpService : INService
|
|||||||
if (socketUser is not SocketGuildUser user || user.IsBot)
|
if (socketUser is not SocketGuildUser user || user.IsBot)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (before.VoiceChannel is not null) ScanChannelForVoiceXp(before.VoiceChannel);
|
if (before.VoiceChannel is not null) ScanChannelForVoiceXp(before.VoiceChannel);
|
||||||
|
|
||||||
@@ -514,7 +514,7 @@ public class XpService : INService
|
|||||||
if (arg.Author is not SocketGuildUser user || user.IsBot)
|
if (arg.Author is not SocketGuildUser user || user.IsBot)
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (!ShouldTrackXp(user, arg.Channel.Id))
|
if (!ShouldTrackXp(user, arg.Channel.Id))
|
||||||
return;
|
return;
|
||||||
|
@@ -26,53 +26,53 @@ public class EmbedBuilderService : IEmbedBuilderService, INService
|
|||||||
public sealed class DiscordEmbedBuilderWrapper : IEmbedBuilder
|
public sealed class DiscordEmbedBuilderWrapper : IEmbedBuilder
|
||||||
{
|
{
|
||||||
private readonly BotConfig _botConfig;
|
private readonly BotConfig _botConfig;
|
||||||
private EmbedBuilder _embed;
|
private EmbedBuilder embed;
|
||||||
|
|
||||||
public DiscordEmbedBuilderWrapper(in BotConfig botConfig, EmbedBuilder embed = null)
|
public DiscordEmbedBuilderWrapper(in BotConfig botConfig, EmbedBuilder embed = null)
|
||||||
{
|
{
|
||||||
_botConfig = botConfig;
|
_botConfig = botConfig;
|
||||||
_embed = embed ?? new EmbedBuilder();
|
this.embed = embed ?? new EmbedBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEmbedBuilder WithDescription(string desc)
|
public IEmbedBuilder WithDescription(string desc)
|
||||||
=> Wrap(_embed.WithDescription(desc));
|
=> Wrap(embed.WithDescription(desc));
|
||||||
|
|
||||||
public IEmbedBuilder WithTitle(string title)
|
public IEmbedBuilder WithTitle(string title)
|
||||||
=> Wrap(_embed.WithTitle(title));
|
=> Wrap(embed.WithTitle(title));
|
||||||
|
|
||||||
public IEmbedBuilder AddField(string title, object value, bool isInline = false)
|
public IEmbedBuilder AddField(string title, object value, bool isInline = false)
|
||||||
=> Wrap(_embed.AddField(title, value, isInline));
|
=> Wrap(embed.AddField(title, value, isInline));
|
||||||
|
|
||||||
public IEmbedBuilder WithFooter(string text, string iconUrl = null)
|
public IEmbedBuilder WithFooter(string text, string iconUrl = null)
|
||||||
=> Wrap(_embed.WithFooter(text, iconUrl));
|
=> Wrap(embed.WithFooter(text, iconUrl));
|
||||||
|
|
||||||
public IEmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
|
public IEmbedBuilder WithAuthor(string name, string iconUrl = null, string url = null)
|
||||||
=> Wrap(_embed.WithAuthor(name, iconUrl, url));
|
=> Wrap(embed.WithAuthor(name, iconUrl, url));
|
||||||
|
|
||||||
public IEmbedBuilder WithUrl(string url)
|
public IEmbedBuilder WithUrl(string url)
|
||||||
=> Wrap(_embed.WithUrl(url));
|
=> Wrap(embed.WithUrl(url));
|
||||||
|
|
||||||
public IEmbedBuilder WithImageUrl(string url)
|
public IEmbedBuilder WithImageUrl(string url)
|
||||||
=> Wrap(_embed.WithImageUrl(url));
|
=> Wrap(embed.WithImageUrl(url));
|
||||||
|
|
||||||
public IEmbedBuilder WithThumbnailUrl(string url)
|
public IEmbedBuilder WithThumbnailUrl(string url)
|
||||||
=> Wrap(_embed.WithThumbnailUrl(url));
|
=> Wrap(embed.WithThumbnailUrl(url));
|
||||||
|
|
||||||
public IEmbedBuilder WithColor(EmbedColor color)
|
public IEmbedBuilder WithColor(EmbedColor color)
|
||||||
=> color switch
|
=> color switch
|
||||||
{
|
{
|
||||||
EmbedColor.Ok => Wrap(_embed.WithColor(_botConfig.Color.Ok.ToDiscordColor())),
|
EmbedColor.Ok => Wrap(embed.WithColor(_botConfig.Color.Ok.ToDiscordColor())),
|
||||||
EmbedColor.Pending => Wrap(_embed.WithColor(_botConfig.Color.Pending.ToDiscordColor())),
|
EmbedColor.Pending => Wrap(embed.WithColor(_botConfig.Color.Pending.ToDiscordColor())),
|
||||||
EmbedColor.Error => Wrap(_embed.WithColor(_botConfig.Color.Error.ToDiscordColor())),
|
EmbedColor.Error => Wrap(embed.WithColor(_botConfig.Color.Error.ToDiscordColor())),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(color), "Unsupported EmbedColor type")
|
_ => throw new ArgumentOutOfRangeException(nameof(color), "Unsupported EmbedColor type")
|
||||||
};
|
};
|
||||||
|
|
||||||
public Embed Build()
|
public Embed Build()
|
||||||
=> _embed.Build();
|
=> embed.Build();
|
||||||
|
|
||||||
private IEmbedBuilder Wrap(EmbedBuilder eb)
|
private IEmbedBuilder Wrap(EmbedBuilder eb)
|
||||||
{
|
{
|
||||||
_embed = eb;
|
embed = eb;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -7,25 +7,25 @@ namespace NadekoBot.Services;
|
|||||||
public sealed class BehaviorExecutor : IBehaviourExecutor, INService
|
public sealed class BehaviorExecutor : IBehaviourExecutor, INService
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider _services;
|
private readonly IServiceProvider _services;
|
||||||
private IEnumerable<ILateExecutor> _lateExecutors;
|
private IEnumerable<ILateExecutor> lateExecutors;
|
||||||
private IEnumerable<ILateBlocker> _lateBlockers;
|
private IEnumerable<ILateBlocker> lateBlockers;
|
||||||
private IEnumerable<IEarlyBehavior> _earlyBehaviors;
|
private IEnumerable<IEarlyBehavior> earlyBehaviors;
|
||||||
private IEnumerable<IInputTransformer> _transformers;
|
private IEnumerable<IInputTransformer> transformers;
|
||||||
|
|
||||||
public BehaviorExecutor(IServiceProvider services)
|
public BehaviorExecutor(IServiceProvider services)
|
||||||
=> _services = services;
|
=> _services = services;
|
||||||
|
|
||||||
public void Initialize()
|
public void Initialize()
|
||||||
{
|
{
|
||||||
_lateExecutors = _services.GetServices<ILateExecutor>();
|
lateExecutors = _services.GetServices<ILateExecutor>();
|
||||||
_lateBlockers = _services.GetServices<ILateBlocker>();
|
lateBlockers = _services.GetServices<ILateBlocker>();
|
||||||
_earlyBehaviors = _services.GetServices<IEarlyBehavior>().OrderByDescending(x => x.Priority);
|
earlyBehaviors = _services.GetServices<IEarlyBehavior>().OrderByDescending(x => x.Priority);
|
||||||
_transformers = _services.GetServices<IInputTransformer>();
|
transformers = _services.GetServices<IInputTransformer>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> RunEarlyBehavioursAsync(SocketGuild guild, IUserMessage usrMsg)
|
public async Task<bool> RunEarlyBehavioursAsync(SocketGuild guild, IUserMessage usrMsg)
|
||||||
{
|
{
|
||||||
foreach (var beh in _earlyBehaviors)
|
foreach (var beh in earlyBehaviors)
|
||||||
if (await beh.RunBehavior(guild, usrMsg))
|
if (await beh.RunBehavior(guild, usrMsg))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@@ -35,7 +35,7 @@ public sealed class BehaviorExecutor : IBehaviourExecutor, INService
|
|||||||
public async Task<string> RunInputTransformersAsync(SocketGuild guild, IUserMessage usrMsg)
|
public async Task<string> RunInputTransformersAsync(SocketGuild guild, IUserMessage usrMsg)
|
||||||
{
|
{
|
||||||
var messageContent = usrMsg.Content;
|
var messageContent = usrMsg.Content;
|
||||||
foreach (var exec in _transformers)
|
foreach (var exec in transformers)
|
||||||
{
|
{
|
||||||
string newContent;
|
string newContent;
|
||||||
if ((newContent = await exec.TransformInput(guild, usrMsg.Channel, usrMsg.Author, messageContent))
|
if ((newContent = await exec.TransformInput(guild, usrMsg.Channel, usrMsg.Author, messageContent))
|
||||||
@@ -51,10 +51,10 @@ public sealed class BehaviorExecutor : IBehaviourExecutor, INService
|
|||||||
|
|
||||||
public async Task<bool> RunLateBlockersAsync(ICommandContext ctx, CommandInfo cmd)
|
public async Task<bool> RunLateBlockersAsync(ICommandContext ctx, CommandInfo cmd)
|
||||||
{
|
{
|
||||||
foreach (var exec in _lateBlockers)
|
foreach (var exec in lateBlockers)
|
||||||
if (await exec.TryBlockLate(ctx, cmd.Module.GetTopLevelModule().Name, cmd))
|
if (await exec.TryBlockLate(ctx, cmd.Module.GetTopLevelModule().Name, cmd))
|
||||||
{
|
{
|
||||||
Log.Information("Late blocking User [{0}] Command: [{1}] in [{2}]",
|
Log.Information("Late blocking User [{User}] Command: [{Command}] in [{Module}]",
|
||||||
ctx.User,
|
ctx.User,
|
||||||
cmd.Aliases[0],
|
cmd.Aliases[0],
|
||||||
exec.GetType().Name);
|
exec.GetType().Name);
|
||||||
@@ -66,7 +66,7 @@ public sealed class BehaviorExecutor : IBehaviourExecutor, INService
|
|||||||
|
|
||||||
public async Task RunLateExecutorsAsync(SocketGuild guild, IUserMessage usrMsg)
|
public async Task RunLateExecutorsAsync(SocketGuild guild, IUserMessage usrMsg)
|
||||||
{
|
{
|
||||||
foreach (var exec in _lateExecutors)
|
foreach (var exec in lateExecutors)
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await exec.LateExecute(guild, usrMsg);
|
await exec.LateExecute(guild, usrMsg);
|
||||||
|
@@ -13,10 +13,10 @@ namespace NadekoBot.Services;
|
|||||||
|
|
||||||
public class GoogleApiService : IGoogleApiService, INService
|
public class GoogleApiService : IGoogleApiService, INService
|
||||||
{
|
{
|
||||||
private const string SearchEngineId = "018084019232060951019:hs5piey28-e";
|
private const string SEARCH_ENGINE_ID = "018084019232060951019:hs5piey28-e";
|
||||||
|
|
||||||
private static readonly Regex
|
private static readonly Regex
|
||||||
plRegex = new("(?:youtu\\.be\\/|list=)(?<id>[\\da-zA-Z\\-_]*)", RegexOptions.Compiled);
|
_plRegex = new("(?:youtu\\.be\\/|list=)(?<id>[\\da-zA-Z\\-_]*)", RegexOptions.Compiled);
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, string> Languages { get; } = new Dictionary<string, string>
|
public IReadOnlyDictionary<string, string> Languages { get; } = new Dictionary<string, string>
|
||||||
{
|
{
|
||||||
@@ -151,9 +151,9 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
{ "yi", "yi" }
|
{ "yi", "yi" }
|
||||||
};
|
};
|
||||||
|
|
||||||
private readonly YouTubeService yt;
|
private readonly YouTubeService _yt;
|
||||||
private readonly UrlshortenerService sh;
|
private readonly UrlshortenerService _sh;
|
||||||
private readonly CustomsearchService cs;
|
private readonly CustomsearchService _cs;
|
||||||
|
|
||||||
//private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?<id>[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled);
|
//private readonly Regex YtVideoIdRegex = new Regex(@"(?:youtube\.com\/\S*(?:(?:\/e(?:mbed))?\/|watch\?(?:\S*?&?v\=))|youtu\.be\/)(?<id>[a-zA-Z0-9_-]{6,11})", RegexOptions.Compiled);
|
||||||
private readonly IBotCredentials _creds;
|
private readonly IBotCredentials _creds;
|
||||||
@@ -166,9 +166,9 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
|
|
||||||
var bcs = new BaseClientService.Initializer { ApplicationName = "Nadeko Bot", ApiKey = _creds.GoogleApiKey };
|
var bcs = new BaseClientService.Initializer { ApplicationName = "Nadeko Bot", ApiKey = _creds.GoogleApiKey };
|
||||||
|
|
||||||
yt = new(bcs);
|
_yt = new(bcs);
|
||||||
sh = new(bcs);
|
_sh = new(bcs);
|
||||||
cs = new(bcs);
|
_cs = new(bcs);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
|
public async Task<IEnumerable<string>> GetPlaylistIdsByKeywordsAsync(string keywords, int count = 1)
|
||||||
@@ -180,9 +180,9 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
|
|
||||||
var match = plRegex.Match(keywords);
|
var match = _plRegex.Match(keywords);
|
||||||
if (match.Length > 1) return new[] { match.Groups["id"].Value };
|
if (match.Length > 1) return new[] { match.Groups["id"].Value };
|
||||||
var query = yt.Search.List("snippet");
|
var query = _yt.Search.List("snippet");
|
||||||
query.MaxResults = count;
|
query.MaxResults = count;
|
||||||
query.Type = "playlist";
|
query.Type = "playlist";
|
||||||
query.Q = keywords;
|
query.Q = keywords;
|
||||||
@@ -199,7 +199,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
|
|
||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
var query = yt.Search.List("snippet");
|
var query = _yt.Search.List("snippet");
|
||||||
query.MaxResults = count;
|
query.MaxResults = count;
|
||||||
query.RelatedToVideoId = id;
|
query.RelatedToVideoId = id;
|
||||||
query.Type = "video";
|
query.Type = "video";
|
||||||
@@ -215,7 +215,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
|
|
||||||
var query = yt.Search.List("snippet");
|
var query = _yt.Search.List("snippet");
|
||||||
query.MaxResults = count;
|
query.MaxResults = count;
|
||||||
query.Q = keywords;
|
query.Q = keywords;
|
||||||
query.Type = "video";
|
query.Type = "video";
|
||||||
@@ -234,7 +234,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
if (count <= 0)
|
if (count <= 0)
|
||||||
throw new ArgumentOutOfRangeException(nameof(count));
|
throw new ArgumentOutOfRangeException(nameof(count));
|
||||||
|
|
||||||
var query = yt.Search.List("snippet");
|
var query = _yt.Search.List("snippet");
|
||||||
query.MaxResults = count;
|
query.MaxResults = count;
|
||||||
query.Q = keywords;
|
query.Q = keywords;
|
||||||
query.Type = "video";
|
query.Type = "video";
|
||||||
@@ -256,7 +256,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await sh.Url.Insert(new() { LongUrl = url }).ExecuteAsync();
|
var response = await _sh.Url.Insert(new() { LongUrl = url }).ExecuteAsync();
|
||||||
return response.Id;
|
return response.Id;
|
||||||
}
|
}
|
||||||
catch (GoogleApiException ex) when (ex.HttpStatusCode == HttpStatusCode.Forbidden)
|
catch (GoogleApiException ex) when (ex.HttpStatusCode == HttpStatusCode.Forbidden)
|
||||||
@@ -288,7 +288,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
var toGet = count > 50 ? 50 : count;
|
var toGet = count > 50 ? 50 : count;
|
||||||
count -= toGet;
|
count -= toGet;
|
||||||
|
|
||||||
var query = yt.PlaylistItems.List("contentDetails");
|
var query = _yt.PlaylistItems.List("contentDetails");
|
||||||
query.MaxResults = toGet;
|
query.MaxResults = toGet;
|
||||||
query.PlaylistId = playlistId;
|
query.PlaylistId = playlistId;
|
||||||
query.PageToken = nextPageToken;
|
query.PageToken = nextPageToken;
|
||||||
@@ -318,7 +318,7 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
var toGet = remaining > 50 ? 50 : remaining;
|
var toGet = remaining > 50 ? 50 : remaining;
|
||||||
remaining -= toGet;
|
remaining -= toGet;
|
||||||
|
|
||||||
var q = yt.Videos.List("contentDetails");
|
var q = _yt.Videos.List("contentDetails");
|
||||||
q.Id = string.Join(",", videoIdsList.Take(toGet));
|
q.Id = string.Join(",", videoIdsList.Take(toGet));
|
||||||
videoIdsList = videoIdsList.Skip(toGet).ToList();
|
videoIdsList = videoIdsList.Skip(toGet).ToList();
|
||||||
var items = (await q.ExecuteAsync()).Items;
|
var items = (await q.ExecuteAsync()).Items;
|
||||||
@@ -334,9 +334,9 @@ public class GoogleApiService : IGoogleApiService, INService
|
|||||||
if (string.IsNullOrWhiteSpace(query))
|
if (string.IsNullOrWhiteSpace(query))
|
||||||
throw new ArgumentNullException(nameof(query));
|
throw new ArgumentNullException(nameof(query));
|
||||||
|
|
||||||
var req = cs.Cse.List();
|
var req = _cs.Cse.List();
|
||||||
req.Q = query;
|
req.Q = query;
|
||||||
req.Cx = SearchEngineId;
|
req.Cx = SEARCH_ENGINE_ID;
|
||||||
req.Num = 1;
|
req.Num = 1;
|
||||||
req.Fields = "items(image(contextLink,thumbnailLink),link)";
|
req.Fields = "items(image(contextLink,thumbnailLink),link)";
|
||||||
req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image;
|
req.SearchType = CseResource.ListRequest.SearchTypeEnum.Image;
|
||||||
|
@@ -15,7 +15,7 @@ public class RedisCache : IDataCache
|
|||||||
private readonly string _redisKey;
|
private readonly string _redisKey;
|
||||||
private readonly EndPoint _redisEndpoint;
|
private readonly EndPoint _redisEndpoint;
|
||||||
|
|
||||||
private readonly object timelyLock = new();
|
private readonly object _timelyLock = new();
|
||||||
|
|
||||||
public RedisCache(
|
public RedisCache(
|
||||||
ConnectionMultiplexer redis,
|
ConnectionMultiplexer redis,
|
||||||
@@ -36,77 +36,77 @@ public class RedisCache : IDataCache
|
|||||||
// can re-use the same image/anime data
|
// can re-use the same image/anime data
|
||||||
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(Uri key)
|
public async Task<(bool Success, byte[] Data)> TryGetImageDataAsync(Uri key)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
byte[] x = await _db.StringGetAsync("image_" + key);
|
byte[] x = await db.StringGetAsync("image_" + key);
|
||||||
return (x is not null, x);
|
return (x is not null, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SetImageDataAsync(Uri key, byte[] data)
|
public Task SetImageDataAsync(Uri key, byte[] data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
return _db.StringSetAsync("image_" + key, data);
|
return db.StringSetAsync("image_" + key, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key)
|
public async Task<(bool Success, string Data)> TryGetAnimeDataAsync(string key)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
string x = await _db.StringGetAsync("anime_" + key);
|
string x = await db.StringGetAsync("anime_" + key);
|
||||||
return (x is not null, x);
|
return (x is not null, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SetAnimeDataAsync(string key, string data)
|
public Task SetAnimeDataAsync(string key, string data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
return _db.StringSetAsync("anime_" + key, data, TimeSpan.FromHours(3));
|
return db.StringSetAsync("anime_" + key, data, TimeSpan.FromHours(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<(bool Success, string Data)> TryGetNovelDataAsync(string key)
|
public async Task<(bool Success, string Data)> TryGetNovelDataAsync(string key)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
string x = await _db.StringGetAsync("novel_" + key);
|
string x = await db.StringGetAsync("novel_" + key);
|
||||||
return (x is not null, x);
|
return (x is not null, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task SetNovelDataAsync(string key, string data)
|
public Task SetNovelDataAsync(string key, string data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
return _db.StringSetAsync("novel_" + key, data, TimeSpan.FromHours(3));
|
return db.StringSetAsync("novel_" + key, data, TimeSpan.FromHours(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan? AddTimelyClaim(ulong id, int period)
|
public TimeSpan? AddTimelyClaim(ulong id, int period)
|
||||||
{
|
{
|
||||||
if (period == 0)
|
if (period == 0)
|
||||||
return null;
|
return null;
|
||||||
lock (timelyLock)
|
lock (_timelyLock)
|
||||||
{
|
{
|
||||||
var time = TimeSpan.FromHours(period);
|
var time = TimeSpan.FromHours(period);
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
if ((bool?)_db.StringGet($"{_redisKey}_timelyclaim_{id}") is null)
|
if ((bool?)db.StringGet($"{_redisKey}_timelyclaim_{id}") is null)
|
||||||
{
|
{
|
||||||
_db.StringSet($"{_redisKey}_timelyclaim_{id}", true, time);
|
db.StringSet($"{_redisKey}_timelyclaim_{id}", true, time);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return _db.KeyTimeToLive($"{_redisKey}_timelyclaim_{id}");
|
return db.KeyTimeToLive($"{_redisKey}_timelyclaim_{id}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAllTimelyClaims()
|
public void RemoveAllTimelyClaims()
|
||||||
{
|
{
|
||||||
var server = Redis.GetServer(_redisEndpoint);
|
var server = Redis.GetServer(_redisEndpoint);
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
foreach (var k in server.Keys(pattern: $"{_redisKey}_timelyclaim_*"))
|
foreach (var k in server.Keys(pattern: $"{_redisKey}_timelyclaim_*"))
|
||||||
_db.KeyDelete(k, CommandFlags.FireAndForget);
|
db.KeyDelete(k, CommandFlags.FireAndForget);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAddAffinityCooldown(ulong userId, out TimeSpan? time)
|
public bool TryAddAffinityCooldown(ulong userId, out TimeSpan? time)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
time = _db.KeyTimeToLive($"{_redisKey}_affinity_{userId}");
|
time = db.KeyTimeToLive($"{_redisKey}_affinity_{userId}");
|
||||||
if (time is null)
|
if (time is null)
|
||||||
{
|
{
|
||||||
time = TimeSpan.FromMinutes(30);
|
time = TimeSpan.FromMinutes(30);
|
||||||
_db.StringSet($"{_redisKey}_affinity_{userId}", true, time);
|
db.StringSet($"{_redisKey}_affinity_{userId}", true, time);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,12 +115,12 @@ public class RedisCache : IDataCache
|
|||||||
|
|
||||||
public bool TryAddDivorceCooldown(ulong userId, out TimeSpan? time)
|
public bool TryAddDivorceCooldown(ulong userId, out TimeSpan? time)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
time = _db.KeyTimeToLive($"{_redisKey}_divorce_{userId}");
|
time = db.KeyTimeToLive($"{_redisKey}_divorce_{userId}");
|
||||||
if (time is null)
|
if (time is null)
|
||||||
{
|
{
|
||||||
time = TimeSpan.FromHours(6);
|
time = TimeSpan.FromHours(6);
|
||||||
_db.StringSet($"{_redisKey}_divorce_{userId}", true, time);
|
db.StringSet($"{_redisKey}_divorce_{userId}", true, time);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,42 +129,43 @@ public class RedisCache : IDataCache
|
|||||||
|
|
||||||
public Task SetStreamDataAsync(string url, string data)
|
public Task SetStreamDataAsync(string url, string data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
return _db.StringSetAsync($"{_redisKey}_stream_{url}", data, TimeSpan.FromHours(6));
|
return db.StringSetAsync($"{_redisKey}_stream_{url}", data, TimeSpan.FromHours(6));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetStreamData(string url, out string dataStr)
|
public bool TryGetStreamData(string url, out string dataStr)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
dataStr = _db.StringGet($"{_redisKey}_stream_{url}");
|
dataStr = db.StringGet($"{_redisKey}_stream_{url}");
|
||||||
|
|
||||||
return !string.IsNullOrWhiteSpace(dataStr);
|
return !string.IsNullOrWhiteSpace(dataStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan? TryAddRatelimit(ulong id, string name, int expireIn)
|
public TimeSpan? TryAddRatelimit(ulong id, string name, int expireIn)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
if (_db.StringSet($"{_redisKey}_ratelimit_{id}_{name}",
|
if (db.StringSet($"{_redisKey}_ratelimit_{id}_{name}",
|
||||||
0, // i don't use the value
|
0, // i don't use the value
|
||||||
TimeSpan.FromSeconds(expireIn),
|
TimeSpan.FromSeconds(expireIn),
|
||||||
When.NotExists))
|
When.NotExists))
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return _db.KeyTimeToLive($"{_redisKey}_ratelimit_{id}_{name}");
|
return db.KeyTimeToLive($"{_redisKey}_ratelimit_{id}_{name}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetEconomy(out string data)
|
public bool TryGetEconomy(out string data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
if ((data = _db.StringGet($"{_redisKey}_economy")) is not null) return true;
|
data = db.StringGet($"{_redisKey}_economy");
|
||||||
|
if (data is not null) return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetEconomy(string data)
|
public void SetEconomy(string data)
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
_db.StringSet($"{_redisKey}_economy", data, TimeSpan.FromMinutes(3));
|
db.StringSet($"{_redisKey}_economy", data, TimeSpan.FromMinutes(3));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<TOut> GetOrAddCachedDataAsync<TParam, TOut>(
|
public async Task<TOut> GetOrAddCachedDataAsync<TParam, TOut>(
|
||||||
@@ -174,9 +175,9 @@ public class RedisCache : IDataCache
|
|||||||
TimeSpan expiry)
|
TimeSpan expiry)
|
||||||
where TOut : class
|
where TOut : class
|
||||||
{
|
{
|
||||||
var _db = Redis.GetDatabase();
|
var db = Redis.GetDatabase();
|
||||||
|
|
||||||
var data = await _db.StringGetAsync(key);
|
var data = await db.StringGetAsync(key);
|
||||||
if (!data.HasValue)
|
if (!data.HasValue)
|
||||||
{
|
{
|
||||||
var obj = await factory(param);
|
var obj = await factory(param);
|
||||||
@@ -184,7 +185,7 @@ public class RedisCache : IDataCache
|
|||||||
if (obj is null)
|
if (obj is null)
|
||||||
return default;
|
return default;
|
||||||
|
|
||||||
await _db.StringSetAsync(key, JsonConvert.SerializeObject(obj), expiry);
|
await db.StringSetAsync(key, JsonConvert.SerializeObject(obj), expiry);
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
@@ -3,9 +3,9 @@ namespace NadekoBot.Services;
|
|||||||
|
|
||||||
public static class RedisImageExtensions
|
public static class RedisImageExtensions
|
||||||
{
|
{
|
||||||
private const string OldCdnUrl = "nadeko-pictures.nyc3.digitaloceanspaces.com";
|
private const string OLD_CDN_URL = "nadeko-pictures.nyc3.digitaloceanspaces.com";
|
||||||
private const string NewCdnUrl = "cdn.nadeko.bot";
|
private const string NEW_CDN_URL = "cdn.nadeko.bot";
|
||||||
|
|
||||||
public static Uri ToNewCdn(this Uri uri)
|
public static Uri ToNewCdn(this Uri uri)
|
||||||
=> new(uri.ToString().Replace(OldCdnUrl, NewCdnUrl));
|
=> new(uri.ToString().Replace(OLD_CDN_URL, NEW_CDN_URL));
|
||||||
}
|
}
|
@@ -58,7 +58,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.ChannelCreated += c =>
|
_client.ChannelCreated += c =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (c is ITextChannel)
|
if (c is ITextChannel)
|
||||||
Interlocked.Increment(ref textChannels);
|
Interlocked.Increment(ref textChannels);
|
||||||
@@ -71,7 +71,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.ChannelDestroyed += c =>
|
_client.ChannelDestroyed += c =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
if (c is ITextChannel)
|
if (c is ITextChannel)
|
||||||
Interlocked.Decrement(ref textChannels);
|
Interlocked.Decrement(ref textChannels);
|
||||||
@@ -84,7 +84,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.GuildAvailable += g =>
|
_client.GuildAvailable += g =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
var vc = g.Channels.Count - tc;
|
var vc = g.Channels.Count - tc;
|
||||||
@@ -96,7 +96,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.JoinedGuild += g =>
|
_client.JoinedGuild += g =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
var vc = g.Channels.Count - tc;
|
var vc = g.Channels.Count - tc;
|
||||||
@@ -108,7 +108,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.GuildUnavailable += g =>
|
_client.GuildUnavailable += g =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
var vc = g.Channels.Count - tc;
|
var vc = g.Channels.Count - tc;
|
||||||
@@ -121,7 +121,7 @@ public class StatsService : IStatsService, IReadyExecutor, INService, IDisposabl
|
|||||||
|
|
||||||
_client.LeftGuild += g =>
|
_client.LeftGuild += g =>
|
||||||
{
|
{
|
||||||
var _ = Task.Run(() =>
|
_= Task.Run(() =>
|
||||||
{
|
{
|
||||||
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
var tc = g.Channels.Count(cx => cx is ITextChannel);
|
||||||
var vc = g.Channels.Count - tc;
|
var vc = g.Channels.Count - tc;
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user