mirror of
https://github.com/Bubuni-Team/telegram-bot.git
synced 2026-07-31 00:29:24 +03:00
Initial KV API concept
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kruzya.TelegramBot.Core.Data;
|
||||
using Kruzya.TelegramBot.Core.Extensions;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
public class CoreContextStorageService : IOptionStorageAdapter
|
||||
{
|
||||
private CoreContext _db;
|
||||
public CoreContextStorageService(CoreContext db)
|
||||
{
|
||||
_db = db;
|
||||
}
|
||||
|
||||
public async Task<byte[]?> LoadValueAsync(IOptionKey key)
|
||||
{
|
||||
var entity = await BuildQueryForKey(key).FirstOrDefaultAsync();
|
||||
|
||||
return entity?.Value;
|
||||
}
|
||||
|
||||
public async Task SaveValueAsync(IOptionKey key, byte[] value)
|
||||
{
|
||||
var entity = await BuildQueryForKey(key).FirstOrDefaultAsync();
|
||||
if (entity == null)
|
||||
{
|
||||
entity = await CreateEntity(key);
|
||||
}
|
||||
|
||||
entity.Value = value;
|
||||
_db.AddOrUpdate(entity);
|
||||
}
|
||||
|
||||
private IQueryable<BotUserValue> BuildQueryForKey(IOptionKey key)
|
||||
{
|
||||
var legacyUserId = key.UserId ?? 0;
|
||||
|
||||
return _db.UserValues.Where(e => e.BotUser.ChatId == key.ChatId && e.BotUser.UserId == legacyUserId
|
||||
&& e.Name == key.Identifier);
|
||||
}
|
||||
|
||||
private async Task<BotUserValue> CreateEntity(IOptionKey key)
|
||||
{
|
||||
var entity = _db.UserValues.Create()!;
|
||||
entity.BotUser = await _db.Users.FindOrCreate(key.ChatId, key.UserId ?? 0);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
/// <summary>
|
||||
/// Allows interact with option related with some chat.
|
||||
/// </summary>
|
||||
public interface IOptionItem<T>
|
||||
{
|
||||
public IOptionKey Key { get; }
|
||||
public T Value { get; set; }
|
||||
public bool IsChanged { get; }
|
||||
|
||||
public Task LoadAsync(IOptionStorageAdapter adapter);
|
||||
public Task SaveAsync(IOptionStorageAdapter adapter);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
/// <summary>
|
||||
/// Explains what
|
||||
/// </summary>
|
||||
public interface IOptionKey
|
||||
{
|
||||
/// <summary>
|
||||
/// The chat identifier where this key is related.
|
||||
/// </summary>
|
||||
public long ChatId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The Telegram user identifier. May be NULL if this is a simple option for all chat members.
|
||||
/// </summary>
|
||||
public long? UserId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The unique option identifier.
|
||||
/// </summary>
|
||||
public string Identifier { get; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
/// <summary>
|
||||
/// Describes what API should be implemented in Option Manager Service.
|
||||
/// </summary>
|
||||
public interface IOptionManagerService
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
/// <summary>
|
||||
/// Implements an interaction with storage for options.
|
||||
/// </summary>
|
||||
public interface IOptionStorageAdapter
|
||||
{
|
||||
/// <summary>
|
||||
/// Loads a saved value (if exists) from storage.
|
||||
/// </summary>
|
||||
/// <param name="key"></param>
|
||||
/// <returns></returns>
|
||||
public Task<byte[]?> LoadValueAsync(IOptionKey key);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a passed value to storage.
|
||||
/// </summary>
|
||||
/// <param name="key">The unique chat key</param>
|
||||
/// <param name="value">The serialized value for saving</param>
|
||||
/// <returns></returns>
|
||||
public Task SaveValueAsync(IOptionKey key, byte[] value);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
public class OptionItem<T> : IOptionItem<T>
|
||||
{
|
||||
public IOptionKey Key { get; }
|
||||
|
||||
public T Value
|
||||
{
|
||||
get => _value;
|
||||
|
||||
set
|
||||
{
|
||||
_value = value;
|
||||
_isChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsChanged => _isChanged;
|
||||
|
||||
private T _value;
|
||||
private bool _isChanged;
|
||||
|
||||
public OptionItem(IOptionKey key, T value)
|
||||
{
|
||||
Key = key;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public async Task LoadAsync(IOptionStorageAdapter adapter)
|
||||
{
|
||||
var savedValue = await adapter.LoadValueAsync(Key);
|
||||
if (savedValue == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// This property changed when we're loaded default value. Reset here.
|
||||
_isChanged = false;
|
||||
_value = JsonSerializer.Deserialize<T>(new ReadOnlySpan<byte>(savedValue));
|
||||
}
|
||||
|
||||
public async Task SaveAsync(IOptionStorageAdapter adapter)
|
||||
{
|
||||
var data = JsonSerializer.SerializeToUtf8Bytes(Value, new JsonSerializerOptions { WriteIndented = false,
|
||||
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull });
|
||||
await adapter.SaveValueAsync(Key, data);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace Kruzya.TelegramBot.Core.Option;
|
||||
|
||||
public class OptionKey : IOptionKey
|
||||
{
|
||||
public long ChatId { get; }
|
||||
public long? UserId { get; } = null;
|
||||
public string Identifier { get; }
|
||||
|
||||
public OptionKey(Chat chat, User user, string identifier) : this(chat.Id, user.Id, identifier)
|
||||
{}
|
||||
|
||||
public OptionKey(Chat chat, string identifier) : this(chat.Id, null, identifier)
|
||||
{}
|
||||
|
||||
public OptionKey(long chat, string identifier) : this(chat, null, identifier)
|
||||
{}
|
||||
|
||||
public OptionKey(long chat, long? user, string identifier)
|
||||
{
|
||||
ChatId = chat;
|
||||
UserId = user;
|
||||
Identifier = identifier;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user