FileInlineConverter

using PRTelegramBot.Core.BotScope;
using PRTelegramBot.Extensions;
using PRTelegramBot.Interfaces;
using PRTelegramBot.Models.CallbackCommands;
using PRTelegramBot.Models.InlineButtons;
using System.Collections.Concurrent;

namespace PRTelegramBot.Converters.Inline
{
    /// <summary>
    /// Конвертер inline меню в файлы.
    /// Сохраняет временные данные в формате файлов "{Ид бота}-{Ид пользователя}-{Ид команды}".
    /// Файлы сохраняются в папке "InlineCallbacks" в директории приложения. При создание экзепляра можно указать другое название папки.
    /// </summary>
    public class FileInlineConverter : IInlineMenuConverter
    {
        /// <summary>
        /// Базовый путь для сохранения файлов.
        /// </summary>
        protected string basePath;

        /// <summary>
        /// Локи против raceCondition.
        /// </summary>
        private static readonly ConcurrentDictionary<string, object> fileLocks = new();

        #region IInlineMenuConverter

        /// <inheritdoc />
        public string GenerateCallbackData(InlineCallback inlineCallback)
        {
            BaseConvert(inlineCallback.CommandType, () => CurrentScope.Bot.GetSerializer().Serialize(inlineCallback));
            return GetUserKey(inlineCallback.CommandType);
        }

        /// <inheritdoc />
        public string GenerateCallbackData<T>(InlineCallback<T> inlineCallback) where T : TCommandBase
        {
            BaseConvert(inlineCallback.CommandType, () => CurrentScope.Bot.GetSerializer().Serialize<InlineCallback<T>>(inlineCallback));
            return GetUserKey(inlineCallback.CommandType);
        }

        /// <inheritdoc />
        public InlineCallback? GetCommandByCallbackOrNull(string data)
        {
            var file = $"{basePath}/{data}.json";

            if (!File.Exists(file))
                return null;

            var result = File.ReadAllText(file);

            return CurrentScope.Bot.GetSerializer().Deserialize<InlineCallback>(result);
        }

        /// <inheritdoc />
        public InlineCallback<T>? GetCommandByCallbackOrNull<T>(string data) where T : TCommandBase
        {
            var file = $"{basePath}/{data}.json";

            if (!File.Exists(file))
                return null;

            var result = File.ReadAllText(file);

            return CurrentScope.Bot.GetSerializer().Deserialize<InlineCallback<T>>(result);
        }

        #endregion

        private string GetUserKey(Enum command)
        {
            return CurrentScope.Context.Update.GetInlineKey(command);
        }

        private string BaseConvert(Enum command, Func<string> convert)
        {
            try
            {
                var userKey = GetUserKey(command);
                var filePath = Path.Combine(basePath, $"{userKey}.json");
                var data = convert();

                if (!Directory.Exists(basePath))
                    Directory.CreateDirectory(basePath);

                File.WriteAllText(filePath, data);
                return data;
            }
            catch(Exception ex)
            {
                return null;
            }
        }

        private string GetAppPath()
        {
            return AppContext.BaseDirectory;
        }

        public FileInlineConverter(string path)
        {
            basePath = Path.Combine(GetAppPath(), "path");
        }

        public FileInlineConverter()
        {
            basePath = Path.Combine(GetAppPath(), "InlineCallbacks");
        }
    }
}

Last updated