Skip to content

Commit

Permalink
Refactoring telegram objects
Browse files Browse the repository at this point in the history
  • Loading branch information
dyatlov-a committed Jan 30, 2025
1 parent 0a92433 commit f56b78a
Show file tree
Hide file tree
Showing 18 changed files with 108 additions and 85 deletions.
2 changes: 1 addition & 1 deletion src/Inc.TeamAssistant.Connector.Application/CommandList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ internal static class CommandList
private const string AddLocationAlias = "/l";
public const string AddLocation = "/location";

public const string AddPollAnswer = "/poll_answer?pollId={0}&option={1}";
public const string AddPollAnswer = "/poll_answer?pollId={0}";

public const string EditDraft = "/edit_draft?description={0}";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Inc.TeamAssistant.Connector.Application.Contracts;

public interface IPersonPhotosService
public interface IPersonPhotoService
{
Task<byte[]?> GetPersonPhoto(long personId, CancellationToken token);
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using FluentValidation;
using Inc.TeamAssistant.Connector.Application.Services;
using Inc.TeamAssistant.Connector.Application.Telegram;
using Inc.TeamAssistant.Connector.Domain;
using Inc.TeamAssistant.Primitives.Commands;
using Inc.TeamAssistant.Primitives.Exceptions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@ namespace Inc.TeamAssistant.Connector.Application.QueryHandlers.GetPersonPhoto;

internal sealed class GetPersonPhotoQueryHandler : IRequestHandler<GetPersonPhotoQuery, GetPersonPhotoResult>
{
private readonly IPersonPhotosService _personPhotosService;
private readonly IPersonPhotoService _personPhotoService;

public GetPersonPhotoQueryHandler(IPersonPhotosService personPhotosService)
public GetPersonPhotoQueryHandler(IPersonPhotoService personPhotoService)
{
_personPhotosService = personPhotosService ?? throw new ArgumentNullException(nameof(personPhotosService));
_personPhotoService = personPhotoService ?? throw new ArgumentNullException(nameof(personPhotoService));
}

public async Task<GetPersonPhotoResult> Handle(GetPersonPhotoQuery query, CancellationToken token)
{
ArgumentNullException.ThrowIfNull(query);

var photo = await _personPhotosService.GetPersonPhoto(query.PersonId, token);
var photo = await _personPhotoService.GetPersonPhoto(query.PersonId, token);

return new GetPersonPhotoResult(photo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Inc.TeamAssistant.Connector.Application.Executors;
using Inc.TeamAssistant.Connector.Application.Parsers;
using Inc.TeamAssistant.Connector.Application.Services;
using Inc.TeamAssistant.Connector.Application.Telegram;
using Inc.TeamAssistant.Primitives.Bots;
using Inc.TeamAssistant.Primitives.Commands;
using Inc.TeamAssistant.Primitives.Handlers;
Expand All @@ -27,25 +28,25 @@ public static IServiceCollection AddConnectorApplication(
services
.AddSingleton<CommandFactory>()
.AddSingleton<DialogCommandFactory>()
.AddSingleton<MessageContextBuilder>()
.AddSingleton<TelegramMessageContextFactory>()
.AddSingleton<MessageParser>()
.AddSingleton<DialogContinuation>()
.AddSingleton<UpdateHandlerFactory>()
.AddHostedService<TelegramBotConnector>()
.AddSingleton<TelegramUpdateHandlerFactory>()
.AddHostedService<BotWorker>()
.AddSingleton<ICommandExecutor, CommandExecutor>()
.AddSingleton<TelegramBotClientProvider>()
.AddSingleton(new AliasService(CommandList.BuildAliasMap()))
.AddSingleton<SingleLineCommandFactory>()
.AddSingleton<CommandCreatorResolver>()
.AddSingleton<IBotAccessor, BotAccessor>()
.AddSingleton<ContextCommandConverter>()
.AddSingleton<IBotConnector, BotConnector>()
.AddSingleton<IBotListeners, BotListeners>()
.AddSingleton<TelegramContextCommandConverter>()
.AddSingleton<IBotConnector, TelegramBotConnector>()
.AddSingleton<IBotListeners, TelegramBotListeners>()

.AddSingleton<PersonPhotosService>()
.AddSingleton<IPersonPhotosService>(sp => ActivatorUtilities.CreateInstance<PersonPhotosServiceCache>(
.AddSingleton<TelegramPhotoService>()
.AddSingleton<IPersonPhotoService>(sp => ActivatorUtilities.CreateInstance<PersonPhotoServiceCache>(
sp,
sp.GetRequiredService<PersonPhotosService>(),
sp.GetRequiredService<TelegramPhotoService>(),
userAvatarCacheDurationInSeconds))

.AddTransient(typeof(IRequestPostProcessor<,>), typeof(CommandPostProcessor<,>))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace Inc.TeamAssistant.Connector.Application.Services;

internal sealed class TelegramBotConnector : IHostedService
internal sealed class BotWorker : IHostedService
{
private readonly IBotReader _botReader;
private readonly IBotListeners _botListeners;

public TelegramBotConnector(IBotReader botReader, IBotListeners botListeners)
public BotWorker(IBotReader botReader, IBotListeners botListeners)
{
_botReader = botReader ?? throw new ArgumentNullException(nameof(botReader));
_botListeners = botListeners ?? throw new ArgumentNullException(nameof(botListeners));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using Inc.TeamAssistant.Connector.Application.Telegram;
using Inc.TeamAssistant.Primitives.Commands;
using Inc.TeamAssistant.Primitives.Notifications;
using MediatR.Pipeline;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
using System.Runtime.CompilerServices;
using Inc.TeamAssistant.Connector.Application.Contracts;
using Microsoft.Extensions.Caching.Memory;

namespace Inc.TeamAssistant.Connector.Application.Services;

internal sealed class PersonPhotosServiceCache : IPersonPhotosService
internal sealed class PersonPhotoServiceCache : IPersonPhotoService
{
private readonly IPersonPhotosService _service;
private readonly IPersonPhotoService _service;
private readonly IMemoryCache _memoryCache;
private readonly int _cacheDurationInSeconds;

public PersonPhotosServiceCache(IPersonPhotosService service, IMemoryCache memoryCache, int cacheDurationInSeconds)
public PersonPhotoServiceCache(IPersonPhotoService service, IMemoryCache memoryCache, int cacheDurationInSeconds)
{
_service = service ?? throw new ArgumentNullException(nameof(service));
_memoryCache = memoryCache ?? throw new ArgumentNullException(nameof(memoryCache));
Expand All @@ -20,14 +21,19 @@ public PersonPhotosServiceCache(IPersonPhotosService service, IMemoryCache memor
{
const int maxCacheDurationRandomComponentInSeconds = 60 * 5;

return await _memoryCache.GetOrCreateAsync($"user_avatar__{personId}", async c =>
return await _memoryCache.GetOrCreateAsync(ToKey(personId), async c =>
{
var cacheDurationRandomComponentInSeconds = Random.Shared.Next(0, maxCacheDurationRandomComponentInSeconds);
var cacheDurationRandomComponentInSeconds = Random.Shared.Next(1, maxCacheDurationRandomComponentInSeconds);
var cacheDuration = TimeSpan.FromSeconds(_cacheDurationInSeconds + cacheDurationRandomComponentInSeconds);

c.SetAbsoluteExpiration(cacheDuration);

return await _service.GetPersonPhoto(personId, token);
});
}

private static string ToKey(long personId, [CallerMemberName] string method = "")
{
return $"{nameof(PersonPhotoServiceCache)}__{method}__{personId}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
using Inc.TeamAssistant.Primitives.Exceptions;
using Telegram.Bot;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class TelegramBotClientProvider
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@
using Telegram.Bot;
using Telegram.Bot.Types;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class BotConnector : IBotConnector
internal sealed class TelegramBotConnector : IBotConnector
{
private readonly IBotReader _botReader;
private readonly ContextCommandConverter _converter;
private readonly TelegramContextCommandConverter _converter;
private readonly IMessageBuilder _messageBuilder;

public BotConnector(IBotReader botReader, ContextCommandConverter converter, IMessageBuilder messageBuilder)
public TelegramBotConnector(
IBotReader botReader,
TelegramContextCommandConverter converter,
IMessageBuilder messageBuilder)
{
_botReader = botReader ?? throw new ArgumentNullException(nameof(botReader));
_converter = converter ?? throw new ArgumentNullException(nameof(converter));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
using Telegram.Bot.Polling;
using Telegram.Bot.Types.Enums;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class BotListeners : IBotListeners
internal sealed class TelegramBotListeners : IBotListeners
{
private readonly UpdateHandlerFactory _updateHandlerFactory;
private readonly TelegramUpdateHandlerFactory _updateHandlerFactory;
private readonly IBotReader _botReader;
private readonly ILogger<BotListeners> _logger;
private readonly ILogger<TelegramBotListeners> _logger;

private static readonly ReceiverOptions ReceiverOptions = new()
{
Expand All @@ -21,7 +21,10 @@ internal sealed class BotListeners : IBotListeners
private readonly ConcurrentDictionary<Guid, CancellationTokenSource> _listeners = new();
private volatile int _isWorking = 1;

public BotListeners(UpdateHandlerFactory updateHandlerFactory, IBotReader botReader, ILogger<BotListeners> logger)
public TelegramBotListeners(
TelegramUpdateHandlerFactory updateHandlerFactory,
IBotReader botReader,
ILogger<TelegramBotListeners> logger)
{
_updateHandlerFactory = updateHandlerFactory ?? throw new ArgumentNullException(nameof(updateHandlerFactory));
_botReader = botReader ?? throw new ArgumentNullException(nameof(botReader));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
using Inc.TeamAssistant.Connector.Application.Contracts;
using Inc.TeamAssistant.Connector.Application.Services;
using Inc.TeamAssistant.Primitives.Commands;
using Microsoft.Extensions.Logging;
using Telegram.Bot;
using Telegram.Bot.Polling;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class TelegramBotMessageHandler : IUpdateHandler
{
private readonly ILogger _logger;
private readonly CommandFactory _commandFactory;
private readonly ICommandExecutor _commandExecutor;
private readonly MessageContextBuilder _messageContextBuilder;
private readonly TelegramMessageContextFactory _messageContextFactory;
private readonly IBotReader _botReader;
private readonly Guid _botId;

public TelegramBotMessageHandler(
ILogger logger,
CommandFactory commandFactory,
ICommandExecutor commandExecutor,
MessageContextBuilder messageContextBuilder,
TelegramMessageContextFactory messageContextFactory,
IBotReader botReader,
Guid botId)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_commandFactory = commandFactory ?? throw new ArgumentNullException(nameof(commandFactory));
_commandExecutor = commandExecutor ?? throw new ArgumentNullException(nameof(commandExecutor));
_messageContextBuilder =
messageContextBuilder ?? throw new ArgumentNullException(nameof(messageContextBuilder));
_messageContextFactory = messageContextFactory ?? throw new ArgumentNullException(nameof(messageContextFactory));
_botReader = botReader ?? throw new ArgumentNullException(nameof(botReader));
_botId = botId;
}
Expand All @@ -46,21 +46,21 @@ public async Task HandleUpdateAsync(ITelegramBotClient botClient, Update update,
var bot = await _botReader.Find(_botId, DateTimeOffset.UtcNow, token);
if (bot is not null)
{
var messageContext = await _messageContextBuilder.Build(bot, update, token);
var messageContext = await _messageContextFactory.Create(bot, update, token);
if (messageContext is not null)
{
var command = await _commandFactory.TryCreate(bot, messageContext, token);
if (command is not null)
await _commandExecutor.Execute(command, token);
}

if (update.CallbackQuery is not null)
await botClient.AnswerCallbackQueryAsync(
update.CallbackQuery.Id,
"Done",
false,
cancellationToken: token);
}

if (update.CallbackQuery is not null)
await botClient.AnswerCallbackQueryAsync(
update.CallbackQuery.Id,
"Done",
false,
cancellationToken: token);
}
catch (Exception ex)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
using Inc.TeamAssistant.Primitives.Languages;
using Telegram.Bot.Types;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class ContextCommandConverter
internal sealed class TelegramContextCommandConverter
{
private readonly IMessageBuilder _messageBuilder;

public ContextCommandConverter(IMessageBuilder messageBuilder)
public TelegramContextCommandConverter(IMessageBuilder messageBuilder)
{
_messageBuilder = messageBuilder ?? throw new ArgumentNullException(nameof(messageBuilder));
}
Expand All @@ -25,13 +25,14 @@ public ContextCommandConverter(IMessageBuilder messageBuilder)
var commandsByScopes = contextCommands
.Where(c => c.HelpMessageId is not null && c.Scopes.Any(s => s == commandScope))
.ToArray();
if (!commandsByScopes.Any())
continue;

var botCommandScope = ToBotCommandScope(commandScope);
var botCommands = await ToBotCommands(commandsByScopes, languageId);
if (commandsByScopes.Any())
{
var botCommandScope = ToBotCommandScope(commandScope);
var botCommands = await ToBotCommands(commandsByScopes, languageId);

yield return (botCommandScope, botCommands);
yield return (botCommandScope, botCommands);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Text;
using Inc.TeamAssistant.Connector.Application.Contracts;
using Inc.TeamAssistant.Connector.Application.Parsers;
using Inc.TeamAssistant.Connector.Domain;
Expand All @@ -9,15 +10,15 @@
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;

namespace Inc.TeamAssistant.Connector.Application.Services;
namespace Inc.TeamAssistant.Connector.Application.Telegram;

internal sealed class MessageContextBuilder
internal sealed class TelegramMessageContextFactory
{
private readonly IPersonRepository _personRepository;
private readonly IClientLanguageRepository _clientLanguageRepository;
private readonly MessageParser _messageParser;

public MessageContextBuilder(
public TelegramMessageContextFactory(
IPersonRepository personRepository,
IClientLanguageRepository clientLanguageRepository,
MessageParser messageParser)
Expand All @@ -27,7 +28,7 @@ public MessageContextBuilder(
_messageParser = messageParser ?? throw new ArgumentNullException(nameof(messageParser));
}

public async Task<MessageContext?> Build(Bot bot, Update update, CancellationToken token)
public async Task<MessageContext?> Create(Bot bot, Update update, CancellationToken token)
{
ArgumentNullException.ThrowIfNull(bot);
ArgumentNullException.ThrowIfNull(update);
Expand Down Expand Up @@ -72,8 +73,10 @@ public MessageContextBuilder(
ArgumentNullException.ThrowIfNull(bot);
ArgumentNullException.ThrowIfNull(pollAnswer);

var parameters = string.Join("&option=", pollAnswer.OptionIds);
var text = string.Format(CommandList.AddPollAnswer, pollAnswer.PollId, parameters);
var text = pollAnswer.OptionIds.Aggregate(
new StringBuilder(string.Format(CommandList.AddPollAnswer, pollAnswer.PollId)),
(sb, p) => sb.Append(GlobalSettings.OptionParameterName).Append(p),
sb => sb.ToString());

return await Create(
bot,
Expand Down Expand Up @@ -184,9 +187,6 @@ private async Task<Person> EnsurePerson(User user, CancellationToken token)
private IReadOnlyList<TeamContext> GetTeams(Bot bot, long personId, long chatId)
{
ArgumentNullException.ThrowIfNull(bot);

bool MemberOfTeam(Team t) => t.Teammates.Any(tm => tm.Id == personId);
bool OwnerOfTeam(Team t) => t.Owner.Id == personId;

var memberOfChats = bot.Teams
.Where(t => MemberOfTeam(t) || t.ChatId == chatId || t.Owner.Id == personId)
Expand All @@ -199,5 +199,8 @@ private IReadOnlyList<TeamContext> GetTeams(Bot bot, long personId, long chatId)
.ToArray();

return results;

bool MemberOfTeam(Team t) => t.Teammates.Any(tm => tm.Id == personId);
bool OwnerOfTeam(Team t) => t.Owner.Id == personId;
}
}
Loading

0 comments on commit f56b78a

Please sign in to comment.