Implementation carried over from v1.
All checks were successful
Pack and Push NuGet Package / publish (push) Successful in 43s

This commit is contained in:
2025-07-05 05:11:04 +02:00
commit 9766124241
11 changed files with 689 additions and 0 deletions

View File

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\MessengerApi.QueryClient\MessengerApi.QueryClient.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,59 @@
using MessengerApi.Model;
using MessengerApi.Model.Messages;
using portaloggy;
namespace MessengerApi.Example
{
internal class Program
{
static void Main(string[] args)
{
var logger = new ConsoleLogger() { IsMessageSeverityColoringEnabled = true};
var httpClient = new HttpClient();
// Client 1 will demonstrate querying approach.
var client1 = new QueryClient(
new Credentials(
"aab8f7e9-ad13-4bf8-bb2e-0cd93d81adc0",
"http://localhost:5259"),
httpClient,
logger);
// Client 2 is subscription client waiting for the queries.
var client2 = new SubscriptionClient(
new Credentials(
"8f73f683-7cb3-40df-998e-6e604aef0e53",
"http://localhost:5259"),
httpClient,
logger);
var user1 = Guid.Parse("f696442b-e8dc-4074-b34f-94bcece8e74b");
var user2 = Guid.Parse("15d97720-f5b7-47aa-9c1a-71f98b0b9248");
// Subscribe client 2 to questions.
var client2Subscription = client2.Subscribe("TEST");
client2Subscription.OnMessage += (s, m) =>
{
logger.Info($"Received subscribed message - {m.Payload}");
client2.SendMessage(new OutboxMessage
{
ToUserId = m.Sender,
Payload = "ANSWER",
PayloadType = m.PayloadType
});
};
// Demonstrate query pipeline. Client 1 sends query and waits for response.
// Client 2 is subscribed to those messages and will send an answer right away.
var answer = client1.Query(new OutboxMessage
{
ToUserId = user2,
PayloadType = "TEST",
Payload = "QUESTION"
}).GetAwaiter().GetResult();
logger.Info($"Received answer message to my query with payload: {answer.Payload}.");
}
}
}

View File

@ -0,0 +1,49 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.11.35312.102
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}"
ProjectSection(SolutionItems) = preProject
..\Directory.Packages.props = ..\Directory.Packages.props
..\NuGet.config = ..\NuGet.config
..\README.md = ..\README.md
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
ProjectSection(SolutionItems) = preProject
..\.gitea\workflows\publish-nuget.yml = ..\.gitea\workflows\publish-nuget.yml
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".gitea", ".gitea", "{C3305381-7A52-4E26-9527-1697692DDD5A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.QueryClient", "MessengerApi.QueryClient\MessengerApi.QueryClient.csproj", "{1E842111-FBF0-7B24-DFBD-E1E5F0C5C1EC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.QueryClient.Example", "MessengerApi.QueryClient.Example\MessengerApi.QueryClient.Example.csproj", "{649F6676-5735-4E14-B25B-A2E80458C630}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E842111-FBF0-7B24-DFBD-E1E5F0C5C1EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E842111-FBF0-7B24-DFBD-E1E5F0C5C1EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E842111-FBF0-7B24-DFBD-E1E5F0C5C1EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E842111-FBF0-7B24-DFBD-E1E5F0C5C1EC}.Release|Any CPU.Build.0 = Release|Any CPU
{649F6676-5735-4E14-B25B-A2E80458C630}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{649F6676-5735-4E14-B25B-A2E80458C630}.Debug|Any CPU.Build.0 = Debug|Any CPU
{649F6676-5735-4E14-B25B-A2E80458C630}.Release|Any CPU.ActiveCfg = Release|Any CPU
{649F6676-5735-4E14-B25B-A2E80458C630}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {C3305381-7A52-4E26-9527-1697692DDD5A}
{C3305381-7A52-4E26-9527-1697692DDD5A} = {8EC462FD-D22E-90A8-E5CE-7E832BA40C5D}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {61948E36-4C2B-4BC9-80B6-9E155CE9F7DE}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>disable</Nullable>
<AssemblyVersion>$([System.DateTime]::UtcNow.ToString("yyyy.MM.dd.HHmm"))</AssemblyVersion>
<PackageVersion>$([System.DateTime]::UtcNow.ToString("yyyy.MM.dd.HHmm"))</PackageVersion>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Title>$(AssemblyName)</Title>
<BaseOutputPath>..\out\</BaseOutputPath>
<PackageTags>logging;log;logger</PackageTags>
<PackageLicenseExpression>mit-0</PackageLicenseExpression>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MessengerApi.SubscriptionClient" />
<PackageReference Include="portaloggy" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,71 @@
using portaloggy;
using MessengerApi.Model.Messages;
using MessengerApi.Model;
namespace MessengerApi
{
public interface IQueryClient : IDisposable
{
Task<InboxMessage> Query(OutboxMessage message);
}
public class QueryClient : SubscriptionClient, IQueryClient
{
private readonly int _timeoutInSeconds;
public QueryClient(
Credentials credentials,
HttpClient httpClient = null,
ILogger logger = null,
int maximumPermittedWaitTimeInSeconds = 10) :base(credentials, httpClient, logger)
{
this._timeoutInSeconds = maximumPermittedWaitTimeInSeconds;
}
public async Task<InboxMessage> Query(OutboxMessage message)
{
try
{
var messageTypeMask = $"{message.PayloadType}-{Guid.NewGuid()}";
var maskedMessage = new OutboxMessage
{
Payload = message.Payload,
LifespanInSeconds = message.LifespanInSeconds,
PayloadType = messageTypeMask,
ToUserId = message.ToUserId
};
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(this._timeoutInSeconds));
var sub = this.Subscribe(messageTypeMask);
var result = (InboxMessage)null;
sub.OnMessage += (source, message) =>
{
result = message;
cts.Cancel();
};
this.SendMessage(maskedMessage);
while (!cts.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
this.Unsubscribe(sub);
if (result == null)
{
throw new InvalidOperationException("Couldn't retrieve response.");
}
result.PayloadType = message.PayloadType;
return result;
}
catch
{
throw;
}
}
}
}