Skip to content
This repository was archived by the owner on May 12, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Kysect.BotFramework.ConsoleTest/Program.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using System.Threading.Tasks;
using Kysect.BotFramework.ApiProviders.Discord;
using Kysect.BotFramework.ApiProviders.Telegram;
using Kysect.BotFramework.Commands;
using Kysect.BotFramework.DefaultCommands;
using Kysect.BotFramework.Core;
using Kysect.BotFramework.DefaultCommands;
using Kysect.BotFramework.Settings;

namespace Kysect.BotFramework.ConsoleTest
Expand All @@ -19,6 +21,7 @@ private static async Task MainAsync()
.SetPrefix('!')
.SetCaseSensitive(false)
.AddCommand(PingCommand.Descriptor)
.AddCommand(PollCommand.Descriptor)
.Build(api);

botManager.Start();
Expand Down
110 changes: 104 additions & 6 deletions Kysect.BotFramework/ApiProviders/Discord/DiscordApiProvider.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.Rest;
using Discord.WebSocket;
using DSharpPlus;
using DSharpPlus.Entities;
using FluentResults;
using Kysect.BotFramework.Core;
using Kysect.BotFramework.Core.BotMedia;
using Kysect.BotFramework.Core.BotMessages;
using Kysect.BotFramework.Core.Tools.Loggers;
using Kysect.BotFramework.DefaultCommands;
using Kysect.BotFramework.Settings;
using TokenType = Discord.TokenType;
using System.Text.RegularExpressions;

namespace Kysect.BotFramework.ApiProviders.Discord
{
Expand All @@ -21,6 +27,12 @@ public class DiscordApiProvider : IBotApiProvider, IDisposable
private readonly object _lock = new object();
private readonly DiscordSettings _settings;
private DiscordSocketClient _client;
private int _argsCount;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это не часть логики DiscordApiProvider.


private readonly string[] _emojis =
{
"", "1️⃣", "2️⃣", "3️⃣","4️⃣","5️⃣","6️⃣","7️⃣", "8️⃣", "9️⃣", "🔟"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Bibletoon Записывай как работать с эмодзи кекв

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(это локальный мем, если что, не обращайте внимания)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Кекв

};
Comment on lines +32 to +35
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Это не часть логики DiscordApiProvider.


public DiscordApiProvider(ISettingsProvider<DiscordSettings> settingsProvider)
{
Expand Down Expand Up @@ -118,12 +130,26 @@ public Result<string> SendTextMessage(string text, SenderInfo sender)
if (text.Length == 0)
{
LoggerHolder.Instance.Error("The message wasn't sent by the command " +
$"\"{PingCommand.Descriptor.CommandName}\", the length must not be zero.");
"\"{CommandName}\", the length must not be zero",
PingCommand.Descriptor.CommandName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Почему именно PingCommand.Descriptor.CommandName?
  2. А в чем идея этого изменения?

return Result.Ok();
}

return SendText(text, sender);
}

public Result<string> SendPollMessage(string text, SenderInfo sender)
{
if (text.Length == 0)
{
LoggerHolder.Instance.Error("The message wasn't sent by the command " +
"\"{CommandName}\", the length must not be zero",
PollCommand.Descriptor.CommandName);
return Result.Ok();
Comment on lines +145 to +148

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Залогировали ошибку и вернули ок?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А почему тут Result.Ok, если это возвращение при ошибке - не валидном наборе аргументов.

}

return SendPoll(text, sender);
}

public void Dispose()
{
Expand All @@ -150,15 +176,22 @@ private Task ClientOnMessage(SocketMessage arg)
}

var context = new SocketCommandContext(_client, message);
if (!context.User.IsBot && context.Message.Content.Contains("!Poll"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Это не должно быть в ApiProvider
  2. Ты хардкодишь конкретную команду тут, так быть не должно иначе этот метод на каждую команду будет получать новый if
  3. А мы разве не поддерживаем кастомные префиксы для команд?

{
_argsCount = GetPollArguments(message.Content).Count() - 1;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Что за -1?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я думаю это связано с тем, что на 0 позиции будет название команды, а остальные - это аргументы пула. А он считает именно их кол-во.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тогда не понял, почему вообще название команды это аргумент команды...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

На 0-й позиции будет заголовок опроса. -1 поправлю, глупый момент, согласен

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Команды не должны менять внутренний контекст провайдера иначе будут сайд эффекты при параллельных запросах.

}
if (context.User.IsBot && context.Message.Embeds.Any())
{
ReactWithEmojis(context);
}

if (context.User.IsBot || context.Guild is null)
{
return Task.CompletedTask;
}

LoggerHolder.Instance.Debug($"New message event: {context.Message}");

IBotMessage botMessage = ParseMessage(message, context);

OnMessage?.Invoke(context.Client,
new BotEventArgs(
botMessage,
Expand Down Expand Up @@ -270,18 +303,83 @@ private Result<string> SendText(string text, SenderInfo sender)
return Result.Fail(new Error(message).CausedBy(e));
}
}

private Result<string> SendPoll(string text, SenderInfo sender)
{
List<string> arguments = GetPollArguments(text);

Result<string> result = CheckText(text);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Наверное же сначала нужно делать этот чек, а потом уже GetPoolArgs.

if (result.IsFailed)
{
return result;
}

for (int i = 1; i < arguments.Count; i++)
{
arguments[i] = _emojis[i] + "\t" + arguments[i];
}

var embed = new EmbedBuilder
{
Title = arguments[0],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

У тебя из метода GetPollArguments может вернуться пустой лист

Color = Color.Purple,
Description = String.Join("\n", arguments.Skip(1))
};

Comment on lines +317 to +328
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Опять же, это выглядит как логика создания какого-то особенного сообщения. Давайте выделим класс PoolInfoMessage, которое будет создаваться от аргументов, внутри вот эти действия делать и ему оставим метод BuildToEmbed.

Task<RestUserMessage> task = _client.GetGuild((ulong) sender.GroupId)
.GetTextChannel((ulong) sender.UserSenderId)
.SendMessageAsync(embed: embed.Build());

try
{
task.Wait();
return Result.Ok("Message send");
}
catch (Exception e)
{
var message = "Error while sending message";
LoggerHolder.Instance.Error(e, message);
return Result.Fail(new Error(message).CausedBy(e));
}
}

private Result<string> CheckText(string text)
{
if (text.Length > 2000)
{
string subString = text.Substring(0, 99) + "...";
string errorMessage = "The message wasn't sent by the command " +
$"\"{PingCommand.Descriptor.CommandName}\", the length is too big.";
$"\"{PingCommand.Descriptor.CommandName}\", the length is too big";
return Result.Fail(new Error(errorMessage).CausedBy(subString));
}

return Result.Ok();
}

private List<string> GetPollArguments(string args)
{
var regex = new Regex(@"[^\s""']+|""([^""]*)""|'([^']*)'"); // Splits into "..." '...' a b c

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А в чем смысл создавать каждый раз одну и ту же регулярку? Ну сделай ее статичным полем приватным просто

var matches = regex.Matches(args);
List<string> options = new List<string>();

if (matches.Count > 0)
{
foreach (Match match in matches)
{
options.Add(match.Value.Replace("\"", ""));
}
}

return options;
}
Comment on lines +359 to +374
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну вот этот метод точно можно было унести куда-то. Не относится к DiscordProvider.


private async void ReactWithEmojis(SocketCommandContext context)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Мне почему-то кажется, что тут более подходящим названием было AddReactionToMessage.
  2. Имеет смысл вынести логику реакции. Например, сделать класс MessageWithPool, который в конструктор принимал бы message и poolAnswerCount и внутри бы делал вот эту магию с добавлением Emoji.

{
for (int i = 1; i < _argsCount; i++)
{
await context.Message.AddReactionAsync(new Emoji(_emojis[i]))
.ConfigureAwait(false);
}
}
Comment on lines +376 to +383

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Да откуда вы все берете ConfigureAwait? Вам кто-то о нем рассказал или что?
async void не используй, без понимания как, почему и зачем просто сделай async Task

}
}
1 change: 1 addition & 0 deletions Kysect.BotFramework/ApiProviders/IBotApiProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,6 @@ public interface IBotApiProvider
Result<string> SendMedia(IBotMediaFile mediaFile, string text, SenderInfo sender);
Result<string> SendOnlineMedia(IBotOnlineFile file, string text, SenderInfo sender);
Result<string> SendTextMessage(string text, SenderInfo sender);
Result<string> SendPollMessage(string text, SenderInfo sender);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ public TelegramApiProvider(ISettingsProvider<TelegramSettings> settingsProvider)
_settings = settingsProvider.GetSettings();
Initialize();
}

public event EventHandler<BotEventArgs> OnMessage;

public void Restart()
Expand Down Expand Up @@ -308,6 +307,8 @@ private Result<string> SendText(string text, SenderInfo sender)
return Result.Fail(new Error(message).CausedBy(e));
}
}

public Result<string> SendPollMessage(string text, SenderInfo sender) => throw new NotImplementedException();

private Result<string> CheckText(string text)
{
Expand Down
2 changes: 2 additions & 0 deletions Kysect.BotFramework/ApiProviders/VK/VkFixedApiProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ public void Restart()

public Result<string> SendTextMessage(string text, SenderInfo sender) => throw new NotImplementedException();

public Result<string> SendPollMessage(string text, SenderInfo sender) => throw new NotImplementedException();

public void Dispose()
{
throw new NotImplementedException();
Expand Down
23 changes: 23 additions & 0 deletions Kysect.BotFramework/Core/BotMessages/BotPollMessage.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using Kysect.BotFramework.ApiProviders;
using Telegram.Bot.Requests;

namespace Kysect.BotFramework.Core.BotMessages
{
public class BotPollMessage : IBotMessage
{
public BotPollMessage(string text)
{
Text = text;
}

public string Text { get; }

public void Send(IBotApiProvider apiProvider, SenderInfo sender)
{
apiProvider.SendPollMessage(Text, sender);
}
}
}
3 changes: 2 additions & 1 deletion Kysect.BotFramework/Core/CommandInvoking/CommandHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using FluentResults;
using Kysect.BotFramework.Core.BotMessages;
using Kysect.BotFramework.Core.Commands;
using Kysect.BotFramework.DefaultCommands;
using Microsoft.Extensions.DependencyInjection;

namespace Kysect.BotFramework.Core.CommandInvoking
Expand All @@ -24,7 +25,7 @@ public Result CheckArgsCount(CommandContainer args)
return commandTask.ToResult<CommandContainer>();
}

return commandTask.Value.Args.Length == args.Arguments.Count
return (commandTask.Value.Args.Count == args.Arguments.Count) || (args.CommandName == "Poll") // Better way to check for Poll?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Что-то вообще ничего не понял

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Если есть кастомная логика проверки валидности размера, то предлагаю сделать базовый класс для команд, где будет виртуальный метод IsValidArgumentCount, который проверяет commandTask.Value.Args.Count == args.Arguments.Count, а PollCommand будет наследоваться и оверрайдить со своей кастомной логикой (в идеале там должен быть парсинг и какая-то проверка, а не "если poll - значит точно ок".

? Result.Ok()
: Result.Fail<CommandContainer>(
"Cannot execute command. Argument count miss matched with command signature");
Expand Down
9 changes: 5 additions & 4 deletions Kysect.BotFramework/Core/Commands/BotCommandDescriptor.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using Kysect.BotFramework.Core.CommandInvoking;
using Microsoft.Extensions.DependencyInjection;

Expand All @@ -8,9 +9,9 @@ public abstract class BotCommandDescriptor
{
public string CommandName { get; }
public string Description { get; }
public string[] Args { get; }
public List<string> Args { get; }
Comment on lines -11 to +12

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В чем суть данного (и пачки ниже) изменения?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Хотел получать переменное кол-во аргументов. Изначально нужно было указывать определенное количество, как я понял. Так же и появилась проблема выше - проверка на полученное количество аргументов и заданное на получение в PollCommand дескрипторе, как args

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Вообще ничего не понял
Что значит переменное кол-во аргументов?
Ты хочешь сам изменять аргументы команды? Ты явно делаешь что-то не так

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ну нам нужно получать !Poll + args и непонятно как действовать с string[ ], т.к. он просит указать точное количество args, а их может быть от 1 до 10 по логике, поэтому изменил на лист. Может и правда не так понял 😕

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Так тебе приходит запрос уже с каким-то конкретным количеством аргументов, зачем тут лист?
Ну пришло 5 - массив из 5 элементов
7 - из 7
Сам по себе-то массив не меняется


public BotCommandDescriptor(string commandName, string description, string[] args)
public BotCommandDescriptor(string commandName, string description, List<string> args)
{
CommandName = commandName;
Description = description;
Expand All @@ -22,13 +23,13 @@ public BotCommandDescriptor(string commandName, string description, string[] arg

public class BotCommandDescriptor<T> : BotCommandDescriptor where T : IBotCommand
{
public BotCommandDescriptor(string commandName, string description, string[] args)
public BotCommandDescriptor(string commandName, string description, List<string> args)
: base(commandName, description, args)
{
}

public BotCommandDescriptor(string commandName, string description)
: this(commandName, description, Array.Empty<string>())
: this(commandName, description, new List<string>())
{
}

Expand Down
25 changes: 25 additions & 0 deletions Kysect.BotFramework/DefaultCommands/PollCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using FluentResults;
using Kysect.BotFramework.Core.BotMessages;
using Kysect.BotFramework.Core.Commands;

namespace Kysect.BotFramework.DefaultCommands
{
public class PollCommand : IBotAsyncCommand
{
public static readonly BotCommandDescriptor<PollCommand> Descriptor = new BotCommandDescriptor<PollCommand>(
"Poll",
"Create a new poll", new List<string>());

public Result CanExecute(CommandContainer args) => Result.Ok();

public Task<Result<IBotMessage>> Execute(CommandContainer args)
{
IBotMessage message = new BotPollMessage(String.Join(" ", args.Arguments));
return Task.FromResult(Result.Ok(message));
Comment on lines +21 to +22
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ничего не понял)
Почему мы на эту команду делаем ничего?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В предыдущих сериях pr'ах была добавлена возможность отправлять не только текст, поэтому команда отвечает только за то, что бы создать сообщение, а вызовом метода отправки занимается BotManager (так как сообщению нужен api provider, что бы отправиться)

}
Comment on lines +19 to +23

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не понял, создал ботмесседж и вернул его
А где сама логика Execute-то?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

А она внутри IBotMessage и вызывается BotManager'ом

}
}
1 change: 1 addition & 0 deletions Kysect.BotFramework/Kysect.BotFramework.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

<ItemGroup>
<PackageReference Include="Discord.Net" Version="2.3.1" />
<PackageReference Include="DSharpPlus" Version="4.1.0" />
<PackageReference Include="FluentResults" Version="2.3.0" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="5.0.1" />
<PackageReference Include="Serilog" Version="2.10.0" />
Expand Down