Skip to content

Commit

Permalink
improve lols.bot querying
Browse files Browse the repository at this point in the history
  • Loading branch information
TiraelSedai committed Jul 31, 2024
1 parent 12c360b commit a86c341
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 58 deletions.
55 changes: 33 additions & 22 deletions ClubDoorman/UserManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,6 @@ private async Task Init()
if (banlist != null)
foreach (var id in banlist)
_banlist.TryAdd(id, 0);
_ = Task.Run(async () =>
{
while (true)
{
await Task.Delay(TimeSpan.FromMinutes(15));
try
{
var banlistOneHour = await httpClient.GetFromJsonAsync<string[]>("https://lols.bot/spam/banlist-1h.json") ?? [];
foreach (var id in banlistOneHour.Select(long.Parse))
_banlist.TryAdd(id, 0);
}
catch (Exception e)
{
_logger.LogWarning(e, "Exception during banlist update");
}
}
});
}

public UserManager(ILogger<UserManager> logger)
Expand All @@ -41,13 +24,14 @@ public UserManager(ILogger<UserManager> logger)
if (Config.ClubServiceToken == null)
_logger.LogWarning("DOORMAN_CLUB_SERVICE_TOKEN variable is not set, additional club checks disabled");
else
_httpClient.DefaultRequestHeaders.Add("X-Service-Token", Config.ClubServiceToken);
_clubHttpClient.DefaultRequestHeaders.Add("X-Service-Token", Config.ClubServiceToken);
}

private const string Path = "data/approved-users.txt";
private readonly ConcurrentDictionary<long, byte> _banlist = [];
private readonly SemaphoreSlim _semaphore = new(1);
private readonly HashSet<long> _approved = File.ReadAllLines(Path).Select(long.Parse).ToHashSet();
private readonly HttpClient _clubHttpClient = new();
private readonly HttpClient _httpClient = new();

public bool Approved(long userId) => _approved.Contains(userId);
Expand All @@ -61,7 +45,27 @@ public async ValueTask Approve(long userId)
}
}

public bool InBanlist(long userId) => _banlist.ContainsKey(userId);
public async ValueTask<bool> InBanlist(long userId)
{
if (_banlist.ContainsKey(userId))
return true;
try
{
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(5));
var result = await _httpClient.GetFromJsonAsync<LolsBotApiResponse>($"https://lols.bot/?a={userId}", cts.Token);
if (!result!.banned)
return false;

_banlist.TryAdd(userId, 0);
return true;
}
catch (Exception e)
{
_logger.LogWarning(e, "LolsBotApi exception");
return false;
}
}

public async ValueTask<string?> GetClubUsername(long userId)
{
Expand All @@ -70,9 +74,13 @@ public async ValueTask Approve(long userId)
var url = $"{Config.ClubUrl}user/by_telegram_id/{userId}.json";
try
{
var get = await _httpClient.GetAsync(url);
var resp = await get.Content.ReadFromJsonAsync<ClubByTgIdResponse>();
return resp?.user?.full_name;
using var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(5));
var response = await _clubHttpClient.GetFromJsonAsync<ClubByTgIdResponse>(url, cts.Token);
var fullName = response?.user?.full_name;
if (!string.IsNullOrEmpty(fullName))
await Approve(userId);
return fullName;
}
catch (Exception e)
{
Expand All @@ -83,6 +91,9 @@ public async ValueTask Approve(long userId)

#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
#pragma warning disable IDE1006 // Naming Styles

private record LolsBotApiResponse(long user_id, int offenses, bool banned);

internal class ClubByTgIdResponse
{
public Error? error { get; set; }
Expand Down
68 changes: 32 additions & 36 deletions ClubDoorman/Worker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -141,11 +141,10 @@ private async Task HandleUpdate(Update update, User me, CancellationToken stoppi
var name = await userManager.GetClubUsername(user.Id);
if (!string.IsNullOrEmpty(name))
{
await userManager.Approve(user.Id);
logger.LogDebug("User is {Name} from club", name);
return;
}
if (userManager.InBanlist(user.Id))
if (await userManager.InBanlist(user.Id))
{
const string reason = "Пользователь в блеклисте спамеров";
await DeleteAndReportMessage(message, user, reason, stoppingToken);
Expand Down Expand Up @@ -272,10 +271,7 @@ private async ValueTask IntroFlow(Message? userJoinMessage, User user, Chat? cha
return;
var clubUser = await userManager.GetClubUsername(user.Id);
if (clubUser != null)
{
await userManager.Approve(user.Id);
return;
}

chat = userJoinMessage?.Chat ?? chat;
Debug.Assert(chat != null);
Expand Down Expand Up @@ -345,7 +341,7 @@ private async Task<bool> BanIfBlacklisted(User user, Chat chat)
{
if (!Config.BlacklistAutoBan)
return false;
if (!userManager.InBanlist(user.Id))
if (!await userManager.InBanlist(user.Id))
return false;

try
Expand Down Expand Up @@ -409,22 +405,22 @@ private async Task HandleChatMemberUpdated(Update update)
switch (newChatMember.Status)
{
case ChatMemberStatus.Member:
{
logger.LogDebug("New chat member new {@New} old {@Old}", newChatMember, chatMember.OldChatMember);
if (chatMember.OldChatMember.Status == ChatMemberStatus.Left)
{
logger.LogDebug("New chat member new {@New} old {@Old}", newChatMember, chatMember.OldChatMember);
if (chatMember.OldChatMember.Status == ChatMemberStatus.Left)
// The reason we need to wait here is that we need to get message that user joined to have a chance to be processed first,
// this is not mandatory but looks nicer, however sometimes Telegram doesn't send it at all so consider this a fallback.
// There is no way real human would be able to solve this captcha in under 2 seconds so it's fine.
_ = Task.Run(async () =>
{
// The reason we need to wait here is that we need to get message that user joined to have a chance to be processed first,
// this is not mandatory but looks nicer, however sometimes Telegram doesn't send it at all so consider this a fallback.
// There is no way real human would be able to solve this captcha in under 2 seconds so it's fine.
_ = Task.Run(async () =>
{
await Task.Delay(TimeSpan.FromSeconds(2));
await IntroFlow(null, newChatMember.User, chatMember.Chat);
});
}

break;
await Task.Delay(TimeSpan.FromSeconds(2));
await IntroFlow(null, newChatMember.User, chatMember.Chat);
});
}

break;
}
case ChatMemberStatus.Kicked
or ChatMemberStatus.Restricted:
await _bot.SendTextMessageAsync(
Expand Down Expand Up @@ -493,23 +489,23 @@ private async Task AdminChatMessage(Message message)
switch (message.Text)
{
case "/check":
{
var emojis = SimpleFilters.TooManyEmojis(text);
var normalized = TextProcessor.NormalizeText(text);
var lookalike = SimpleFilters.FindAllRussianWordsWithLookalikeSymbolsInNormalizedText(normalized);
var hasStopWords = SimpleFilters.HasStopWords(normalized);
var (spam, score) = await classifier.IsSpam(normalized);
var lookAlikeMsg = lookalike.Count == 0 ? "отсутствуют" : string.Join(", ", lookalike);
var msg =
$"Результат:{Environment.NewLine}"
+ $"Много эмодзи: {emojis}{Environment.NewLine}"
+ $"Найдены стоп-слова: {hasStopWords}{Environment.NewLine}"
+ $"Маскирующиеся слова: {lookAlikeMsg}{Environment.NewLine}"
+ $"ML классификатор: спам {spam}, скор {score}{Environment.NewLine}{Environment.NewLine}"
+ $"Если простые фильтры отработали, то в датасет добавлять не нужно";
await _bot.SendTextMessageAsync(message.Chat.Id, msg);
break;
}
{
var emojis = SimpleFilters.TooManyEmojis(text);
var normalized = TextProcessor.NormalizeText(text);
var lookalike = SimpleFilters.FindAllRussianWordsWithLookalikeSymbolsInNormalizedText(normalized);
var hasStopWords = SimpleFilters.HasStopWords(normalized);
var (spam, score) = await classifier.IsSpam(normalized);
var lookAlikeMsg = lookalike.Count == 0 ? "отсутствуют" : string.Join(", ", lookalike);
var msg =
$"Результат:{Environment.NewLine}"
+ $"Много эмодзи: {emojis}{Environment.NewLine}"
+ $"Найдены стоп-слова: {hasStopWords}{Environment.NewLine}"
+ $"Маскирующиеся слова: {lookAlikeMsg}{Environment.NewLine}"
+ $"ML классификатор: спам {spam}, скор {score}{Environment.NewLine}{Environment.NewLine}"
+ $"Если простые фильтры отработали, то в датасет добавлять не нужно";
await _bot.SendTextMessageAsync(message.Chat.Id, msg);
break;
}
case "/spam":
await classifier.AddSpam(message.ReplyToMessage.Text ?? message.ReplyToMessage.Caption ?? string.Empty);
await _bot.SendTextMessageAsync(
Expand Down

0 comments on commit a86c341

Please sign in to comment.