Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added attachments api (without uploading) with stickers and dotnet 9 support #141

Merged
2 changes: 1 addition & 1 deletion .github/workflows/BuildingAndTesting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Preparing
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restoring
run: dotnet restore
- name: Building
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/PublishingAndDeploying.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- name: Preparing
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
dotnet-version: 9.0.x
- name: Restoring
run: dotnet restore
- name: Preparing
Expand Down
4 changes: 2 additions & 2 deletions Common.Build.props
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project>
<PropertyGroup Label="Assembly">
<Version>1.8.0</Version>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
<IsAotCompatible>true</IsAotCompatible>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>

<PropertyGroup Label="Language">
<RootNamespace>Talkie</RootNamespace>
<LangVersion>12</LangVersion>
<LangVersion>13</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
12 changes: 6 additions & 6 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<Project>
<ItemGroup Label="Dependencies">
<PackageVersion Include="BenchmarkDotNet" Version="0.14.0" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog" Version="4.0.1" />
<PackageVersion Include="Microsoft.Extensions.Hosting" Version="8.0.1" />
<PackageVersion Include="Serilog" Version="4.0.2" />
<PackageVersion Include="Serilog.Extensions.Hosting" Version="8.0.0" />
<PackageVersion Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
<PackageVersion Include="NUnit" Version="4.1.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="NUnit" Version="4.2.2" />
<PackageVersion Include="NUnit3TestAdapter" Version="4.6.0" />
<PackageVersion Include="NUnit.Analyzers" Version="4.2.0" />
<PackageVersion Include="NUnit.Analyzers" Version="4.3.0" />
<PackageVersion Include="coverlet.collector" Version="6.0.2" />
</ItemGroup>
</Project>
</Project>
4 changes: 2 additions & 2 deletions Examples.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
<Import Project="Common.Build.props" />

<PropertyGroup Label="Assembly">
<OutputType>Exe</OutputType>
<PublishAot>True</PublishAot>
<OutputType>exe</OutputType>
<PublishAot>true</PublishAot>
<OptimizationPreference>speed</OptimizationPreference>
<TrimMode>full</TrimMode>
<ServerGarbageCollection>true</ServerGarbageCollection>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Talkie.Flows;
using Talkie.Handlers;
using Talkie.Models.Messages;
using Talkie.Models.Messages.Attachments;
using Talkie.Pipelines.Handling;
using Talkie.Pipelines.Intercepting;
using Talkie.Signals;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,23 @@ public sealed class StartSubscriber : IBehaviorsSubscriber
{
public void Subscribe(ISignalFlow flow, IRegisterOnlyDisposableScope disposables, CancellationToken cancellationToken)
{
flow.Subscribe<MessagePublishedSignal>(static signals => signals
flow.Subscribe<MessagePublishedSignal>(signals => signals
.SkipSelfPublish()
.Where(signal => signal
.Message
.GetText()
.TrimStart()
.StartsWith("/start", StringComparison.InvariantCultureIgnoreCase))
.HandleAsync((context, cancellationToken) => context
.HandleAsync((context, cancellation) => context
.ToMessageController()
.PublishMessageAsync(message => message
.SetReply(context.GetMessage())
.SetContent(content => content
.AddText(nameof(Talkie), BoldTextStyle.FromTextRange)
.AddText(" is a library for building chatbots in .NET.", ItalicTextStyle.FromTextRange)),
cancellationToken)
cancellation)
.AsValueTask())
.HandleAsync((context, cancellationToken) => context
.HandleAsync((context, cancellation) => context
.ToMessageController()
.PublishMessageAsync(message => message
.SetReply(context.GetMessage())
Expand All @@ -44,7 +44,7 @@ public void Subscribe(ISignalFlow flow, IRegisterOnlyDisposableScope disposables
.AddText(GetProfileDisplayName(context
.GetMessage()
.PublisherProfile), MonospaceTextStyle.FromTextRange)),
cancellationToken)
cancellation)
.AsValueTask()))
.UnsubscribeWith(disposables);
}
Expand Down
41 changes: 41 additions & 0 deletions Falko.Talkie.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<Solution>
<Folder Name="/Assets/">
<File Path="Common.Build.props" />
<File Path="nuget.config" />
<File Path=".gitignore" />
<File Path=".gitattributes" />
<File Path="ReadMe.md" />
<File Path="Benchmarks.Build.props" />
<File Path="Examples.Build.props" />
<File Path="Logo512.png" />
<File Path="Sources.Build.props" />
<File Path="Tests.Build.props" />
<File Path="Directory.Packages.props" />
<File Path="Icon64.png" />
<File Path="License.md" />
</Folder>

<Folder Name="/Benchmarks/">
<Project Path="Benchmarks\Falko.Talkie.Benchmarks.Sequences\Falko.Talkie.Benchmarks.Sequences.csproj" Type="Classic C#" />
</Folder>

<Folder Name="/Examples/">
<Project Path="Examples\Falko.Talkie.Examples.Microsoft.Hosting\Falko.Talkie.Examples.Microsoft.Hosting.csproj" Type="Classic C#" />
</Folder>

<Folder Name="/Sources/">
<Project Path="Sources\Falko.Talkie.Bridges.Telegram\Falko.Talkie.Bridges.Telegram.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Core\Falko.Talkie.Core.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Microsoft.Hosting\Falko.Talkie.Microsoft.Hosting.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Platforms.Telegram\Falko.Talkie.Platforms.Telegram.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Platforms\Falko.Talkie.Platforms.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Signals.Adapters\Falko.Talkie.Signals.Adapters.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Signals.Connections\Falko.Talkie.Signals.Connections.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Signals.Extensions\Falko.Talkie.Signals.Extensions.csproj" Type="Classic C#" />
<Project Path="Sources\Falko.Talkie.Signals\Falko.Talkie.Signals.csproj" Type="Classic C#" />
</Folder>

<Folder Name="/Tests/">
<Project Path="Tests\Falko.Talkie.Tests.Sequences\Falko.Talkie.Tests.Sequences.csproj" Type="Classic C#" />
</Folder>
</Solution>
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,7 @@ internal Task SendAsync<TRequest>(string methodName, TRequest request,

internal Task SendAsync(string methodName,
CancellationToken cancellationToken = default);

Task<Stream> DownloadAsync(string file,
CancellationToken cancellationToken = default);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ public sealed class TelegramBotApiClient : ITelegramBotApiClient

private readonly HttpClient _client;

private readonly bool _useGzipCompression;
private readonly ServerConfiguration _serverConfiguration;

private readonly TimeSpan _defaultRetryDelay;
private readonly ClientConfiguration _clientConfiguration;

private readonly CancellationTokenSource _globalCancellationTokenSource = new();

Expand All @@ -31,11 +31,10 @@ public TelegramBotApiClient(ServerConfiguration serverConfiguration,
{
ArgumentNullException.ThrowIfNull(serverConfiguration);

clientConfiguration ??= new ClientConfiguration();
_serverConfiguration = serverConfiguration;
_clientConfiguration = clientConfiguration ?? new ClientConfiguration();

_useGzipCompression = clientConfiguration.UseGzipCompression;
_defaultRetryDelay = serverConfiguration.DefaultRetryDelay;
_client = BuildHttpClient(serverConfiguration, clientConfiguration);
_client = BuildHttpClient(serverConfiguration, _clientConfiguration);
}

async Task<TResult> ITelegramBotApiClient.SendAsync<TResult, TRequest>(string methodName, TRequest request,
Expand Down Expand Up @@ -88,6 +87,79 @@ Task ITelegramBotApiClient.SendAsync(string methodName,
return SendRepeatableRequestAsync<object, object>(methodName, null, scopedCancellationTokenSource.Token);
}

public async Task<Stream> DownloadAsync(string file, CancellationToken cancellationToken)
{
ArgumentException.ThrowIfNullOrWhiteSpace(file);

while (true)
{
try
{
return await DownloadCoreAsync(file, cancellationToken);
}
catch (TelegramBotApiRequestException exception)
{
if (exception.StatusCode is null or not HttpStatusCode.TooManyRequests)
{
throw;
}

await WaitRetryDelayAsync(exception, cancellationToken);
}
}
}

private async Task<Stream> DownloadCoreAsync(string file,
CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();

try
{
var httpRequest = new HttpRequestMessage(HttpMethod.Get, file)
{
RequestUri = new Uri($"https://{_serverConfiguration.Domain}/file/bot{_serverConfiguration.Token}/{file}")
};

Console.WriteLine(httpRequest.RequestUri);

var httpResponse = await _client.SendAsync(httpRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

if (httpResponse.IsSuccessStatusCode)
{
return await httpResponse.Content.ReadAsStreamAsync(cancellationToken);
}

var jsonResponse = await httpResponse.Content.ReadAsStringAsync(cancellationToken);

if (JsonSerializer.Deserialize(jsonResponse, typeof(Response), ModelsJsonSerializerContext.Default)
is not Response response)
{
throw new TelegramBotApiRequestException(this, "download",
description: "Failed to deserialize response");
}

throw new TelegramBotApiRequestException(this, "download",
statusCode: (HttpStatusCode?)response.ErrorCode,
description: response.Description,
parameters: response.Parameters);
}
catch (TelegramBotApiRequestException)
{
throw;
}
catch (OperationCanceledException)
{
throw;
}
catch (Exception exception)
{
throw new TelegramBotApiRequestException(this, "download",
description: "Unknown error occurred while sending request",
innerException: exception);
}
}

private async Task<TResult?> SendRepeatableRequestAsync<TResult, TRequest>(string method, TRequest? request,
CancellationToken cancellationToken)
{
Expand Down Expand Up @@ -175,7 +247,7 @@ private async Task<HttpRequestMessage> BuildHttpRequestAsync<TRequest>(string me

var requestJson = JsonSerializer.Serialize(request, typeof(TRequest), ModelsJsonSerializerContext.Default);

if (_useGzipCompression)
if (_clientConfiguration.UseGzipCompression)
{
await AddGzipJsonContentAsync(httpRequest, requestJson, cancellationToken);
}
Expand Down Expand Up @@ -222,7 +294,7 @@ private async Task WaitRetryDelayAsync(TelegramBotApiRequestException exception,
}
else
{
await Task.Delay(_defaultRetryDelay, cancellationToken);
await Task.Delay(_serverConfiguration.DefaultRetryDelay, cancellationToken);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Talkie.Bridges.Telegram.Models;
using File = Talkie.Bridges.Telegram.Models.File;

namespace Talkie.Bridges.Telegram.Clients;

Expand All @@ -16,21 +17,27 @@ public static Task<User> GetMeAsync(this ITelegramBotApiClient client,
return client.SendAsync<User>("getMe", cancellationToken);
}

public static Task<Message> SendMessageAsync(this ITelegramBotApiClient client, SendMessage message,
public static Task<Message> SendMessageAsync(this ITelegramBotApiClient client, SendMessage request,
CancellationToken cancellationToken = default)
{
return client.SendAsync<Message, SendMessage>("sendMessage", message, cancellationToken);
return client.SendAsync<Message, SendMessage>("sendMessage", request, cancellationToken);
}

public static Task<bool> DeleteMessageAsync(this ITelegramBotApiClient client, DeleteMessage deleteMessage,
public static Task<bool> DeleteMessageAsync(this ITelegramBotApiClient client, DeleteMessage request,
CancellationToken cancellationToken = default)
{
return client.SendAsync<bool, DeleteMessage>("deleteMessage", deleteMessage, cancellationToken);
return client.SendAsync<bool, DeleteMessage>("deleteMessage", request, cancellationToken);
}

public static Task<Message> EditMessageTextAsync(this ITelegramBotApiClient client, EditMessageText editMessageText,
public static Task<Message> EditMessageTextAsync(this ITelegramBotApiClient client, EditMessageText request,
CancellationToken cancellationToken = default)
{
return client.SendAsync<Message, EditMessageText>("editMessageText", editMessageText, cancellationToken);
return client.SendAsync<Message, EditMessageText>("editMessageText", request, cancellationToken);
}

public static Task<File> GetFileAsync(this ITelegramBotApiClient client, GetFile request,
CancellationToken cancellationToken = default)
{
return client.SendAsync<File, GetFile>("getFile", request, cancellationToken);
}
}
6 changes: 4 additions & 2 deletions Sources/Falko.Talkie.Bridges.Telegram/Models/Chat.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
namespace Talkie.Bridges.Telegram.Models;

public sealed class Chat(
public sealed class Chat
(
long id,
ChatType type,
string? title = null,
string? firstName = null,
string? lastName = null,
string? username = null,
bool? isForum = null)
bool? isForum = null
)
{
public readonly long Id = id;

Expand Down
6 changes: 4 additions & 2 deletions Sources/Falko.Talkie.Bridges.Telegram/Models/DeleteMessage.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
namespace Talkie.Bridges.Telegram.Models;

public sealed class DeleteMessage(
public sealed class DeleteMessage
(
long messageId,
long chatId)
long chatId
)
{
public readonly long MessageId = messageId;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
namespace Talkie.Bridges.Telegram.Models;

public sealed class EditMessageText(
public sealed class EditMessageText
(
string text,
long? chatId = null,
long? messageId = null,
string? businessConnectionId = null,
IReadOnlyCollection<MessageEntity>? entities = null)
IReadOnlyCollection<MessageEntity>? entities = null
)
{
public readonly string Text = text;

Expand Down
18 changes: 18 additions & 0 deletions Sources/Falko.Talkie.Bridges.Telegram/Models/File.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace Talkie.Bridges.Telegram.Models;

public sealed class File
(
string fileId,
string fileUniqueId,
long? fileSize = null,
string? filePath = null
)
{
public readonly string FileId = fileId;

public readonly string FileUniqueId = fileUniqueId;

public readonly long? FileSize = fileSize;

public readonly string? FilePath = filePath;
}
Loading
Loading