fix: reformat using C# rules

This commit is contained in:
ZavaruKitsu
2022-10-08 19:26:34 +03:00
parent a731e2a8d0
commit 5ab15621a0
180 changed files with 13136 additions and 13081 deletions
+18 -15
View File
@@ -3,22 +3,25 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace TelegramBotBase.Base
{
public static class Async
{
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
namespace TelegramBotBase.Base;
public static IEnumerable<AsyncEventHandler<TEventArgs>> GetHandlers<TEventArgs>(
public static class Async
{
public delegate Task AsyncEventHandler<TEventArgs>(object sender, TEventArgs e) where TEventArgs : EventArgs;
public static IEnumerable<AsyncEventHandler<TEventArgs>> GetHandlers<TEventArgs>(
this AsyncEventHandler<TEventArgs> handler)
where TEventArgs : EventArgs
=> handler.GetInvocationList().Cast<AsyncEventHandler<TEventArgs>>();
public static Task InvokeAllAsync<TEventArgs>(this AsyncEventHandler<TEventArgs> handler, object sender, TEventArgs e)
where TEventArgs : EventArgs
=> Task.WhenAll(
handler.GetHandlers()
.Select(handleAsync => handleAsync(sender, e)));
{
return handler.GetInvocationList().Cast<AsyncEventHandler<TEventArgs>>();
}
}
public static Task InvokeAllAsync<TEventArgs>(this AsyncEventHandler<TEventArgs> handler, object sender,
TEventArgs e)
where TEventArgs : EventArgs
{
return Task.WhenAll(
handler.GetHandlers()
.Select(handleAsync => handleAsync(sender, e)));
}
}
+51 -55
View File
@@ -1,63 +1,59 @@
using System.Threading.Tasks;
using TelegramBotBase.Sessions;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
/// <summary>
/// Base class for controls
/// </summary>
public class ControlBase
{
public DeviceSession Device { get; set; }
public int Id { get; set; }
public string ControlId => "#c" + Id;
/// <summary>
/// Base class for controls
/// Defines if the control should be rendered and invoked with actions
/// </summary>
public class ControlBase
public bool Enabled { get; set; } = true;
/// <summary>
/// Get invoked when control will be added to a form and invoked.
/// </summary>
/// <returns></returns>
public virtual void Init()
{
public DeviceSession Device { get; set; }
public int Id { get; set; }
public string ControlId => "#c" + Id;
/// <summary>
/// Defines if the control should be rendered and invoked with actions
/// </summary>
public bool Enabled { get; set; } = true;
/// <summary>
/// Get invoked when control will be added to a form and invoked.
/// </summary>
/// <returns></returns>
public virtual void Init()
{
}
public virtual Task Load(MessageResult result)
{
return Task.CompletedTask;
}
public virtual Task Action(MessageResult result, string value = null)
{
return Task.CompletedTask;
}
public virtual Task Render(MessageResult result)
{
return Task.CompletedTask;
}
public virtual Task Hidden(bool formClose)
{
return Task.CompletedTask;
}
/// <summary>
/// Will be called on a cleanup.
/// </summary>
/// <returns></returns>
public virtual Task Cleanup()
{
return Task.CompletedTask;
}
}
}
public virtual Task Load(MessageResult result)
{
return Task.CompletedTask;
}
public virtual Task Action(MessageResult result, string value = null)
{
return Task.CompletedTask;
}
public virtual Task Render(MessageResult result)
{
return Task.CompletedTask;
}
public virtual Task Hidden(bool formClose)
{
return Task.CompletedTask;
}
/// <summary>
/// Will be called on a cleanup.
/// </summary>
/// <returns></returns>
public virtual Task Cleanup()
{
return Task.CompletedTask;
}
}
+158 -160
View File
@@ -7,166 +7,164 @@ using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
using Telegram.Bot.Types.InputFiles;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
/// <summary>
/// Returns a class to manage attachments within messages.
/// </summary>
public class DataResult : ResultBase
{
/// <summary>
/// Returns a class to manage attachments within messages.
/// </summary>
public class DataResult : ResultBase
public DataResult(UpdateResult update)
{
//public Telegram.Bot.Args.MessageEventArgs RawMessageData { get; set; }
public UpdateResult UpdateData { get; set; }
public Contact Contact => Message.Contact;
public Location Location => Message.Location;
public Document Document => Message.Document;
public Audio Audio => Message.Audio;
public Video Video => Message.Video;
public PhotoSize[] Photos => Message.Photo;
public MessageType Type => Message?.Type ?? MessageType.Unknown;
public override Message Message => UpdateData?.Message;
/// <summary>
/// Returns the FileId of the first reachable element.
/// </summary>
public string FileId =>
(Document?.FileId ??
Audio?.FileId ??
Video?.FileId ??
Photos.FirstOrDefault()?.FileId);
public DataResult(UpdateResult update)
{
UpdateData = update;
}
public async Task<InputOnlineFile> DownloadDocument()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Document.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, Document.FileName);
}
/// <summary>
/// Downloads a file and saves it to the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task DownloadDocument(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Document.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
/// <summary>
/// Downloads the document and returns an byte array.
/// </summary>
/// <returns></returns>
public async Task<byte[]> DownloadRawDocument()
{
var ms = new MemoryStream();
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
return ms.ToArray();
}
/// <summary>
/// Downloads a document and returns it as string. (txt,csv,etc) Default encoding ist UTF8.
/// </summary>
/// <returns></returns>
public async Task<string> DownloadRawTextDocument()
{
return await DownloadRawTextDocument(Encoding.UTF8);
}
/// <summary>
/// Downloads a document and returns it as string. (txt,csv,etc)
/// </summary>
/// <returns></returns>
public async Task<string> DownloadRawTextDocument(Encoding encoding)
{
var ms = new MemoryStream();
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
ms.Position = 0;
var sr = new StreamReader(ms, encoding);
return sr.ReadToEnd();
}
public async Task<InputOnlineFile> DownloadVideo()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Video.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Video.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadVideo(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Video.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
public async Task<InputOnlineFile> DownloadAudio()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Audio.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Audio.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadAudio(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Audio.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
public async Task<InputOnlineFile> DownloadPhoto(int index)
{
var photo = Photos[index];
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(photo.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadPhoto(int index, string path)
{
var photo = Photos[index];
var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
UpdateData = update;
}
}
//public Telegram.Bot.Args.MessageEventArgs RawMessageData { get; set; }
public UpdateResult UpdateData { get; set; }
public Contact Contact => Message.Contact;
public Location Location => Message.Location;
public Document Document => Message.Document;
public Audio Audio => Message.Audio;
public Video Video => Message.Video;
public PhotoSize[] Photos => Message.Photo;
public MessageType Type => Message?.Type ?? MessageType.Unknown;
public override Message Message => UpdateData?.Message;
/// <summary>
/// Returns the FileId of the first reachable element.
/// </summary>
public string FileId =>
Document?.FileId ??
Audio?.FileId ??
Video?.FileId ??
Photos.FirstOrDefault()?.FileId;
public async Task<InputOnlineFile> DownloadDocument()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Document.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId,
encryptedContent);
return new InputOnlineFile(encryptedContent, Document.FileName);
}
/// <summary>
/// Downloads a file and saves it to the given path.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public async Task DownloadDocument(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Document.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
/// <summary>
/// Downloads the document and returns an byte array.
/// </summary>
/// <returns></returns>
public async Task<byte[]> DownloadRawDocument()
{
var ms = new MemoryStream();
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
return ms.ToArray();
}
/// <summary>
/// Downloads a document and returns it as string. (txt,csv,etc) Default encoding ist UTF8.
/// </summary>
/// <returns></returns>
public async Task<string> DownloadRawTextDocument()
{
return await DownloadRawTextDocument(Encoding.UTF8);
}
/// <summary>
/// Downloads a document and returns it as string. (txt,csv,etc)
/// </summary>
/// <returns></returns>
public async Task<string> DownloadRawTextDocument(Encoding encoding)
{
var ms = new MemoryStream();
await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Document.FileId, ms);
ms.Position = 0;
var sr = new StreamReader(ms, encoding);
return sr.ReadToEnd();
}
public async Task<InputOnlineFile> DownloadVideo()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Video.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Video.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadVideo(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Video.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
public async Task<InputOnlineFile> DownloadAudio()
{
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(Audio.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(Audio.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadAudio(string path)
{
var file = await Device.Client.TelegramClient.GetFileAsync(Audio.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
public async Task<InputOnlineFile> DownloadPhoto(int index)
{
var photo = Photos[index];
var encryptedContent = new MemoryStream();
encryptedContent.SetLength(photo.FileSize.Value);
var file = await Device.Client.TelegramClient.GetInfoAndDownloadFileAsync(photo.FileId, encryptedContent);
return new InputOnlineFile(encryptedContent, "");
}
public async Task DownloadPhoto(int index, string path)
{
var photo = Photos[index];
var file = await Device.Client.TelegramClient.GetFileAsync(photo.FileId);
var fs = new FileStream(path, FileMode.Create);
await Device.Client.TelegramClient.DownloadFileAsync(file.FilePath, fs);
fs.Close();
fs.Dispose();
}
}
+424 -403
View File
@@ -9,421 +9,442 @@ using TelegramBotBase.Form.Navigation;
using TelegramBotBase.Sessions;
using static TelegramBotBase.Base.Async;
namespace TelegramBotBase.Form
namespace TelegramBotBase.Form;
/// <summary>
/// Base class for forms
/// </summary>
public class FormBase : IDisposable
{
/// <summary>
/// Base class for forms
/// </summary>
public class FormBase : IDisposable
private static readonly object EvInit = new();
private static readonly object EvOpened = new();
private static readonly object EvClosed = new();
public EventHandlerList Events = new();
public FormBase()
{
Controls = new List<ControlBase>();
}
public NavigationController NavigationController { get; set; }
public FormBase(MessageClient client) : this()
{
Client = client;
}
public DeviceSession Device { get; set; }
public NavigationController NavigationController { get; set; }
public MessageClient Client { get; set; }
public DeviceSession Device { get; set; }
/// <summary>
/// has this formular already been disposed ?
/// </summary>
public bool IsDisposed { get; set; }
public MessageClient Client { get; set; }
public List<ControlBase> Controls { get; set; }
/// <summary>
/// has this formular already been disposed ?
/// </summary>
public bool IsDisposed { get; set; }
public List<ControlBase> Controls { get; set; }
/// <summary>
/// Cleanup
/// </summary>
public void Dispose()
{
Client = null;
Device = null;
IsDisposed = true;
}
public EventHandlerList Events = new EventHandlerList();
private static readonly object EvInit = new object();
private static readonly object EvOpened = new object();
private static readonly object EvClosed = new object();
public FormBase()
public async Task OnInit(InitEventArgs e)
{
var handler = Events[EvInit]?.GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
if (handler == null)
{
Controls = new List<ControlBase>();
return;
}
public FormBase(MessageClient client) : this()
foreach (var h in handler)
{
this.Client = client;
}
public async Task OnInit(InitEventArgs e)
{
var handler = Events[EvInit]?.GetInvocationList().Cast<AsyncEventHandler<InitEventArgs>>();
if (handler == null)
return;
foreach (var h in handler)
{
await h.InvokeAllAsync(this, e);
}
}
///// <summary>
///// Will get called at the initialization (once per context)
///// </summary>
public event AsyncEventHandler<InitEventArgs> Init
{
add => Events.AddHandler(EvInit, value);
remove => Events.RemoveHandler(EvInit, value);
}
public async Task OnOpened(EventArgs e)
{
var handler = Events[EvOpened]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
if (handler == null)
return;
foreach (var h in handler)
{
await h.InvokeAllAsync(this, e);
}
}
/// <summary>
/// Gets invoked if gets navigated to this form
/// </summary>
/// <returns></returns>
public event AsyncEventHandler<EventArgs> Opened
{
add => Events.AddHandler(EvOpened, value);
remove => Events.RemoveHandler(EvOpened, value);
}
public async Task OnClosed(EventArgs e)
{
var handler = Events[EvClosed]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
if (handler == null)
return;
foreach (var h in handler)
{
await h.InvokeAllAsync(this, e);
}
}
/// <summary>
/// Form has been closed (left)
/// </summary>
/// <returns></returns>
public event AsyncEventHandler<EventArgs> Closed
{
add => Events.AddHandler(EvClosed, value);
remove => Events.RemoveHandler(EvClosed, value);
}
/// <summary>
/// Get invoked when a modal child from has been closed.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task ReturnFromModal(ModalDialog modal)
{
return Task.CompletedTask;
}
/// <summary>
/// Pre to form close, cleanup all controls
/// </summary>
/// <returns></returns>
public Task CloseControls()
{
foreach (var b in Controls)
{
b.Cleanup().Wait();
}
return Task.CompletedTask;
}
public virtual Task PreLoad(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if a message was sent or an action triggered
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task LoadControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData?.StartsWith("#c") ?? false)
{
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Load(message);
return;
}
}
foreach (var b in Controls)
{
if (!b.Enabled)
continue;
await b.Load(message);
}
}
/// <summary>
/// Gets invoked if the form gets loaded and on every message belongs to this context
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Load(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked, when a messages has been edited.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Edited(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if the user clicked a button.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task ActionControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData.StartsWith("#c"))
{
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Action(message, message.RawData.Split('_')[1]);
return;
}
}
foreach (var b in Controls)
{
if (!b.Enabled)
continue;
await b.Action(message);
if (message.Handled)
return;
}
}
/// <summary>
/// Gets invoked if the user has clicked a button.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Action(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if the user has sent some media (Photo, Audio, Video, Contact, Location, Document)
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task SentData(DataResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task RenderControls(MessageResult message)
{
foreach (var b in Controls)
{
if (!b.Enabled)
continue;
await b.Render(message);
}
}
/// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Render(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Navigates to a new form
/// </summary>
/// <param name="newForm"></param>
/// <returns></returns>
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
{
var ds = Device;
if (ds == null)
return;
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = Client;
newForm.Device = ds;
//Notify prior to close
foreach (var b in Controls)
{
if (!b.Enabled)
continue;
await b.Hidden(true);
}
CloseControls().Wait();
await OnClosed(EventArgs.Empty);
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(EventArgs.Empty);
}
/// <summary>
/// Opens this form modal, but don't closes the original ones
/// </summary>
/// <param name="newForm"></param>
/// <returns></returns>
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
{
var ds = Device;
if (ds == null)
return;
var parentForm = this;
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = parentForm.Client;
newForm.Device = ds;
newForm.ParentForm = parentForm;
newForm.Closed += async (s, en) =>
{
await CloseModal(newForm, parentForm);
};
foreach (var b in Controls)
{
if (!b.Enabled)
continue;
await b.Hidden(false);
}
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(EventArgs.Empty);
}
public Task CloseModal(ModalDialog modalForm, FormBase oldForm)
{
var ds = Device;
if (ds == null)
return Task.CompletedTask;
if (modalForm == null)
throw new Exception("No modal form");
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = oldForm;
return Task.CompletedTask;
}
/// <summary>
/// Adds a control to the formular and sets its ID and Device.
/// </summary>
/// <param name="control"></param>
public void AddControl(ControlBase control)
{
//Duplicate check
if (Controls.Contains(control))
throw new ArgumentException("Control has been already added.");
control.Id = Controls.Count + 1;
control.Device = Device;
Controls.Add(control);
control.Init();
}
/// <summary>
/// Removes control from the formular and runs a cleanup on it.
/// </summary>
/// <param name="control"></param>
public void RemoveControl(ControlBase control)
{
if (!Controls.Contains(control))
return;
control.Cleanup().Wait();
Controls.Remove(control);
}
/// <summary>
/// Removes all controls.
/// </summary>
public void RemoveAllControls()
{
foreach(var c in Controls)
{
c.Cleanup().Wait();
Controls.Remove(c);
}
}
/// <summary>
/// Cleanup
/// </summary>
public void Dispose()
{
Client = null;
Device = null;
IsDisposed = true;
await h.InvokeAllAsync(this, e);
}
}
}
///// <summary>
///// Will get called at the initialization (once per context)
///// </summary>
public event AsyncEventHandler<InitEventArgs> Init
{
add => Events.AddHandler(EvInit, value);
remove => Events.RemoveHandler(EvInit, value);
}
public async Task OnOpened(EventArgs e)
{
var handler = Events[EvOpened]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
if (handler == null)
{
return;
}
foreach (var h in handler)
{
await h.InvokeAllAsync(this, e);
}
}
/// <summary>
/// Gets invoked if gets navigated to this form
/// </summary>
/// <returns></returns>
public event AsyncEventHandler<EventArgs> Opened
{
add => Events.AddHandler(EvOpened, value);
remove => Events.RemoveHandler(EvOpened, value);
}
public async Task OnClosed(EventArgs e)
{
var handler = Events[EvClosed]?.GetInvocationList().Cast<AsyncEventHandler<EventArgs>>();
if (handler == null)
{
return;
}
foreach (var h in handler)
{
await h.InvokeAllAsync(this, e);
}
}
/// <summary>
/// Form has been closed (left)
/// </summary>
/// <returns></returns>
public event AsyncEventHandler<EventArgs> Closed
{
add => Events.AddHandler(EvClosed, value);
remove => Events.RemoveHandler(EvClosed, value);
}
/// <summary>
/// Get invoked when a modal child from has been closed.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task ReturnFromModal(ModalDialog modal)
{
return Task.CompletedTask;
}
/// <summary>
/// Pre to form close, cleanup all controls
/// </summary>
/// <returns></returns>
public Task CloseControls()
{
foreach (var b in Controls)
{
b.Cleanup().Wait();
}
return Task.CompletedTask;
}
public virtual Task PreLoad(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if a message was sent or an action triggered
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task LoadControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData?.StartsWith("#c") ?? false)
{
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Load(message);
return;
}
}
foreach (var b in Controls)
{
if (!b.Enabled)
{
continue;
}
await b.Load(message);
}
}
/// <summary>
/// Gets invoked if the form gets loaded and on every message belongs to this context
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Load(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked, when a messages has been edited.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Edited(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if the user clicked a button.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task ActionControls(MessageResult message)
{
//Looking for the control by id, if not listened, raise event for all
if (message.RawData.StartsWith("#c"))
{
var c = Controls.FirstOrDefault(a => a.ControlId == message.RawData.Split('_')[0]);
if (c != null)
{
await c.Action(message, message.RawData.Split('_')[1]);
return;
}
}
foreach (var b in Controls)
{
if (!b.Enabled)
{
continue;
}
await b.Action(message);
if (message.Handled)
{
return;
}
}
}
/// <summary>
/// Gets invoked if the user has clicked a button.
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Action(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked if the user has sent some media (Photo, Audio, Video, Contact, Location, Document)
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task SentData(DataResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual async Task RenderControls(MessageResult message)
{
foreach (var b in Controls)
{
if (!b.Enabled)
{
continue;
}
await b.Render(message);
}
}
/// <summary>
/// Gets invoked at the end of the cycle to "Render" text, images, buttons, etc...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public virtual Task Render(MessageResult message)
{
return Task.CompletedTask;
}
/// <summary>
/// Navigates to a new form
/// </summary>
/// <param name="newForm"></param>
/// <returns></returns>
public virtual async Task NavigateTo(FormBase newForm, params object[] args)
{
var ds = Device;
if (ds == null)
{
return;
}
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = Client;
newForm.Device = ds;
//Notify prior to close
foreach (var b in Controls)
{
if (!b.Enabled)
{
continue;
}
await b.Hidden(true);
}
CloseControls().Wait();
await OnClosed(EventArgs.Empty);
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(EventArgs.Empty);
}
/// <summary>
/// Opens this form modal, but don't closes the original ones
/// </summary>
/// <param name="newForm"></param>
/// <returns></returns>
public virtual async Task OpenModal(ModalDialog newForm, params object[] args)
{
var ds = Device;
if (ds == null)
{
return;
}
var parentForm = this;
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = newForm;
newForm.Client = parentForm.Client;
newForm.Device = ds;
newForm.ParentForm = parentForm;
newForm.Closed += async (s, en) => { await CloseModal(newForm, parentForm); };
foreach (var b in Controls)
{
if (!b.Enabled)
{
continue;
}
await b.Hidden(false);
}
await newForm.OnInit(new InitEventArgs(args));
await newForm.OnOpened(EventArgs.Empty);
}
public Task CloseModal(ModalDialog modalForm, FormBase oldForm)
{
var ds = Device;
if (ds == null)
{
return Task.CompletedTask;
}
if (modalForm == null)
{
throw new Exception("No modal form");
}
ds.FormSwitched = true;
ds.PreviousForm = ds.ActiveForm;
ds.ActiveForm = oldForm;
return Task.CompletedTask;
}
/// <summary>
/// Adds a control to the formular and sets its ID and Device.
/// </summary>
/// <param name="control"></param>
public void AddControl(ControlBase control)
{
//Duplicate check
if (Controls.Contains(control))
{
throw new ArgumentException("Control has been already added.");
}
control.Id = Controls.Count + 1;
control.Device = Device;
Controls.Add(control);
control.Init();
}
/// <summary>
/// Removes control from the formular and runs a cleanup on it.
/// </summary>
/// <param name="control"></param>
public void RemoveControl(ControlBase control)
{
if (!Controls.Contains(control))
{
return;
}
control.Cleanup().Wait();
Controls.Remove(control);
}
/// <summary>
/// Removes all controls.
/// </summary>
public void RemoveAllControls()
{
foreach (var c in Controls)
{
c.Cleanup().Wait();
Controls.Remove(c);
}
}
}
+179 -186
View File
@@ -10,193 +10,186 @@ using Telegram.Bot.Exceptions;
using Telegram.Bot.Extensions.Polling;
using Telegram.Bot.Types;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
/// <summary>
/// Base class for message handling
/// </summary>
public class MessageClient
{
/// <summary>
/// Base class for message handling
/// </summary>
public class MessageClient
private static readonly object EvOnMessageLoop = new();
private static object __evOnMessage = new();
private static object __evOnMessageEdit = new();
private static object __evCallbackQuery = new();
private CancellationTokenSource _cancellationTokenSource;
public MessageClient(string apiKey)
{
ApiKey = apiKey;
TelegramClient = new TelegramBotClient(apiKey);
public string ApiKey { get; set; }
public ITelegramBotClient TelegramClient { get; set; }
private EventHandlerList Events { get; set; } = new EventHandlerList();
private static readonly object EvOnMessageLoop = new object();
private static object __evOnMessage = new object();
private static object __evOnMessageEdit = new object();
private static object __evCallbackQuery = new object();
private CancellationTokenSource _cancellationTokenSource;
public MessageClient(string apiKey)
{
this.ApiKey = apiKey;
TelegramClient = new TelegramBotClient(apiKey);
Prepare();
}
public MessageClient(string apiKey, HttpClient proxy)
{
this.ApiKey = apiKey;
TelegramClient = new TelegramBotClient(apiKey, proxy);
Prepare();
}
public MessageClient(string apiKey, Uri proxyUrl, NetworkCredential credential = null)
{
this.ApiKey = apiKey;
var proxy = new WebProxy(proxyUrl)
{
Credentials = credential
};
var httpClient = new HttpClient(
new HttpClientHandler { Proxy = proxy, UseProxy = true }
);
TelegramClient = new TelegramBotClient(apiKey, httpClient);
Prepare();
}
/// <summary>
/// Initializes the client with a proxy
/// </summary>
/// <param name="apiKey"></param>
/// <param name="proxyHost">i.e. 127.0.0.1</param>
/// <param name="proxyPort">i.e. 10000</param>
public MessageClient(string apiKey, string proxyHost, int proxyPort)
{
this.ApiKey = apiKey;
var proxy = new WebProxy(proxyHost, proxyPort);
var httpClient = new HttpClient(
new HttpClientHandler { Proxy = proxy, UseProxy = true }
);
TelegramClient = new TelegramBotClient(apiKey, httpClient);
Prepare();
}
public MessageClient(string apiKey, TelegramBotClient client)
{
this.ApiKey = apiKey;
TelegramClient = client;
Prepare();
}
public void Prepare()
{
TelegramClient.Timeout = new TimeSpan(0, 0, 30);
}
public void StartReceiving()
{
_cancellationTokenSource = new CancellationTokenSource();
var receiverOptions = new ReceiverOptions();
TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions, _cancellationTokenSource.Token);
}
public void StopReceiving()
{
_cancellationTokenSource.Cancel();
}
public Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
OnMessageLoop(new UpdateResult(update, null));
return Task.CompletedTask;
}
public Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception, CancellationToken cancellationToken)
{
if (exception is ApiRequestException exApi)
{
Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}");
}
else
{
Console.WriteLine(exception.ToString());
}
return Task.CompletedTask;
}
/// <summary>
/// This will return the current list of bot commands.
/// </summary>
/// <returns></returns>
public async Task<BotCommand[]> GetBotCommands(BotCommandScope scope = null, string languageCode = null)
{
return await TelegramClient.GetMyCommandsAsync(scope, languageCode);
}
/// <summary>
/// This will set your bot commands to the given list.
/// </summary>
/// <param name="botcommands"></param>
/// <returns></returns>
public async Task SetBotCommands(List<BotCommand> botcommands, BotCommandScope scope = null, string languageCode = null)
{
await TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode);
}
/// <summary>
/// This will delete the current list of bot commands.
/// </summary>
/// <returns></returns>
public async Task DeleteBotCommands(BotCommandScope scope = null, string languageCode = null)
{
await TelegramClient.DeleteMyCommandsAsync(scope, languageCode);
}
#region "Events"
public event Async.AsyncEventHandler<UpdateResult> MessageLoop
{
add => Events.AddHandler(EvOnMessageLoop, value);
remove => Events.RemoveHandler(EvOnMessageLoop, value);
}
public void OnMessageLoop(UpdateResult update)
{
(Events[EvOnMessageLoop] as Async.AsyncEventHandler<UpdateResult>)?.Invoke(this, update);
}
#endregion
Prepare();
}
}
public MessageClient(string apiKey, HttpClient proxy)
{
ApiKey = apiKey;
TelegramClient = new TelegramBotClient(apiKey, proxy);
Prepare();
}
public MessageClient(string apiKey, Uri proxyUrl, NetworkCredential credential = null)
{
ApiKey = apiKey;
var proxy = new WebProxy(proxyUrl)
{
Credentials = credential
};
var httpClient = new HttpClient(
new HttpClientHandler { Proxy = proxy, UseProxy = true }
);
TelegramClient = new TelegramBotClient(apiKey, httpClient);
Prepare();
}
/// <summary>
/// Initializes the client with a proxy
/// </summary>
/// <param name="apiKey"></param>
/// <param name="proxyHost">i.e. 127.0.0.1</param>
/// <param name="proxyPort">i.e. 10000</param>
public MessageClient(string apiKey, string proxyHost, int proxyPort)
{
ApiKey = apiKey;
var proxy = new WebProxy(proxyHost, proxyPort);
var httpClient = new HttpClient(
new HttpClientHandler { Proxy = proxy, UseProxy = true }
);
TelegramClient = new TelegramBotClient(apiKey, httpClient);
Prepare();
}
public MessageClient(string apiKey, TelegramBotClient client)
{
ApiKey = apiKey;
TelegramClient = client;
Prepare();
}
public string ApiKey { get; set; }
public ITelegramBotClient TelegramClient { get; set; }
private EventHandlerList Events { get; } = new();
public void Prepare()
{
TelegramClient.Timeout = new TimeSpan(0, 0, 30);
}
public void StartReceiving()
{
_cancellationTokenSource = new CancellationTokenSource();
var receiverOptions = new ReceiverOptions();
TelegramClient.StartReceiving(HandleUpdateAsync, HandleErrorAsync, receiverOptions,
_cancellationTokenSource.Token);
}
public void StopReceiving()
{
_cancellationTokenSource.Cancel();
}
public Task HandleUpdateAsync(ITelegramBotClient botClient, Update update, CancellationToken cancellationToken)
{
OnMessageLoop(new UpdateResult(update, null));
return Task.CompletedTask;
}
public Task HandleErrorAsync(ITelegramBotClient botClient, Exception exception,
CancellationToken cancellationToken)
{
if (exception is ApiRequestException exApi)
{
Console.WriteLine($"Telegram API Error:\n[{exApi.ErrorCode}]\n{exApi.Message}");
}
else
{
Console.WriteLine(exception.ToString());
}
return Task.CompletedTask;
}
/// <summary>
/// This will return the current list of bot commands.
/// </summary>
/// <returns></returns>
public async Task<BotCommand[]> GetBotCommands(BotCommandScope scope = null, string languageCode = null)
{
return await TelegramClient.GetMyCommandsAsync(scope, languageCode);
}
/// <summary>
/// This will set your bot commands to the given list.
/// </summary>
/// <param name="botcommands"></param>
/// <returns></returns>
public async Task SetBotCommands(List<BotCommand> botcommands, BotCommandScope scope = null,
string languageCode = null)
{
await TelegramClient.SetMyCommandsAsync(botcommands, scope, languageCode);
}
/// <summary>
/// This will delete the current list of bot commands.
/// </summary>
/// <returns></returns>
public async Task DeleteBotCommands(BotCommandScope scope = null, string languageCode = null)
{
await TelegramClient.DeleteMyCommandsAsync(scope, languageCode);
}
#region "Events"
public event Async.AsyncEventHandler<UpdateResult> MessageLoop
{
add => Events.AddHandler(EvOnMessageLoop, value);
remove => Events.RemoveHandler(EvOnMessageLoop, value);
}
public void OnMessageLoop(UpdateResult update)
{
(Events[EvOnMessageLoop] as Async.AsyncEventHandler<UpdateResult>)?.Invoke(this, update);
}
#endregion
}
+100 -102
View File
@@ -5,136 +5,134 @@ using Newtonsoft.Json;
using Telegram.Bot.Types;
using Telegram.Bot.Types.Enums;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
public class MessageResult : ResultBase
{
public class MessageResult : ResultBase
internal MessageResult()
{
}
public Update UpdateData { get; set; }
public MessageResult(Update update)
{
UpdateData = update;
}
/// <summary>
/// Returns the Device/ChatId
/// </summary>
public override long DeviceId =>
UpdateData?.Message?.Chat?.Id
?? UpdateData?.EditedMessage?.Chat.Id
?? UpdateData?.CallbackQuery.Message?.Chat.Id
?? Device?.DeviceId
?? 0;
public Update UpdateData { get; set; }
/// <summary>
/// The message id
/// </summary>
public new int MessageId =>
UpdateData?.Message?.MessageId
?? Message?.MessageId
?? UpdateData?.CallbackQuery?.Message?.MessageId
?? 0;
/// <summary>
/// Returns the Device/ChatId
/// </summary>
public override long DeviceId =>
UpdateData?.Message?.Chat?.Id
?? UpdateData?.EditedMessage?.Chat.Id
?? UpdateData?.CallbackQuery.Message?.Chat.Id
?? Device?.DeviceId
?? 0;
public string Command => UpdateData?.Message?.Text ?? "";
/// <summary>
/// The message id
/// </summary>
public new int MessageId =>
UpdateData?.Message?.MessageId
?? Message?.MessageId
?? UpdateData?.CallbackQuery?.Message?.MessageId
?? 0;
public string MessageText => UpdateData?.Message?.Text ?? "";
public string Command => UpdateData?.Message?.Text ?? "";
public MessageType MessageType => Message?.Type ?? MessageType.Unknown;
public string MessageText => UpdateData?.Message?.Text ?? "";
/// <summary>
/// Is this an action ? (i.e. button click)
/// </summary>
public bool IsAction => (UpdateData.CallbackQuery != null);
public MessageType MessageType => Message?.Type ?? MessageType.Unknown;
/// <summary>
/// Is this a command ? Starts with a slash '/' and a command
/// </summary>
public bool IsBotCommand => (MessageText.StartsWith("/"));
/// <summary>
/// Is this an action ? (i.e. button click)
/// </summary>
public bool IsAction => UpdateData.CallbackQuery != null;
/// <summary>
/// Returns a List of all parameters which has been sent with the command itself (i.e. /start 123 456 789 => 123,456,789)
/// </summary>
public List<string> BotCommandParameters
/// <summary>
/// Is this a command ? Starts with a slash '/' and a command
/// </summary>
public bool IsBotCommand => MessageText.StartsWith("/");
/// <summary>
/// Returns a List of all parameters which has been sent with the command itself (i.e. /start 123 456 789 =>
/// 123,456,789)
/// </summary>
public List<string> BotCommandParameters
{
get
{
get
if (!IsBotCommand)
{
if (!IsBotCommand)
return new List<string>();
//Split by empty space and skip first entry (command itself), return as list
return MessageText.Split(' ').Skip(1).ToList();
}
}
/// <summary>
/// Returns just the command (i.e. /start 1 2 3 => /start)
/// </summary>
public string BotCommand
{
get
{
if (!IsBotCommand)
return null;
return MessageText.Split(' ')[0];
}
}
/// <summary>
/// Returns if this message will be used on the first form or not.
/// </summary>
public bool IsFirstHandler { get; set; } = true;
public bool Handled { get; set; } = false;
public string RawData => UpdateData?.CallbackQuery?.Data;
public T GetData<T>()
where T : class
{
T cd = null;
try
{
cd = JsonConvert.DeserializeObject<T>(RawData);
return cd;
}
catch
{
return new List<string>();
}
return null;
//Split by empty space and skip first entry (command itself), return as list
return MessageText.Split(' ').Skip(1).ToList();
}
}
/// <summary>
/// Confirm incomming action (i.e. Button click)
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task ConfirmAction(string message = "", bool showAlert = false, string urlToOpen = null)
/// <summary>
/// Returns just the command (i.e. /start 1 2 3 => /start)
/// </summary>
public string BotCommand
{
get
{
await Device.ConfirmAction(UpdateData.CallbackQuery.Id, message, showAlert, urlToOpen);
}
public override async Task DeleteMessage()
{
try
if (!IsBotCommand)
{
await base.DeleteMessage(MessageId);
return null;
}
catch
{
}
return MessageText.Split(' ')[0];
}
}
internal MessageResult()
/// <summary>
/// Returns if this message will be used on the first form or not.
/// </summary>
public bool IsFirstHandler { get; set; } = true;
public bool Handled { get; set; } = false;
public string RawData => UpdateData?.CallbackQuery?.Data;
public T GetData<T>()
where T : class
{
T cd = null;
try
{
cd = JsonConvert.DeserializeObject<T>(RawData);
return cd;
}
public MessageResult(Update update)
catch
{
UpdateData = update;
}
return null;
}
/// <summary>
/// Confirm incomming action (i.e. Button click)
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public async Task ConfirmAction(string message = "", bool showAlert = false, string urlToOpen = null)
{
await Device.ConfirmAction(UpdateData.CallbackQuery.Id, message, showAlert, urlToOpen);
}
public override async Task DeleteMessage()
{
try
{
await base.DeleteMessage(MessageId);
}
catch
{
}
}
}
+36 -42
View File
@@ -4,48 +4,42 @@ using Telegram.Bot;
using Telegram.Bot.Types;
using TelegramBotBase.Sessions;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
public class ResultBase : EventArgs
{
public class ResultBase : EventArgs
public DeviceSession Device { get; set; }
public virtual long DeviceId { get; set; }
public int MessageId => Message.MessageId;
public virtual Message Message { get; set; }
/// <summary>
/// Deletes the current message
/// </summary>
/// <param name="messageId"></param>
/// <returns></returns>
public virtual async Task DeleteMessage()
{
public DeviceSession Device
{
get;
set;
}
public virtual long DeviceId { get; set; }
public int MessageId => Message.MessageId;
public virtual Message Message { get; set; }
/// <summary>
/// Deletes the current message
/// </summary>
/// <param name="messageId"></param>
/// <returns></returns>
public virtual async Task DeleteMessage()
{
await DeleteMessage(MessageId);
}
/// <summary>
///Deletes the current message or the given one.
/// </summary>
/// <param name="messageId"></param>
/// <returns></returns>
public virtual async Task DeleteMessage(int messageId = -1)
{
try
{
await Device.Client.TelegramClient.DeleteMessageAsync(DeviceId, (messageId == -1 ? MessageId : messageId));
}
catch
{
}
}
await DeleteMessage(MessageId);
}
}
/// <summary>
/// Deletes the current message or the given one.
/// </summary>
/// <param name="messageId"></param>
/// <returns></returns>
public virtual async Task DeleteMessage(int messageId = -1)
{
try
{
await Device.Client.TelegramClient.DeleteMessageAsync(DeviceId,
messageId == -1 ? MessageId : messageId);
}
catch
{
}
}
}
+18 -26
View File
@@ -1,32 +1,24 @@
using System.Collections.Generic;
using System.Linq;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
public class StateContainer
{
public class StateContainer
public StateContainer()
{
public List<StateEntry> States { get; set; }
public List<long> ChatIds
{
get
{
return States.Where(a => a.DeviceId > 0).Select(a => a.DeviceId).ToList();
}
}
public List<long> GroupIds
{
get
{
return States.Where(a => a.DeviceId < 0).Select(a => a.DeviceId).ToList();
}
}
public StateContainer()
{
States = new List<StateEntry>();
}
States = new List<StateEntry>();
}
}
public List<StateEntry> States { get; set; }
public List<long> ChatIds
{
get { return States.Where(a => a.DeviceId > 0).Select(a => a.DeviceId).ToList(); }
}
public List<long> GroupIds
{
get { return States.Where(a => a.DeviceId < 0).Select(a => a.DeviceId).ToList(); }
}
}
+32 -35
View File
@@ -1,41 +1,38 @@
using System.Collections.Generic;
using System.Diagnostics;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
public class StateEntry
{
[DebuggerDisplay("Device: {DeviceId}, {FormUri}")]
public class StateEntry
public StateEntry()
{
/// <summary>
/// Contains the DeviceId of the entry.
/// </summary>
public long DeviceId { get; set; }
/// <summary>
/// Contains the Username (on privat chats) or Group title on groups/channels.
/// </summary>
public string ChatTitle { get; set; }
/// <summary>
/// Contains additional values to save.
/// </summary>
public Dictionary<string, object> Values { get; set; }
/// <summary>
/// Contains the full qualified namespace of the form to used for reload it via reflection.
/// </summary>
public string FormUri {get;set;}
/// <summary>
/// Contains the assembly, where to find that form.
/// </summary>
public string QualifiedName { get; set; }
public StateEntry()
{
Values = new Dictionary<string, object>();
}
Values = new Dictionary<string, object>();
}
}
/// <summary>
/// Contains the DeviceId of the entry.
/// </summary>
public long DeviceId { get; set; }
/// <summary>
/// Contains the Username (on privat chats) or Group title on groups/channels.
/// </summary>
public string ChatTitle { get; set; }
/// <summary>
/// Contains additional values to save.
/// </summary>
public Dictionary<string, object> Values { get; set; }
/// <summary>
/// Contains the full qualified namespace of the form to used for reload it via reflection.
/// </summary>
public string FormUri { get; set; }
/// <summary>
/// Contains the assembly, where to find that form.
/// </summary>
public string QualifiedName { get; set; }
}
+24 -28
View File
@@ -1,35 +1,31 @@
using Telegram.Bot.Types;
using TelegramBotBase.Sessions;
namespace TelegramBotBase.Base
namespace TelegramBotBase.Base;
public class UpdateResult : ResultBase
{
public class UpdateResult : ResultBase
public UpdateResult(Update rawData, DeviceSession device)
{
public UpdateResult(Update rawData, DeviceSession device)
{
RawData = rawData;
Device = device;
}
/// <summary>
/// Returns the Device/ChatId
/// </summary>
public override long DeviceId =>
RawData?.Message?.Chat?.Id
?? RawData?.CallbackQuery?.Message?.Chat?.Id
?? Device?.DeviceId
?? 0;
public Update RawData { get; set; }
public override Message Message =>
RawData?.Message
?? RawData?.EditedMessage
?? RawData?.ChannelPost
?? RawData?.EditedChannelPost
?? RawData?.CallbackQuery?.Message;
RawData = rawData;
Device = device;
}
}
/// <summary>
/// Returns the Device/ChatId
/// </summary>
public override long DeviceId =>
RawData?.Message?.Chat?.Id
?? RawData?.CallbackQuery?.Message?.Chat?.Id
?? Device?.DeviceId
?? 0;
public Update RawData { get; set; }
public override Message Message =>
RawData?.Message
?? RawData?.EditedMessage
?? RawData?.ChannelPost
?? RawData?.EditedChannelPost
?? RawData?.CallbackQuery?.Message;
}