mirror of
https://github.com/Jetsparrow/karmabot.git
synced 2026-01-21 00:56:09 +03:00
Split out parts into JetBotLib
This commit is contained in:
parent
f510c99f3a
commit
ae39f15fda
@ -1,13 +1,10 @@
|
||||
using JetKarmaBot.Commands;
|
||||
using NLog;
|
||||
using Perfusion;
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace JetKarmaBot.Services.Handling
|
||||
namespace JetBotLib
|
||||
{
|
||||
public class ChatCommandRouter : IRequestHandler
|
||||
{
|
||||
@ -17,36 +14,19 @@ namespace JetKarmaBot.Services.Handling
|
||||
public ChatCommandRouter Router;
|
||||
public bool Succeded;
|
||||
}
|
||||
public Telegram.Bot.Types.User Me { get; private set; }
|
||||
[Inject] private Logger log;
|
||||
[Inject] private TelegramBotClient Client { get; set; }
|
||||
|
||||
public async Task Start()
|
||||
{
|
||||
Me = await Client.GetMeAsync();
|
||||
}
|
||||
|
||||
public Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
||||
{
|
||||
log.Debug("Message received");
|
||||
CommandString cmd = ctx.Command;
|
||||
Feature feature = new Feature() { Router = this };
|
||||
ctx.Features.Add(feature);
|
||||
|
||||
try
|
||||
if (commands.ContainsKey(cmd.Command))
|
||||
{
|
||||
if (commands.ContainsKey(cmd.Command))
|
||||
{
|
||||
feature.CommandType = commands[cmd.Command].GetType();
|
||||
log.Debug($"Handling message via {feature.CommandType.Name}");
|
||||
async Task processCommand() => feature.Succeded = await commands[cmd.Command].Execute(ctx);
|
||||
return processCommand();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error($"Error while handling command {cmd.Command}!");
|
||||
log.Error(e);
|
||||
feature.CommandType = commands[cmd.Command].GetType();
|
||||
async Task processCommand() => feature.Succeded = await commands[cmd.Command].Execute(ctx);
|
||||
return processCommand();
|
||||
}
|
||||
|
||||
return next(ctx);
|
||||
@ -54,17 +34,15 @@ namespace JetKarmaBot.Services.Handling
|
||||
|
||||
public void Add(IChatCommand c)
|
||||
{
|
||||
log.ConditionalTrace($"Adding command {c.GetType().Name}");
|
||||
foreach (var name in c.Names)
|
||||
{
|
||||
log.ConditionalTrace($"Mounting {c.GetType().Name} to {name}");
|
||||
if (commands.ContainsKey(name))
|
||||
throw new Exception($"command collision for name {name}, commands {commands[name].GetType()} and {c.GetType()}");
|
||||
commands[name] = c;
|
||||
}
|
||||
}
|
||||
|
||||
internal string GetHelpText(Locale loc)
|
||||
public string GetHelpText(Locale loc)
|
||||
{
|
||||
List<string> pieces = new List<string>();
|
||||
foreach (IChatCommand c in commands.Values.Distinct())
|
||||
@ -81,7 +59,7 @@ namespace JetKarmaBot.Services.Handling
|
||||
return string.Join("\n", pieces);
|
||||
}
|
||||
|
||||
internal string GetHelpTextFor(string commandname, Locale loc)
|
||||
public string GetHelpTextFor(string commandname, Locale loc)
|
||||
{
|
||||
IChatCommand c = commands[commandname];
|
||||
string build = "";
|
||||
@ -2,7 +2,7 @@
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
namespace JetBotLib
|
||||
{
|
||||
public class CommandString
|
||||
{
|
||||
@ -1,8 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using JetKarmaBot.Services.Handling;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
namespace JetBotLib
|
||||
{
|
||||
public interface IChatCommand
|
||||
{
|
||||
9
JetBotLib/JetBotLib.csproj
Normal file
9
JetBotLib/JetBotLib.csproj
Normal file
@ -0,0 +1,9 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Telegram.Bot" Version="14.12.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -5,43 +5,25 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using NLog;
|
||||
using Perfusion;
|
||||
|
||||
namespace JetKarmaBot
|
||||
namespace JetBotLib
|
||||
{
|
||||
public class Localization : IReadOnlyDictionary<string, Locale>
|
||||
{
|
||||
private Dictionary<string, Locale> locales = new Dictionary<string, Locale>();
|
||||
|
||||
public Localization(IContainer c)
|
||||
public Localization()
|
||||
{
|
||||
c.ResolveObject(this);
|
||||
log.Info("Initializing...");
|
||||
string langsFolder = "lang";
|
||||
if (!Directory.Exists(langsFolder))
|
||||
Directory.CreateDirectory(langsFolder);
|
||||
|
||||
foreach (string langFilePath in Directory.EnumerateFiles(langsFolder, "*.json"))
|
||||
{
|
||||
try
|
||||
{
|
||||
string langName = Path.GetFileNameWithoutExtension(langFilePath);
|
||||
string langKey = langName.ToLowerInvariant();
|
||||
locales[langKey] = new Locale(JObject.Parse(File.ReadAllText(langFilePath)), langKey);
|
||||
log.Debug("Found " + langName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error($"Error while parsing {langFilePath}!");
|
||||
log.Error(e);
|
||||
}
|
||||
string langName = Path.GetFileNameWithoutExtension(langFilePath);
|
||||
string langKey = langName.ToLowerInvariant();
|
||||
locales[langKey] = new Locale(JObject.Parse(File.ReadAllText(langFilePath)), langKey);
|
||||
}
|
||||
|
||||
if (locales.Any())
|
||||
log.Info("Initialized!");
|
||||
else
|
||||
throw new FileNotFoundException($"No locales found in {langsFolder}!");
|
||||
}
|
||||
|
||||
public Locale this[string locale]
|
||||
@ -53,17 +35,15 @@ namespace JetKarmaBot
|
||||
}
|
||||
}
|
||||
|
||||
[Inject]
|
||||
private Logger log;
|
||||
|
||||
public Locale FindByCommonName(string name)
|
||||
{
|
||||
log.ConditionalTrace("Trying to find locale " + name);
|
||||
// log.ConditionalTrace("Trying to find locale " + name);
|
||||
foreach (Locale l in locales.Values)
|
||||
{
|
||||
if (l.CommonNames.Contains(name))
|
||||
{
|
||||
log.ConditionalTrace("Found locale " + l.Name);
|
||||
// log.ConditionalTrace("Found locale " + l.Name);
|
||||
return l;
|
||||
}
|
||||
}
|
||||
@ -77,7 +57,7 @@ namespace JetKarmaBot
|
||||
}
|
||||
else if (matchinglocales.Count() == 1)
|
||||
return matchinglocales.First();
|
||||
log.Warn("Failed to find locale " + name);
|
||||
// log.Warn("Failed to find locale " + name);
|
||||
return null;
|
||||
}
|
||||
public bool ContainsLocale(string locale)
|
||||
@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using Perfusion;
|
||||
|
||||
namespace JetKarmaBot.Services.Handling
|
||||
namespace JetBotLib
|
||||
{
|
||||
public interface IRequestHandler
|
||||
{
|
||||
@ -12,7 +10,6 @@ namespace JetKarmaBot.Services.Handling
|
||||
}
|
||||
public class RequestChain : IRequestHandler
|
||||
{
|
||||
[Inject] private Logger log;
|
||||
List<IRequestHandler> handlerStack = new List<IRequestHandler>();
|
||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next = null)
|
||||
{
|
||||
@ -22,11 +19,9 @@ namespace JetKarmaBot.Services.Handling
|
||||
{
|
||||
if (i == handlerStack.Count)
|
||||
{
|
||||
log.ConditionalTrace("(next) End of request chain");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
IRequestHandler handler = handlerStack[i++];
|
||||
log.ConditionalTrace($"(next) Executing handler {handler.GetType().Name}");
|
||||
return handler.Handle(newCtx, chainNext);
|
||||
};
|
||||
await chainNext(ctx);
|
||||
@ -35,7 +30,6 @@ namespace JetKarmaBot.Services.Handling
|
||||
}
|
||||
public void Add(IRequestHandler handler)
|
||||
{
|
||||
log.ConditionalTrace($"Adding {handler.GetType().Name} to reqchain");
|
||||
handlerStack.Add(handler);
|
||||
}
|
||||
}
|
||||
@ -2,12 +2,10 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetKarmaBot.Commands;
|
||||
using JetKarmaBot.Models;
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Args;
|
||||
|
||||
namespace JetKarmaBot.Services.Handling
|
||||
namespace JetBotLib
|
||||
{
|
||||
public class RequestContext : IServiceProvider
|
||||
{
|
||||
98
JetBotLib/TimeoutManager.cs
Normal file
98
JetBotLib/TimeoutManager.cs
Normal file
@ -0,0 +1,98 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
|
||||
namespace JetBotLib
|
||||
{
|
||||
public abstract class TimeoutManager : IRequestHandler
|
||||
{
|
||||
public class Feature
|
||||
{
|
||||
public double Multiplier = 1;
|
||||
}
|
||||
public class PreDbThrowout : IRequestHandler
|
||||
{
|
||||
public TimeoutManager Timeout { get; }
|
||||
public PreDbThrowout(TimeoutManager timeout)
|
||||
{
|
||||
Timeout = timeout;
|
||||
}
|
||||
|
||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
||||
{
|
||||
int uid = ctx.EventArgs.Message.From.Id;
|
||||
if (Timeout.TimeoutCache.TryGetValue(uid, out var stats))
|
||||
{
|
||||
DateTime debtLimit = DateTime.Now.AddSeconds(Timeout.DebtLimitSeconds);
|
||||
if (debtLimit < stats.CooldownDate && stats.TimeoutMessaged)
|
||||
return;
|
||||
}
|
||||
await next(ctx);
|
||||
}
|
||||
}
|
||||
public class TimeoutStats
|
||||
{
|
||||
public DateTime CooldownDate;
|
||||
public bool TimeoutMessaged;
|
||||
protected Dictionary<Type, object> features = new Dictionary<Type, object>();
|
||||
public IReadOnlyDictionary<Type, object> Features => features;
|
||||
public T GetFeature<T>()
|
||||
{
|
||||
if (!Features.ContainsKey(typeof(T)))
|
||||
features.Add(typeof(T), Activator.CreateInstance(typeof(T)));
|
||||
return (T)Features[typeof(T)];
|
||||
}
|
||||
}
|
||||
public Dictionary<int, TimeoutStats> TimeoutCache = new Dictionary<int, TimeoutStats>();
|
||||
|
||||
public abstract Task Save(CancellationToken ct = default(CancellationToken));
|
||||
protected abstract Task LoadUser(int uid, RequestContext ctx = null);
|
||||
public abstract int SaveIntervalSeconds { get; }
|
||||
public abstract int DebtLimitSeconds { get; }
|
||||
public abstract int GetCostSeconds(string name, bool status);
|
||||
|
||||
public async Task SaveLoop(CancellationToken ct = default(CancellationToken))
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(SaveIntervalSeconds * 1000, ct);
|
||||
await Save(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
||||
{
|
||||
int uid = ctx.EventArgs.Message.From.Id;
|
||||
await LoadUser(uid, ctx);
|
||||
DateTime debtLimit = DateTime.Now.AddSeconds(DebtLimitSeconds);
|
||||
if (debtLimit < TimeoutCache[uid].CooldownDate)
|
||||
{
|
||||
if (!TimeoutCache[uid].TimeoutMessaged)
|
||||
{
|
||||
Locale currentLocale = ctx.GetFeature<Locale>();
|
||||
await ctx.SendMessage(currentLocale["jetkarmabot.ratelimit"]);
|
||||
TimeoutCache[uid].TimeoutMessaged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Feature feature = new Feature();
|
||||
ctx.Features.Add(feature);
|
||||
|
||||
await next(ctx);
|
||||
|
||||
var routerFeature = ctx.GetFeature<ChatCommandRouter.Feature>();
|
||||
if (feature.Multiplier == 0) return;
|
||||
int cost = GetCostSeconds(getTypeName(routerFeature.CommandType), routerFeature.Succeded);
|
||||
if (TimeoutCache[uid].CooldownDate < DateTime.Now) TimeoutCache[uid].CooldownDate = DateTime.Now;
|
||||
TimeoutCache[uid].CooldownDate = TimeoutCache[uid].CooldownDate.AddSeconds(cost);
|
||||
TimeoutCache[uid].TimeoutMessaged = false;
|
||||
}
|
||||
private string getTypeName(Type t)
|
||||
{
|
||||
return (t.DeclaringType == null ? t.Namespace + "." + t.Name : getTypeName(t.DeclaringType) + "." + t.Name)
|
||||
+ (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,11 +7,16 @@ using NLog;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
class AwardCommand : IChatCommand
|
||||
{
|
||||
public class TimeoutFeature
|
||||
{
|
||||
public DateTime PreviousAwardDate;
|
||||
}
|
||||
public IReadOnlyCollection<string> Names => new[] { "award", "revoke" };
|
||||
[Inject] private Logger log;
|
||||
|
||||
@ -21,8 +26,9 @@ namespace JetKarmaBot.Commands
|
||||
var currentLocale = ctx.GetFeature<Locale>();
|
||||
|
||||
var awarder = ctx.EventArgs.Message.From;
|
||||
var timeoutFeature = Timeout.TimeoutCache[awarder.Id].GetFeature<TimeoutFeature>();
|
||||
|
||||
if (Timeout.TimeoutCache[awarder.Id].PreviousAwardDate.AddSeconds(Config.Timeout.AwardTimeSeconds) > DateTime.Now)
|
||||
if (timeoutFeature.PreviousAwardDate.AddSeconds(Config.Timeout.AwardTimeSeconds) > DateTime.Now)
|
||||
{
|
||||
ctx.GetFeature<TimeoutManager.Feature>().Multiplier = 0; // Doesn't count as success or failure
|
||||
if (!Timeout.TimeoutCache[awarder.Id].TimeoutMessaged)
|
||||
@ -81,7 +87,7 @@ namespace JetKarmaBot.Commands
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ctx.GetFeature<ChatCommandRouter.Feature>().Router.Me.Id == recipientId)
|
||||
if (ctx.GetFeature<JetKarmaBot>().Me.Id == recipientId)
|
||||
{
|
||||
await ctx.SendMessage(awarding
|
||||
? currentLocale["jetkarmabot.award.errawardbot"]
|
||||
@ -119,7 +125,7 @@ namespace JetKarmaBot.Commands
|
||||
var response = message + "\n" + String.Format(currentLocale["jetkarmabot.award.statustext"], recUserName, prevCount + (awarding ? 1 : -1), awardType.Symbol);
|
||||
|
||||
await ctx.SendMessage(response);
|
||||
Timeout.TimeoutCache[awarder.Id].PreviousAwardDate = DateTime.Now;
|
||||
timeoutFeature.PreviousAwardDate = DateTime.Now;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ using NLog;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
|
||||
@ -4,6 +4,7 @@ using JetKarmaBot.Services.Handling;
|
||||
using Telegram.Bot.Types.Enums;
|
||||
using System.Threading.Tasks;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using Perfusion;
|
||||
using JetKarmaBot.Services.Handling;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
|
||||
@ -5,6 +5,7 @@ using JetKarmaBot.Services.Handling;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using JetKarmaBot.Models;
|
||||
using JetBotLib;
|
||||
|
||||
namespace JetKarmaBot.Commands
|
||||
{
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
using JetBotLib;
|
||||
using JetKarmaBot.Commands;
|
||||
using JetKarmaBot.Models;
|
||||
using JetKarmaBot.Services;
|
||||
@ -19,9 +20,10 @@ namespace JetKarmaBot
|
||||
[Inject] Config Config { get; set; }
|
||||
[Inject] IContainer Container { get; set; }
|
||||
[Inject] KarmaContextFactory Db { get; set; }
|
||||
[Inject] TimeoutManager Timeout { get; set; }
|
||||
[Inject] KarmaTimeoutManager Timeout { get; set; }
|
||||
[Inject] Localization Locale { get; set; }
|
||||
|
||||
public Telegram.Bot.Types.User Me { get; private set; }
|
||||
TelegramBotClient Client { get; set; }
|
||||
ChatCommandRouter Commands;
|
||||
RequestChain Chain;
|
||||
@ -38,6 +40,7 @@ namespace JetKarmaBot
|
||||
};
|
||||
|
||||
Client = new TelegramBotClient(Config.ApiKey, httpProxy);
|
||||
Me = await Client.GetMeAsync();
|
||||
Container.AddInstance(Client);
|
||||
|
||||
timeoutWaitTaskToken = new CancellationTokenSource();
|
||||
@ -72,10 +75,11 @@ namespace JetKarmaBot
|
||||
return;
|
||||
if (!CommandString.TryParse(args.Message.Text, out var cmd))
|
||||
return;
|
||||
if (cmd.UserName != null && cmd.UserName != Commands.Me.Username)
|
||||
if (cmd.UserName != null && cmd.UserName != Me.Username)
|
||||
return;
|
||||
|
||||
RequestContext ctx = new RequestContext(Client, args, cmd);
|
||||
ctx.Features.Add(this);
|
||||
_ = Chain.Handle(ctx);
|
||||
}
|
||||
|
||||
@ -88,7 +92,6 @@ namespace JetKarmaBot
|
||||
c.Add<CurrenciesCommand>();
|
||||
c.Add<LeaderboardCommand>();
|
||||
Commands = c.GetInstance<ChatCommandRouter>();
|
||||
await Commands.Start();
|
||||
foreach (IChatCommand cmd in c.GetInstances<IChatCommand>())
|
||||
{
|
||||
Commands.Add(cmd);
|
||||
|
||||
@ -32,4 +32,7 @@
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\JetBotLib\JetBotLib.csproj" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using JetBotLib;
|
||||
using Perfusion;
|
||||
|
||||
namespace JetKarmaBot.Services.Handling
|
||||
namespace JetKarmaBot.Services
|
||||
{
|
||||
public class DatabaseHandler : IRequestHandler
|
||||
{
|
||||
@ -1,133 +0,0 @@
|
||||
using Perfusion;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetKarmaBot.Models;
|
||||
using System.Threading;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
|
||||
namespace JetKarmaBot.Services.Handling
|
||||
{
|
||||
[Singleton]
|
||||
public class TimeoutManager : IRequestHandler
|
||||
{
|
||||
public class Feature
|
||||
{
|
||||
public double Multiplier = 1;
|
||||
}
|
||||
public class PreDbThrowout : IRequestHandler
|
||||
{
|
||||
public TimeoutManager Timeout { get; }
|
||||
public PreDbThrowout(TimeoutManager timeout)
|
||||
{
|
||||
Timeout = timeout;
|
||||
}
|
||||
|
||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
||||
{
|
||||
int uid = ctx.EventArgs.Message.From.Id;
|
||||
if (Timeout.TimeoutCache.TryGetValue(uid, out var stats))
|
||||
{
|
||||
DateTime debtLimit = DateTime.Now.AddSeconds(Timeout.cfg.Timeout.DebtLimitSeconds);
|
||||
if (debtLimit < stats.CooldownDate && stats.TimeoutMessaged)
|
||||
return;
|
||||
}
|
||||
await next(ctx);
|
||||
}
|
||||
}
|
||||
public class TimeoutStats
|
||||
{
|
||||
public DateTime CooldownDate;
|
||||
public bool TimeoutMessaged;
|
||||
public DateTime PreviousAwardDate;
|
||||
}
|
||||
[Inject] private KarmaContextFactory Db;
|
||||
[Inject] private Config cfg;
|
||||
[Inject] private Localization Locale;
|
||||
[Inject] private Logger log;
|
||||
public Dictionary<int, TimeoutStats> TimeoutCache = new Dictionary<int, TimeoutStats>();
|
||||
private async Task ApplyCost(string name, bool succeded, int uid, KarmaContext db, Feature feature)
|
||||
{
|
||||
if (feature.Multiplier == 0)
|
||||
return;
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name + (succeded ? " (OK)" : "(ERR)"), out var costSeconds))
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name, out costSeconds))
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue("Default", out costSeconds))
|
||||
{
|
||||
throw new LocalizationException("Default key not present");
|
||||
}
|
||||
await PopulateStats(uid, db);
|
||||
DateTime debtLimit = DateTime.Now.AddSeconds(cfg.Timeout.DebtLimitSeconds);
|
||||
if (TimeoutCache[uid].CooldownDate >= debtLimit)
|
||||
//Programming error
|
||||
throw new NotImplementedException();
|
||||
TimeoutCache[uid].CooldownDate = (TimeoutCache[uid].CooldownDate <= DateTime.Now ? DateTime.Now : TimeoutCache[uid].CooldownDate)
|
||||
.AddSeconds(feature.Multiplier * costSeconds);
|
||||
TimeoutCache[uid].TimeoutMessaged = false;
|
||||
}
|
||||
|
||||
private async Task PopulateStats(int uid, KarmaContext db)
|
||||
{
|
||||
if (!TimeoutCache.ContainsKey(uid))
|
||||
{
|
||||
log.ConditionalTrace($"User {uid} not present: saving to cache");
|
||||
TimeoutCache[uid] = new TimeoutStats()
|
||||
{
|
||||
CooldownDate = (await db.Users.FindAsync(uid))?.CooldownDate ?? DateTime.Now
|
||||
};
|
||||
}
|
||||
}
|
||||
public async Task Save(CancellationToken ct = default(CancellationToken))
|
||||
{
|
||||
log.Info("Saving timeout info to database");
|
||||
using (KarmaContext db = Db.GetContext())
|
||||
{
|
||||
foreach (int i in TimeoutCache.Keys)
|
||||
{
|
||||
(await db.Users.FindAsync(new object[] { i }, ct)).CooldownDate = TimeoutCache[i].CooldownDate;
|
||||
}
|
||||
await db.SaveChangesAsync(ct);
|
||||
}
|
||||
log.Info("Saved");
|
||||
}
|
||||
public async Task SaveLoop(CancellationToken ct = default(CancellationToken))
|
||||
{
|
||||
while (!ct.IsCancellationRequested)
|
||||
{
|
||||
await Task.Delay(cfg.Timeout.SaveIntervalSeconds * 1000, ct);
|
||||
await Save(ct);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Handle(RequestContext ctx, Func<RequestContext, Task> next)
|
||||
{
|
||||
int uid = ctx.EventArgs.Message.From.Id;
|
||||
KarmaContext db = ctx.GetFeature<KarmaContext>();
|
||||
await PopulateStats(uid, db);
|
||||
DateTime debtLimit = DateTime.Now.AddSeconds(cfg.Timeout.DebtLimitSeconds);
|
||||
if (debtLimit < TimeoutCache[uid].CooldownDate)
|
||||
{
|
||||
if (!TimeoutCache[uid].TimeoutMessaged)
|
||||
{
|
||||
Locale currentLocale = ctx.GetFeature<Locale>();
|
||||
await ctx.SendMessage(currentLocale["jetkarmabot.ratelimit"]);
|
||||
TimeoutCache[uid].TimeoutMessaged = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
Feature feature = new Feature();
|
||||
ctx.Features.Add(feature);
|
||||
|
||||
await next(ctx);
|
||||
|
||||
var routerFeature = ctx.GetFeature<ChatCommandRouter.Feature>();
|
||||
await ApplyCost(getTypeName(routerFeature.CommandType), routerFeature.Succeded, uid, db, feature);
|
||||
}
|
||||
private string getTypeName(Type t)
|
||||
{
|
||||
return (t.DeclaringType == null ? t.Namespace + "." + t.Name : getTypeName(t.DeclaringType) + "." + t.Name)
|
||||
+ (t.GenericTypeArguments.Length > 0 ? "<" + string.Join(",", t.GenericTypeArguments.Select(getTypeName)) + ">" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
53
JetKarmaBot/Services/KarmaTimeoutManager.cs
Normal file
53
JetKarmaBot/Services/KarmaTimeoutManager.cs
Normal file
@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using JetBotLib;
|
||||
using JetKarmaBot.Models;
|
||||
using Perfusion;
|
||||
|
||||
namespace JetKarmaBot.Services
|
||||
{
|
||||
public class KarmaTimeoutManager : TimeoutManager
|
||||
{
|
||||
[Inject] Config cfg;
|
||||
[Inject] KarmaContextFactory Db;
|
||||
public override int SaveIntervalSeconds => cfg.Timeout.SaveIntervalSeconds;
|
||||
|
||||
public override int DebtLimitSeconds => cfg.Timeout.DebtLimitSeconds;
|
||||
|
||||
public override int GetCostSeconds(string name, bool status)
|
||||
{
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name + (status ? " (OK)" : "(ERR)"), out var costSeconds))
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue(name, out costSeconds))
|
||||
if (!cfg.Timeout.CommandCostsSeconds.TryGetValue("Default", out costSeconds))
|
||||
{
|
||||
throw new LocalizationException("Default key not present");
|
||||
}
|
||||
return costSeconds;
|
||||
}
|
||||
|
||||
public override async Task Save(CancellationToken ct = default(CancellationToken))
|
||||
{
|
||||
using (KarmaContext db = Db.GetContext())
|
||||
{
|
||||
foreach (int uid in TimeoutCache.Keys)
|
||||
{
|
||||
(await db.Users.FindAsync(new object[] { uid }, ct)).CooldownDate = TimeoutCache[uid].CooldownDate;
|
||||
}
|
||||
await db.SaveChangesAsync(ct);
|
||||
}
|
||||
}
|
||||
|
||||
protected override async Task LoadUser(int uid, RequestContext ctx = null)
|
||||
{
|
||||
KarmaContext db = ctx.GetFeature<KarmaContext>();
|
||||
if (!TimeoutCache.ContainsKey(uid))
|
||||
{
|
||||
TimeoutCache[uid] = new TimeoutStats()
|
||||
{
|
||||
CooldownDate = (await db.Users.FindAsync(uid))?.CooldownDate ?? DateTime.Now
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using JetBotLib;
|
||||
using JetKarmaBot.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user