Broker implementation updated.
This commit is contained in:
@ -9,9 +9,23 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerBroker.Db", "Messe
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Db", "Db", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Db", "Db", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MessengerApi", "MessengerApi", "{D520DC2F-BD81-4588-8818-D493553ACD3D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Db.Contracts", "..\subm\messengerapi\code\MessengerApi.Db.Contracts\MessengerApi.Db.Contracts.csproj", "{B75EB44A-7B25-1E85-8E93-73C1A83F91B5}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Db", "..\sub\messengerapi\code\MessengerApi.Db\MessengerApi.Db.csproj", "{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Db", "..\subm\messengerapi\code\MessengerApi.Db\MessengerApi.Db.csproj", "{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerBroker.Configuration", "MessengerBroker.Configuration\MessengerBroker.Configuration.csproj", "{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Configuration", "..\subm\messengerapi\code\MessengerApi.Configuration\MessengerApi.Configuration.csproj", "{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Configuration", "Configuration", "{929526E6-6BE1-4769-B55F-85284F774523}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerBroker.Db.Sql", "MessengerBroker.Db.Sql\MessengerBroker.Db.Sql.csproj", "{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi", "..\subm\messengerapi\code\MessengerApi\MessengerApi.csproj", "{36AEE097-901C-171C-BA84-C231C2EC600F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Db.Sql", "..\subm\messengerapi\code\MessengerApi.Db.Sql\MessengerApi.Db.Sql.csproj", "{5F0E1A67-056B-E6B9-1940-5F31587C05CE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MessengerApi.Db.Npg", "..\subm\messengerapi\code\MessengerApi.Db.Npg\MessengerApi.Db.Npg.csproj", "{2A08099B-1A1E-FE40-9220-43F26AF852EC}"
|
||||||
EndProject
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
@ -27,17 +41,51 @@ Global
|
|||||||
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Release|Any CPU.Build.0 = Release|Any CPU
|
{52CF80F3-A938-437B-B9DD-5E64A206A641}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{B75EB44A-7B25-1E85-8E93-73C1A83F91B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{B75EB44A-7B25-1E85-8E93-73C1A83F91B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{B75EB44A-7B25-1E85-8E93-73C1A83F91B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34}.Release|Any CPU.Build.0 = Release|Any CPU
|
{B75EB44A-7B25-1E85-8E93-73C1A83F91B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{36AEE097-901C-171C-BA84-C231C2EC600F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{36AEE097-901C-171C-BA84-C231C2EC600F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{36AEE097-901C-171C-BA84-C231C2EC600F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{36AEE097-901C-171C-BA84-C231C2EC600F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5F0E1A67-056B-E6B9-1940-5F31587C05CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5F0E1A67-056B-E6B9-1940-5F31587C05CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5F0E1A67-056B-E6B9-1940-5F31587C05CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5F0E1A67-056B-E6B9-1940-5F31587C05CE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2A08099B-1A1E-FE40-9220-43F26AF852EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2A08099B-1A1E-FE40-9220-43F26AF852EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2A08099B-1A1E-FE40-9220-43F26AF852EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2A08099B-1A1E-FE40-9220-43F26AF852EC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(NestedProjects) = preSolution
|
GlobalSection(NestedProjects) = preSolution
|
||||||
{52CF80F3-A938-437B-B9DD-5E64A206A641} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
{52CF80F3-A938-437B-B9DD-5E64A206A641} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
{2F366BD9-AA41-7C4B-C6FA-1C5CCDF56E34} = {D520DC2F-BD81-4588-8818-D493553ACD3D}
|
{B75EB44A-7B25-1E85-8E93-73C1A83F91B5} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{9DFB9A27-503F-0FE5-9414-18A85C9F4BF4} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{B4964B49-DB24-4A91-BD4E-2EE8009CF5B0} = {929526E6-6BE1-4769-B55F-85284F774523}
|
||||||
|
{2138EEC0-ADB6-4C2A-3F81-B53B3884EFBB} = {929526E6-6BE1-4769-B55F-85284F774523}
|
||||||
|
{FCE9214C-CDCB-4D79-B7AB-2BCBAD41AC35} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{5F0E1A67-056B-E6B9-1940-5F31587C05CE} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
|
{2A08099B-1A1E-FE40-9220-43F26AF852EC} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {F0F93DDE-2CDC-4A7D-9D70-A7A12B3AF9CE}
|
SolutionGuid = {F0F93DDE-2CDC-4A7D-9D70-A7A12B3AF9CE}
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
# See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
|
|
||||||
|
|
||||||
# This stage is used when running from VS in fast mode (Default for Debug configuration)
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0 AS base
|
|
||||||
USER $APP_UID
|
|
||||||
WORKDIR /app
|
|
||||||
EXPOSE 8080
|
|
||||||
|
|
||||||
|
|
||||||
# This stage is used to build the service project
|
|
||||||
FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
WORKDIR /src
|
|
||||||
COPY ["MessengerBroker/MessengerBroker.csproj", "MessengerBroker/"]
|
|
||||||
RUN dotnet restore "./MessengerBroker/MessengerBroker.csproj"
|
|
||||||
COPY . .
|
|
||||||
WORKDIR "/src/MessengerBroker"
|
|
||||||
RUN dotnet build "./MessengerBroker.csproj" -c $BUILD_CONFIGURATION -o /app/build
|
|
||||||
|
|
||||||
# This stage is used to publish the service project to be copied to the final stage
|
|
||||||
FROM build AS publish
|
|
||||||
ARG BUILD_CONFIGURATION=Release
|
|
||||||
RUN dotnet publish "./MessengerBroker.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false
|
|
||||||
|
|
||||||
# This stage is used in production or when running from VS in regular mode (Default when not using the Debug configuration)
|
|
||||||
FROM base AS final
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=publish /app/publish .
|
|
||||||
ENTRYPOINT ["dotnet", "MessengerBroker.dll"]
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
using System.Linq.Expressions;
|
|
||||||
|
|
||||||
namespace MessengerBroker
|
|
||||||
{
|
|
||||||
public static class EntityExtensions
|
|
||||||
{
|
|
||||||
public static IQueryable<Db.Model.User> GetUsers(this IQueryable<Db.Model.User> source, Guid[] guids)
|
|
||||||
{
|
|
||||||
return source.Where(x => guids.Any(g => g == x.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static IQueryable<Db.Model.User> GetUsersExcept(this IQueryable<Db.Model.User> source, IEnumerable<Guid> guids)
|
|
||||||
{
|
|
||||||
return source.Where(x => !guids.Any(g => g == x.Id));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool GetUserExists(this IQueryable<Db.Model.User> source, Guid id)
|
|
||||||
{
|
|
||||||
return source.Any(x=> x.Id == id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
27
code/MessengerBroker/Factories/BrokerDbContextFactory.cs
Normal file
27
code/MessengerBroker/Factories/BrokerDbContextFactory.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using MessengerApi.Configuration.Model.Persistence;
|
||||||
|
using MessengerBroker.Configuration.Model;
|
||||||
|
using MessengerBroker.Db;
|
||||||
|
using MessengerBroker.Db.Sql;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Factories
|
||||||
|
{
|
||||||
|
public class BrokerDbContextFactory
|
||||||
|
{
|
||||||
|
private readonly BrokerConfiguration configuration;
|
||||||
|
|
||||||
|
public BrokerDbContextFactory(BrokerConfiguration configuration)
|
||||||
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
public BrokerDbContext CreateDbContext()
|
||||||
|
{
|
||||||
|
if(this.configuration.BrokerPersistenceConfiguration.PersistenceType == MessengerApi.Configuration.Enums.PersistenceTypes.Sql)
|
||||||
|
{
|
||||||
|
return new BrokerSqlDbContext((this.configuration.BrokerPersistenceConfiguration as SqlPersistenceConfiguration).ConnectionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
code/MessengerBroker/GlobalUsings.cs
Normal file
2
code/MessengerBroker/GlobalUsings.cs
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
global using ILogger = portaloggy.ILogger;
|
||||||
|
global using portaloggy;
|
||||||
@ -1,28 +0,0 @@
|
|||||||
namespace MessengerBroker.Handlers
|
|
||||||
{
|
|
||||||
public class AuthHandler
|
|
||||||
{
|
|
||||||
private readonly Settings settings;
|
|
||||||
|
|
||||||
public AuthHandler(Settings settings)
|
|
||||||
{
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Guid? Auth(HttpContext context)
|
|
||||||
{
|
|
||||||
var authHeader = context.Request.Headers["Authorization"].ToString();
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer "))
|
|
||||||
{
|
|
||||||
var token = authHeader.Substring("Bearer ".Length).Trim();
|
|
||||||
if (Guid.TryParse(token, out Guid brokerId) && this.settings.Slaves.Any(x => x.BrokerId == brokerId))
|
|
||||||
{
|
|
||||||
return brokerId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,78 @@
|
|||||||
|
using MessengerBroker.Configuration.Model;
|
||||||
|
using MessengerBroker.Models;
|
||||||
|
using MessengerBroker.Models.Scoped;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.Extensions.Caching.Memory;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Security.Claims;
|
||||||
|
using System.Text.Encodings.Web;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Handlers
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Validates our permananet API keys sent over as Bearer tokens.
|
||||||
|
/// </summary>
|
||||||
|
public class CustomBearerAuthenticationHandler : AuthenticationHandler<AuthenticationSchemeOptions>
|
||||||
|
{
|
||||||
|
private readonly IMemoryCache memoryCache;
|
||||||
|
private readonly BrokerConfiguration configuration;
|
||||||
|
|
||||||
|
public CustomBearerAuthenticationHandler(
|
||||||
|
IOptionsMonitor<AuthenticationSchemeOptions> options,
|
||||||
|
ILoggerFactory loggerFactory,
|
||||||
|
UrlEncoder encoder,
|
||||||
|
IMemoryCache memoryCache,
|
||||||
|
BrokerConfiguration configuration)
|
||||||
|
: base(options, loggerFactory, encoder)
|
||||||
|
{
|
||||||
|
this.memoryCache = memoryCache;
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||||
|
{
|
||||||
|
const string HEADER = "Authorization";
|
||||||
|
const string PREFIX = "Bearer ";
|
||||||
|
|
||||||
|
if (!Request.Headers.TryGetValue(HEADER, out var authHeader) ||
|
||||||
|
!authHeader.ToString().StartsWith(PREFIX))
|
||||||
|
{
|
||||||
|
return Task.FromResult(AuthenticateResult.NoResult());
|
||||||
|
}
|
||||||
|
|
||||||
|
var token = authHeader.ToString().Substring(PREFIX.Length).Trim();
|
||||||
|
|
||||||
|
if(memoryCache.TryGetValue(token, out CachedIdentity oldCache))
|
||||||
|
{
|
||||||
|
var identity = Context.RequestServices.GetRequiredService<Identity>();
|
||||||
|
identity.Server = oldCache.Server;
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(oldCache.ClaimsPrincipal, Scheme.Name)));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var brokerId = Guid.Parse(token);
|
||||||
|
var server = configuration.SlaveServers.SingleOrDefault(x => x.BrokerId == brokerId);
|
||||||
|
|
||||||
|
var principal = new ClaimsPrincipal(
|
||||||
|
new ClaimsIdentity(
|
||||||
|
new List<Claim>
|
||||||
|
{
|
||||||
|
new Claim(ClaimTypes.NameIdentifier, token),
|
||||||
|
new Claim(ClaimTypes.Name, token)
|
||||||
|
}, Scheme.Name));
|
||||||
|
|
||||||
|
var cache = new CachedIdentity
|
||||||
|
{
|
||||||
|
ClaimsPrincipal = principal,
|
||||||
|
Server = server
|
||||||
|
};
|
||||||
|
|
||||||
|
memoryCache.Set(token, cache, TimeSpan.FromMinutes(5));
|
||||||
|
|
||||||
|
var identity = Context.RequestServices.GetRequiredService<Identity>();
|
||||||
|
identity.Server = server;
|
||||||
|
return Task.FromResult(AuthenticateResult.Success(new AuthenticationTicket(cache.ClaimsPrincipal, Scheme.Name)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,81 +0,0 @@
|
|||||||
using MessengerApi.Db;
|
|
||||||
using MessengerBroker.Db;
|
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace MessengerBroker.Handlers
|
|
||||||
{
|
|
||||||
public class DataHandler
|
|
||||||
{
|
|
||||||
private readonly Settings _settings;
|
|
||||||
|
|
||||||
public Task<Tuple<MessengerApi.Db.Entities.User[], MessengerApi.Db.Entities.UserRoute[]>> GetLocalUsersAndRoutes()
|
|
||||||
{
|
|
||||||
var foreignUserIds = (Guid[])null;
|
|
||||||
using(var broCtx = new BrokerDbContext(this._settings.MessengerBrokerDbConnectionString))
|
|
||||||
{
|
|
||||||
foreignUserIds = broCtx.Users.Select(x => x.Id).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var apiCtx = new MessengerDbContext(this._settings.MessengerApiDbConnectionString))
|
|
||||||
{
|
|
||||||
var localUsers = apiCtx.Users
|
|
||||||
.Where(x => !foreignUserIds.Any(f => f == x.Id))
|
|
||||||
.ToArray();
|
|
||||||
var localRoutes = apiCtx.UserRoutes
|
|
||||||
.Include(x => x.From)
|
|
||||||
.Include(x => x.To)
|
|
||||||
.Where(x => localUsers.Any(l => l.Id == x.From.Id) && localUsers.Any(l => l.Id == x.To.Id))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return Task.FromResult(new Tuple<MessengerApi.Db.Entities.User[], MessengerApi.Db.Entities.UserRoute[]>(
|
|
||||||
localUsers,
|
|
||||||
localRoutes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Task<MessengerApi.Db.Entities.User[]> GetForeignUsers(Guid brokerId)
|
|
||||||
{
|
|
||||||
var foreignUserIds = (Guid[])null;
|
|
||||||
using (var broCtx = new BrokerDbContext(this._settings.MessengerBrokerDbConnectionString))
|
|
||||||
{
|
|
||||||
foreignUserIds = broCtx.Users.Where(x=>x.BrokerId == brokerId).Select(x => x.Id).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var apiCtx = new MessengerDbContext(this._settings.MessengerApiDbConnectionString))
|
|
||||||
{
|
|
||||||
var localUsers = apiCtx.Users
|
|
||||||
.Where(x => !foreignUserIds.Any(f => f == x.Id))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return Task.FromResult(localUsers);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<MessengerApi.Db.Entities.Message[]> GetMessages(Guid brokerId, DateTime sinceUtc)
|
|
||||||
{
|
|
||||||
var userIds = (Guid[])null;
|
|
||||||
|
|
||||||
if(brokerId == this._settings.BrokerId)
|
|
||||||
{
|
|
||||||
// Our messages.
|
|
||||||
var users = await this.GetLocalUsersAndRoutes();
|
|
||||||
userIds = users.Item1.Select(x => x.Id).ToArray();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var users = await this.GetForeignUsers(brokerId);
|
|
||||||
userIds = users.Select(x => x.Id).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
using (var apiCtx = new MessengerDbContext(this._settings.MessengerApiDbConnectionString))
|
|
||||||
{
|
|
||||||
var messages = apiCtx.Messages
|
|
||||||
.Include(x => x.From).Include(x => x.To)
|
|
||||||
.Where(x => x.CreatedUtc >= sinceUtc && userIds.Contains(x.From.Id))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
return messages;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
using MessengerApi.Factories;
|
||||||
|
using MessengerBroker.Configuration.Model;
|
||||||
|
using MessengerBroker.Factories;
|
||||||
|
using MessengerBroker.Model.Http;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Handlers.Endpoint
|
||||||
|
{
|
||||||
|
public class MessagesEndpointHandler
|
||||||
|
{
|
||||||
|
private readonly BrokerConfiguration configuration;
|
||||||
|
private readonly BrokerDbContextFactory brokerDbContextFactory;
|
||||||
|
private readonly DbContextFactory messengerDbContextFactory;
|
||||||
|
|
||||||
|
public MessagesEndpointHandler(
|
||||||
|
BrokerConfiguration configuration,
|
||||||
|
BrokerDbContextFactory brokerDbContextFactory,
|
||||||
|
DbContextFactory messengerDbContextFactory)
|
||||||
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.brokerDbContextFactory = brokerDbContextFactory;
|
||||||
|
this.messengerDbContextFactory = messengerDbContextFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<Messages.MessagesResponse> GetMessages(Messages.MessagesRequest request)
|
||||||
|
{
|
||||||
|
using var broCtx = this.brokerDbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
var brokerMessageIdCollection = broCtx.Messages
|
||||||
|
.Where(x => x.BrokerId == request.OwnerBrokerId)
|
||||||
|
.Select(x => x.Id)
|
||||||
|
.Take(1000)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
using var apiCtx = this.messengerDbContextFactory.CreateDbContext();
|
||||||
|
|
||||||
|
var messages = apiCtx.Messages
|
||||||
|
.Where(x => x.CreatedUtc >= request.SinceUtc && brokerMessageIdCollection.Contains(x.Id))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var response = new Messages.MessagesResponse
|
||||||
|
{
|
||||||
|
Messages = messages
|
||||||
|
};
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
using MessengerApi.Factories;
|
||||||
|
using MessengerBroker.Configuration.Model;
|
||||||
|
using MessengerBroker.Factories;
|
||||||
|
using MessengerBroker.Model.Http;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Handlers.Endpoint
|
||||||
|
{
|
||||||
|
public class UsersEndpointHandler
|
||||||
|
{
|
||||||
|
private readonly BrokerConfiguration configuration;
|
||||||
|
private readonly BrokerDbContextFactory brokerDbContextFactory;
|
||||||
|
private readonly DbContextFactory messengerDbContextFactory;
|
||||||
|
|
||||||
|
public UsersEndpointHandler(
|
||||||
|
BrokerConfiguration configuration,
|
||||||
|
BrokerDbContextFactory brokerDbContextFactory,
|
||||||
|
DbContextFactory messengerDbContextFactory)
|
||||||
|
{
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.brokerDbContextFactory = brokerDbContextFactory;
|
||||||
|
this.messengerDbContextFactory = messengerDbContextFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<Users.UsersResponse> GetUsers()
|
||||||
|
{
|
||||||
|
var foreignUserIds = (Guid[])null;
|
||||||
|
|
||||||
|
using(var broCtx = this.brokerDbContextFactory.CreateDbContext())
|
||||||
|
{
|
||||||
|
foreignUserIds = broCtx.Users.Select(x => x.Id).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
using (var apiCtx = this.messengerDbContextFactory.CreateDbContext())
|
||||||
|
{
|
||||||
|
var localUsers = apiCtx.Users
|
||||||
|
.Where(x => !foreignUserIds.Any(f => f == x.Id))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
var localRoutes = apiCtx.UserRoutes
|
||||||
|
.Include(x => x.From)
|
||||||
|
.Include(x => x.To)
|
||||||
|
.Where(x => localUsers.Any(l => l.Id == x.From.Id) && localUsers.Any(l => l.Id == x.To.Id))
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return Task.FromResult(new Users.UsersResponse
|
||||||
|
{
|
||||||
|
Users = localUsers.Select(x => new Users.UsersResponse.User
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
ApiKey = x.ApiKey,
|
||||||
|
IsEnabled = x.IsEnabled,
|
||||||
|
Name = x.Name
|
||||||
|
}).ToArray(),
|
||||||
|
UserRoutes = localRoutes.Select(x => new Users.UsersResponse.UserRoute
|
||||||
|
{
|
||||||
|
Id = x.Id,
|
||||||
|
FromId = x.From.Id,
|
||||||
|
ToId = x.To.Id
|
||||||
|
}).ToArray()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,196 +1,196 @@
|
|||||||
using MessengerApi.Db;
|
//using MessengerApi.Db;
|
||||||
using MessengerBroker.Db;
|
//using MessengerBroker.Db;
|
||||||
using Microsoft.EntityFrameworkCore;
|
//using Microsoft.EntityFrameworkCore;
|
||||||
using System.Text.Json;
|
//using System.Text.Json;
|
||||||
|
|
||||||
namespace MessengerBroker.Handlers
|
//namespace MessengerBroker.Handlers
|
||||||
{
|
//{
|
||||||
public class MasterHandler
|
// public class MasterHandler
|
||||||
{
|
// {
|
||||||
private readonly Settings settings;
|
// private readonly Settings settings;
|
||||||
|
|
||||||
private readonly HttpClient httpClient = new HttpClient();
|
// private readonly HttpClient httpClient = new HttpClient();
|
||||||
|
|
||||||
public async Task BeginSyncingWithMaster(Settings.MasterServer masterServer, CancellationToken ct = default)
|
// public async Task BeginSyncingWithMaster(Settings.MasterServer masterServer, CancellationToken ct = default)
|
||||||
{
|
// {
|
||||||
while (!ct.IsCancellationRequested)
|
// while (!ct.IsCancellationRequested)
|
||||||
{
|
// {
|
||||||
await Task.Delay(TimeSpan.FromSeconds(1));
|
// await Task.Delay(TimeSpan.FromSeconds(1));
|
||||||
|
|
||||||
var usersRequest = new HttpRequestMessage(HttpMethod.Get, $"{masterServer.BrokerApiUrl}/users");
|
// var usersRequest = new HttpRequestMessage(HttpMethod.Get, $"{masterServer.BrokerApiUrl}/users");
|
||||||
usersRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", this.settings.BrokerId.ToString());
|
// usersRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", this.settings.BrokerId.ToString());
|
||||||
|
|
||||||
var usersResponseMessage = await this.httpClient.SendAsync(usersRequest, ct);
|
// var usersResponseMessage = await this.httpClient.SendAsync(usersRequest, ct);
|
||||||
|
|
||||||
if (!usersResponseMessage.IsSuccessStatusCode)
|
// if (!usersResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
// {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
var usersResponse = JsonSerializer.Deserialize<Model.Http.Users.UsersResponse>(await usersResponseMessage.Content.ReadAsStringAsync());
|
// var usersResponse = JsonSerializer.Deserialize<Model.Http.Users.UsersResponse>(await usersResponseMessage.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
using (var broCtx = new BrokerDbContext(this.settings.MessengerBrokerDbConnectionString))
|
// using (var broCtx = new BrokerDbContext(this.settings.MessengerBrokerDbConnectionString))
|
||||||
using (var apiCtx = new MessengerDbContext(this.settings.MessengerApiDbConnectionString))
|
// using (var apiCtx = new MessengerDbContext(this.settings.MessengerApiDbConnectionString))
|
||||||
{
|
// {
|
||||||
var updatedUsers = usersResponse.Users.Where(x => broCtx.Users.GetUserExists(x.Id)).ToList();
|
// var updatedUsers = usersResponse.Users.Where(x => broCtx.Users.GetUserExists(x.Id)).ToList();
|
||||||
updatedUsers.ForEach(async x => await this.UpdateUser(x, apiCtx));
|
// updatedUsers.ForEach(async x => await this.UpdateUser(x, apiCtx));
|
||||||
|
|
||||||
var deletedUsers = broCtx.Users.GetUsersExcept(usersResponse.Users.Select(x => x.Id)).ToList();
|
// var deletedUsers = broCtx.Users.GetUsersExcept(usersResponse.Users.Select(x => x.Id)).ToList();
|
||||||
deletedUsers.ForEach(async x => await this.RemoveUser(x.Id, broCtx, apiCtx));
|
// deletedUsers.ForEach(async x => await this.RemoveUser(x.Id, broCtx, apiCtx));
|
||||||
|
|
||||||
var addedUsers = usersResponse.Users.Where(x => !broCtx.Users.GetUserExists(x.Id)).ToList();
|
// var addedUsers = usersResponse.Users.Where(x => !broCtx.Users.GetUserExists(x.Id)).ToList();
|
||||||
addedUsers.ForEach(async x => await this.AddUser(x, masterServer.BrokerId, broCtx, apiCtx));
|
// addedUsers.ForEach(async x => await this.AddUser(x, masterServer.BrokerId, broCtx, apiCtx));
|
||||||
|
|
||||||
foreach (var route in usersResponse.UserRoutes
|
// foreach (var route in usersResponse.UserRoutes
|
||||||
.Where(r => apiCtx.UserRoutes
|
// .Where(r => apiCtx.UserRoutes
|
||||||
.Include(x => x.From)
|
// .Include(x => x.From)
|
||||||
.Include(x => x.To)
|
// .Include(x => x.To)
|
||||||
.Any(apir => apir.Id == r.Id && (apir.From.Id != r.FromId || apir.To.Id != r.ToId))))
|
// .Any(apir => apir.Id == r.Id && (apir.From.Id != r.FromId || apir.To.Id != r.ToId))))
|
||||||
{
|
// {
|
||||||
var existing = apiCtx.UserRoutes.Include(x => x.From).Include(x => x.To).Single(x => x.Id == route.Id);
|
// var existing = apiCtx.UserRoutes.Include(x => x.From).Include(x => x.To).Single(x => x.Id == route.Id);
|
||||||
existing.From = apiCtx.Users.Single(x => x.Id == route.FromId);
|
// existing.From = apiCtx.Users.Single(x => x.Id == route.FromId);
|
||||||
existing.To = apiCtx.Users.Single(x => x.Id == route.ToId);
|
// existing.To = apiCtx.Users.Single(x => x.Id == route.ToId);
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (var deletedRoute in apiCtx.UserRoutes
|
// foreach (var deletedRoute in apiCtx.UserRoutes
|
||||||
.Where(x => !usersResponse.UserRoutes.Any(r => r.Id == x.Id)))
|
// .Where(x => !usersResponse.UserRoutes.Any(r => r.Id == x.Id)))
|
||||||
{
|
// {
|
||||||
apiCtx.UserRoutes.Remove(deletedRoute);
|
// apiCtx.UserRoutes.Remove(deletedRoute);
|
||||||
}
|
// }
|
||||||
|
|
||||||
foreach (var addedRoute in usersResponse.UserRoutes
|
// foreach (var addedRoute in usersResponse.UserRoutes
|
||||||
.Where(r => !apiCtx.UserRoutes.Any(x => x.Id == r.Id)))
|
// .Where(r => !apiCtx.UserRoutes.Any(x => x.Id == r.Id)))
|
||||||
{
|
// {
|
||||||
apiCtx.UserRoutes.Add(new MessengerApi.Db.Entities.UserRoute
|
// apiCtx.UserRoutes.Add(new MessengerApi.Db.Entities.UserRoute
|
||||||
{
|
// {
|
||||||
Id = addedRoute.Id,
|
// Id = addedRoute.Id,
|
||||||
From = apiCtx.Users.Single(x => x.Id == addedRoute.FromId),
|
// From = apiCtx.Users.Single(x => x.Id == addedRoute.FromId),
|
||||||
To = apiCtx.Users.Single(x => x.Id == addedRoute.ToId)
|
// To = apiCtx.Users.Single(x => x.Id == addedRoute.ToId)
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
broCtx.SaveChanges();
|
// broCtx.SaveChanges();
|
||||||
apiCtx.SaveChanges();
|
// apiCtx.SaveChanges();
|
||||||
}
|
// }
|
||||||
|
|
||||||
var messagesRequest = new HttpRequestMessage(HttpMethod.Get, $"{masterServer.BrokerApiUrl}/messages");
|
// var messagesRequest = new HttpRequestMessage(HttpMethod.Get, $"{masterServer.BrokerApiUrl}/messages");
|
||||||
messagesRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", this.settings.BrokerId.ToString());
|
// messagesRequest.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", this.settings.BrokerId.ToString());
|
||||||
|
|
||||||
var messagesResponseMessage = await this.httpClient.SendAsync(messagesRequest, ct);
|
// var messagesResponseMessage = await this.httpClient.SendAsync(messagesRequest, ct);
|
||||||
|
|
||||||
if (!messagesResponseMessage.IsSuccessStatusCode)
|
// if (!messagesResponseMessage.IsSuccessStatusCode)
|
||||||
{
|
// {
|
||||||
continue;
|
// continue;
|
||||||
}
|
// }
|
||||||
|
|
||||||
var messagesResponse = JsonSerializer.Deserialize<Model.Http.Sync.SyncResponse>(await messagesResponseMessage.Content.ReadAsStringAsync());
|
// var messagesResponse = JsonSerializer.Deserialize<Model.Http.Messages.MessagesResponse>(await messagesResponseMessage.Content.ReadAsStringAsync());
|
||||||
|
|
||||||
using (var broCtx = new BrokerDbContext(this.settings.MessengerBrokerDbConnectionString))
|
// using (var broCtx = new BrokerDbContext(this.settings.MessengerBrokerDbConnectionString))
|
||||||
using (var apiCtx = new MessengerDbContext(this.settings.MessengerApiDbConnectionString))
|
// using (var apiCtx = new MessengerDbContext(this.settings.MessengerApiDbConnectionString))
|
||||||
{
|
// {
|
||||||
var addedMessages = messagesResponse.Messages
|
// var addedMessages = messagesResponse.Messages
|
||||||
.Where(m => broCtx.Messages.Any(x => x.BrokerId == masterServer.BrokerId && x.Id == m.Id) == false)
|
// .Where(m => broCtx.Messages.Any(x => x.BrokerId == masterServer.BrokerId && x.Id == m.Id) == false)
|
||||||
.ToList();
|
// .ToList();
|
||||||
|
|
||||||
addedMessages.ForEach(x =>
|
// addedMessages.ForEach(x =>
|
||||||
{
|
// {
|
||||||
broCtx.Messages.Add(new Db.Model.Message
|
// broCtx.Messages.Add(new Db.Model.Message
|
||||||
{
|
// {
|
||||||
BrokerId = masterServer.BrokerId,
|
// BrokerId = masterServer.BrokerId,
|
||||||
Id = x.Id
|
// Id = x.Id
|
||||||
});
|
// });
|
||||||
|
|
||||||
apiCtx.Messages.Add(new MessengerApi.Db.Entities.Message
|
// apiCtx.Messages.Add(new MessengerApi.Db.Entities.Message
|
||||||
{
|
// {
|
||||||
Id = x.Id,
|
// Id = x.Id,
|
||||||
CreatedUtc = x.CreatedUtc,
|
// CreatedUtc = x.CreatedUtc,
|
||||||
From = x.From != null ? (apiCtx.Users.SingleOrDefault(u => u.Id == x.From.Value)) ?? null : null,
|
// From = x.From != null ? (apiCtx.Users.SingleOrDefault(u => u.Id == x.From.Value)) ?? null : null,
|
||||||
To = x.To != null ? (apiCtx.Users.SingleOrDefault(u => u.Id == x.To.Value)) ?? null : null,
|
// To = x.To != null ? (apiCtx.Users.SingleOrDefault(u => u.Id == x.To.Value)) ?? null : null,
|
||||||
IsAcknowledged = x.IsAcknowledged,
|
// IsAcknowledged = x.IsAcknowledged,
|
||||||
IsDelivered = x.IsDelivered,
|
// IsDelivered = x.IsDelivered,
|
||||||
Payload = x.Payload,
|
// Payload = x.Payload,
|
||||||
PayloadId = x.PayloadId,
|
// PayloadId = x.PayloadId,
|
||||||
PayloadLifespanInSeconds = x.PayloadLifespanInSeconds,
|
// PayloadLifespanInSeconds = x.PayloadLifespanInSeconds,
|
||||||
PayloadTimestamp = x.PayloadTimestamp,
|
// PayloadTimestamp = x.PayloadTimestamp,
|
||||||
PayloadType = x.PayloadType,
|
// PayloadType = x.PayloadType,
|
||||||
});
|
// });
|
||||||
});
|
// });
|
||||||
|
|
||||||
var existingMessages = messagesResponse.Messages
|
// var existingMessages = messagesResponse.Messages
|
||||||
.Except(addedMessages)
|
// .Except(addedMessages)
|
||||||
.ToList();
|
// .ToList();
|
||||||
|
|
||||||
existingMessages.ForEach(x =>
|
// existingMessages.ForEach(x =>
|
||||||
{
|
// {
|
||||||
var existing = apiCtx.Messages.SingleOrDefault(a => a.Id == x.Id);
|
// var existing = apiCtx.Messages.SingleOrDefault(a => a.Id == x.Id);
|
||||||
|
|
||||||
if(existing != null && (existing.IsDelivered != x.IsDelivered || existing.IsAcknowledged != x.IsAcknowledged))
|
// if(existing != null && (existing.IsDelivered != x.IsDelivered || existing.IsAcknowledged != x.IsAcknowledged))
|
||||||
{
|
// {
|
||||||
existing.IsDelivered = x.IsDelivered;
|
// existing.IsDelivered = x.IsDelivered;
|
||||||
existing.IsAcknowledged = x.IsAcknowledged;
|
// existing.IsAcknowledged = x.IsAcknowledged;
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
broCtx.SaveChanges();
|
// broCtx.SaveChanges();
|
||||||
apiCtx.SaveChanges();
|
// apiCtx.SaveChanges();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private async Task RemoveUser(Guid id, BrokerDbContext broCtx, MessengerDbContext apiCtx)
|
// private async Task RemoveUser(Guid id, BrokerDbContext broCtx, MessengerDbContext apiCtx)
|
||||||
{
|
// {
|
||||||
var broUser = await broCtx.Users.SingleOrDefaultAsync(x => x.Id == id);
|
// var broUser = await broCtx.Users.SingleOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
if (broUser != null)
|
// if (broUser != null)
|
||||||
{
|
// {
|
||||||
broCtx.Users.Remove(broUser);
|
// broCtx.Users.Remove(broUser);
|
||||||
}
|
// }
|
||||||
|
|
||||||
var apiUser = await apiCtx.Users.SingleOrDefaultAsync(x => x.Id == id);
|
// var apiUser = await apiCtx.Users.SingleOrDefaultAsync(x => x.Id == id);
|
||||||
|
|
||||||
if (apiUser != null)
|
// if (apiUser != null)
|
||||||
{
|
// {
|
||||||
apiCtx.Users.Remove(apiUser);
|
// apiCtx.Users.Remove(apiUser);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private async Task AddUser(Model.Http.Users.UsersResponse.User user, Guid brokerId, BrokerDbContext broCtx, MessengerDbContext apiCtx)
|
// private async Task AddUser(Model.Http.Users.UsersResponse.User user, Guid brokerId, BrokerDbContext broCtx, MessengerDbContext apiCtx)
|
||||||
{
|
// {
|
||||||
if (broCtx.Users.GetUserExists(user.Id) == false)
|
// if (broCtx.Users.GetUserExists(user.Id) == false)
|
||||||
{
|
// {
|
||||||
broCtx.Users.Add(new Db.Model.User
|
// broCtx.Users.Add(new Db.Model.User
|
||||||
{
|
// {
|
||||||
Id = user.Id,
|
// Id = user.Id,
|
||||||
BrokerId = brokerId
|
// BrokerId = brokerId
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (apiCtx.Users.Any(x => x.Id == user.Id))
|
// if (apiCtx.Users.Any(x => x.Id == user.Id))
|
||||||
{
|
// {
|
||||||
await this.UpdateUser(user, apiCtx);
|
// await this.UpdateUser(user, apiCtx);
|
||||||
}
|
// }
|
||||||
else
|
// else
|
||||||
{
|
// {
|
||||||
await apiCtx.Users.AddAsync(new MessengerApi.Db.Entities.User
|
// await apiCtx.Users.AddAsync(new MessengerApi.Db.Entities.User
|
||||||
{
|
// {
|
||||||
Id = user.Id,
|
// Id = user.Id,
|
||||||
ApiKey = user.ApiKey,
|
// ApiKey = user.ApiKey,
|
||||||
CanReceive = user.CanReceive,
|
// CanReceive = user.CanReceive,
|
||||||
CanSend = user.CanSend,
|
// CanSend = user.CanSend,
|
||||||
IsEnabled = user.IsEnabled,
|
// IsEnabled = user.IsEnabled,
|
||||||
Name = user.Name
|
// Name = user.Name
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
private async Task UpdateUser(Model.Http.Users.UsersResponse.User user, MessengerDbContext apiCtx)
|
// private async Task UpdateUser(Model.Http.Users.UsersResponse.User user, MessengerDbContext apiCtx)
|
||||||
{
|
// {
|
||||||
var apiUser = await apiCtx.Users.SingleAsync(x => x.Id == user.Id);
|
// var apiUser = await apiCtx.Users.SingleAsync(x => x.Id == user.Id);
|
||||||
apiUser.ApiKey = user.ApiKey;
|
// apiUser.ApiKey = user.ApiKey;
|
||||||
apiUser.CanReceive = user.CanReceive;
|
// apiUser.CanReceive = user.CanReceive;
|
||||||
apiUser.CanSend = user.CanSend;
|
// apiUser.CanSend = user.CanSend;
|
||||||
apiUser.IsEnabled = user.IsEnabled;
|
// apiUser.IsEnabled = user.IsEnabled;
|
||||||
apiUser.Name = user.Name;
|
// apiUser.Name = user.Name;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
@ -12,7 +12,9 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\sub\messengerapi\code\MessengerApi.Db\MessengerApi.Db.csproj" />
|
<ProjectReference Include="..\..\subm\messengerapi\code\MessengerApi\MessengerApi.csproj" />
|
||||||
|
<ProjectReference Include="..\MessengerBroker.Configuration\MessengerBroker.Configuration.csproj" />
|
||||||
|
<ProjectReference Include="..\MessengerBroker.Db.Sql\MessengerBroker.Db.Sql.csproj" />
|
||||||
<ProjectReference Include="..\MessengerBroker.Db\MessengerBroker.Db.csproj" />
|
<ProjectReference Include="..\MessengerBroker.Db\MessengerBroker.Db.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +0,0 @@
|
|||||||
@MessengerBroker_HostAddress = http://localhost:5048
|
|
||||||
|
|
||||||
GET {{MessengerBroker_HostAddress}}/weatherforecast/
|
|
||||||
Accept: application/json
|
|
||||||
|
|
||||||
###
|
|
||||||
@ -1,42 +0,0 @@
|
|||||||
namespace MessengerBroker.Model.Http
|
|
||||||
{
|
|
||||||
public class Sync
|
|
||||||
{
|
|
||||||
public class SyncRequest
|
|
||||||
{
|
|
||||||
public Guid BrokerId { get; set; }
|
|
||||||
|
|
||||||
public DateTime SinceUtc { get; set; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public class SyncResponse
|
|
||||||
{
|
|
||||||
public Message[] Messages { get; set; }
|
|
||||||
|
|
||||||
public class Message
|
|
||||||
{
|
|
||||||
public Guid Id { get; set; }
|
|
||||||
|
|
||||||
public DateTime CreatedUtc { get; set; }
|
|
||||||
|
|
||||||
public Guid? From { get; set; }
|
|
||||||
|
|
||||||
public Guid? To { get; set; }
|
|
||||||
|
|
||||||
public bool IsDelivered { get; set; }
|
|
||||||
|
|
||||||
public bool IsAcknowledged { get; set; }
|
|
||||||
|
|
||||||
public string PayloadId { get; set; }
|
|
||||||
|
|
||||||
public string PayloadType { get; set; }
|
|
||||||
|
|
||||||
public string Payload { get; set; }
|
|
||||||
|
|
||||||
public DateTime? PayloadTimestamp { get; set; }
|
|
||||||
|
|
||||||
public int? PayloadLifespanInSeconds { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
12
code/MessengerBroker/Models/CachedIdentity.cs
Normal file
12
code/MessengerBroker/Models/CachedIdentity.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using MessengerBroker.Configuration.Model.Servers;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Models
|
||||||
|
{
|
||||||
|
public class CachedIdentity
|
||||||
|
{
|
||||||
|
public SlaveServer Server { get; set; }
|
||||||
|
|
||||||
|
public ClaimsPrincipal ClaimsPrincipal { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
17
code/MessengerBroker/Models/Http/Messages.cs
Normal file
17
code/MessengerBroker/Models/Http/Messages.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace MessengerBroker.Model.Http
|
||||||
|
{
|
||||||
|
public class Messages
|
||||||
|
{
|
||||||
|
public class MessagesRequest
|
||||||
|
{
|
||||||
|
public Guid OwnerBrokerId { get; set; }
|
||||||
|
|
||||||
|
public DateTime SinceUtc { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class MessagesResponse
|
||||||
|
{
|
||||||
|
public MessengerApi.Db.Entities.Message[] Messages { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,10 +17,6 @@
|
|||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
|
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
public bool CanSend { get; set; }
|
|
||||||
|
|
||||||
public bool CanReceive { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class UserRoute
|
public class UserRoute
|
||||||
9
code/MessengerBroker/Models/Scoped/Identity.cs
Normal file
9
code/MessengerBroker/Models/Scoped/Identity.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using MessengerBroker.Configuration.Model.Servers;
|
||||||
|
|
||||||
|
namespace MessengerBroker.Models.Scoped
|
||||||
|
{
|
||||||
|
public class Identity
|
||||||
|
{
|
||||||
|
public SlaveServer Server { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,14 @@
|
|||||||
|
using MessengerApi.Configuration.Sources.Environment;
|
||||||
|
using MessengerBroker.Configuration.Model;
|
||||||
|
using MessengerBroker.Factories;
|
||||||
using MessengerBroker.Handlers;
|
using MessengerBroker.Handlers;
|
||||||
|
using MessengerBroker.Handlers.Endpoint;
|
||||||
using MessengerBroker.Model.Http;
|
using MessengerBroker.Model.Http;
|
||||||
using System.Runtime.CompilerServices;
|
using MessengerBroker.Models.Scoped;
|
||||||
|
using Microsoft.AspNetCore.Authentication;
|
||||||
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
using System.Net;
|
||||||
|
|
||||||
namespace MessengerBroker
|
namespace MessengerBroker
|
||||||
{
|
{
|
||||||
@ -8,94 +16,119 @@ namespace MessengerBroker
|
|||||||
{
|
{
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
var settings = (Settings)null;
|
BrokerConfiguration configuration = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
configuration = new BrokerConfiguration(new EnvironmentConfigurationSource());
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Can't load settings.", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
builder.Services.AddMemoryCache();
|
||||||
|
builder.Services.AddSingleton<ILogger, ConsoleLogger>();
|
||||||
|
builder.Services.AddSingleton<BrokerConfiguration>(configuration);
|
||||||
|
builder.Services.AddSingleton<BrokerDbContextFactory>();
|
||||||
|
builder.Services.AddSingleton<MessengerApi.Factories.DbContextFactory>((sp) =>
|
||||||
|
{
|
||||||
|
return new MessengerApi.Factories.DbContextFactory(configuration.ApiPersistenceConfiguration);
|
||||||
|
});
|
||||||
|
|
||||||
|
builder.Services.AddScoped<Identity>();
|
||||||
|
builder.Services.AddScoped<UsersEndpointHandler>();
|
||||||
|
builder.Services.AddScoped<MessagesEndpointHandler>();
|
||||||
|
|
||||||
|
// Authentication.
|
||||||
|
builder.Services
|
||||||
|
.AddAuthentication("Bearer")
|
||||||
|
.AddScheme<AuthenticationSchemeOptions, CustomBearerAuthenticationHandler>("Bearer", null);
|
||||||
|
|
||||||
|
// Proxy registration to forward real client IPs.
|
||||||
|
builder.Services.Configure<ForwardedHeadersOptions>(options =>
|
||||||
|
{
|
||||||
|
options.ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
|
||||||
|
|
||||||
|
foreach (var proxy in configuration.Proxies)
|
||||||
|
{
|
||||||
|
options.KnownProxies.Add(IPAddress.Parse(proxy));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
var app = builder.Build();
|
var app = builder.Build();
|
||||||
|
|
||||||
app.MapGet("/users", async (HttpContext httpContext) =>
|
// DB Migrations
|
||||||
|
using (var ctx = app.Services.GetRequiredService<BrokerDbContextFactory>().CreateDbContext())
|
||||||
{
|
{
|
||||||
var authHandler = app.Services.GetService<AuthHandler>();
|
var migrationLogger = app.Services.GetRequiredService<ILogger>();
|
||||||
var brokerId = authHandler.Auth(httpContext);
|
|
||||||
|
|
||||||
if(brokerId == null)
|
try
|
||||||
{
|
{
|
||||||
return Results.Unauthorized();
|
if (ctx.Database.GetPendingMigrations().Any())
|
||||||
|
{
|
||||||
|
migrationLogger.Info("Applying migrations.");
|
||||||
|
ctx.Database.Migrate();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
migrationLogger.Info("No migrations pending.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
migrationLogger.Error("Can't run migrations successfully.", ex);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var dataHandler = app.Services.GetService<DataHandler>();
|
//// Housekeeping.
|
||||||
var usersAndRoutes = await dataHandler.GetLocalUsersAndRoutes();
|
//if (configuration.HousekeepingEnabled)
|
||||||
|
//{
|
||||||
|
// _ = Task.Run(async () =>
|
||||||
|
// {
|
||||||
|
// while (true)
|
||||||
|
// {
|
||||||
|
// await app.Services.GetService<HousekeepingHandler>().RemoveOldMessages();
|
||||||
|
// await Task.Delay(TimeSpan.FromMinutes(1));
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
//}
|
||||||
|
|
||||||
var response = new Users.UsersResponse
|
//// Run pull sync from masters.
|
||||||
{
|
//_ = Task.Run(async () =>
|
||||||
Users = usersAndRoutes.Item1.Select(x => new Users.UsersResponse.User
|
//{
|
||||||
{
|
// var cts = new CancellationTokenSource();
|
||||||
Id = x.Id,
|
// var handler = app.Services.GetService<MasterHandler>();
|
||||||
Name = x.Name,
|
|
||||||
ApiKey = x.ApiKey,
|
|
||||||
CanReceive = x.CanReceive,
|
|
||||||
CanSend = x.CanSend,
|
|
||||||
IsEnabled = x.IsEnabled,
|
|
||||||
}).ToArray(),
|
|
||||||
UserRoutes = usersAndRoutes.Item2.Select(x => new Users.UsersResponse.UserRoute
|
|
||||||
{
|
|
||||||
Id = x.Id,
|
|
||||||
FromId = x.From.Id,
|
|
||||||
ToId = x.To.Id
|
|
||||||
}).ToArray()
|
|
||||||
};
|
|
||||||
|
|
||||||
|
// foreach (var master in settings.Masters)
|
||||||
|
// {
|
||||||
|
// _ = handler.BeginSyncingWithMaster(master, cts.Token);
|
||||||
|
// }
|
||||||
|
//});
|
||||||
|
|
||||||
|
app.UseStaticFiles();
|
||||||
|
app.UseRouting();
|
||||||
|
app.UseAuthentication();
|
||||||
|
app.UseForwardedHeaders();
|
||||||
|
|
||||||
|
app.MapGet("/users", async (UsersEndpointHandler handler) =>
|
||||||
|
{
|
||||||
|
var response = await handler.GetUsers();
|
||||||
return Results.Json(response);
|
return Results.Json(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
app.MapGet("/sync", async (HttpContext httpContext, [AsParameters] Sync.SyncRequest request) =>
|
app.MapGet("/messages", async (
|
||||||
|
MessagesEndpointHandler handler,
|
||||||
|
[AsParameters] Messages.MessagesRequest request) =>
|
||||||
{
|
{
|
||||||
var authHandler = app.Services.GetService<AuthHandler>();
|
var response = await handler.GetMessages(request);
|
||||||
var brokerId = authHandler.Auth(httpContext);
|
|
||||||
|
|
||||||
if(brokerId == null)
|
|
||||||
{
|
|
||||||
return Results.Unauthorized();
|
|
||||||
}
|
|
||||||
else if(request.BrokerId != brokerId && request.BrokerId != settings.BrokerId)
|
|
||||||
{
|
|
||||||
return Results.Unauthorized();
|
|
||||||
}
|
|
||||||
|
|
||||||
var dataHandler = app.Services.GetService<DataHandler>();
|
|
||||||
var messages = await dataHandler.GetMessages(request.BrokerId, request.SinceUtc);
|
|
||||||
|
|
||||||
var response = new Sync.SyncResponse
|
|
||||||
{
|
|
||||||
Messages = messages.Select(x => new Sync.SyncResponse.Message
|
|
||||||
{
|
|
||||||
Id = x.Id,
|
|
||||||
CreatedUtc = x.CreatedUtc,
|
|
||||||
From = x.From.Id,
|
|
||||||
To = x.To.Id,
|
|
||||||
IsAcknowledged = x.IsAcknowledged,
|
|
||||||
IsDelivered = x.IsDelivered,
|
|
||||||
Payload = x.Payload,
|
|
||||||
PayloadId = x.PayloadId,
|
|
||||||
PayloadLifespanInSeconds = x.PayloadLifespanInSeconds,
|
|
||||||
PayloadTimestamp = x.PayloadTimestamp,
|
|
||||||
PayloadType = x.PayloadType
|
|
||||||
}).ToArray()
|
|
||||||
};
|
|
||||||
|
|
||||||
return Results.Json(response);
|
return Results.Json(response);
|
||||||
});
|
});
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
var cts = new CancellationTokenSource();
|
|
||||||
var handler = app.Services.GetService<MasterHandler>();
|
|
||||||
|
|
||||||
foreach(var master in settings.Masters)
|
|
||||||
{
|
|
||||||
_ = handler.BeginSyncingWithMaster(master, cts.Token);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.Run();
|
app.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
namespace MessengerBroker
|
|
||||||
{
|
|
||||||
public class Settings
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Connection string to Messenger API DB.
|
|
||||||
/// </summary>
|
|
||||||
public string MessengerApiDbConnectionString { get; set; }
|
|
||||||
|
|
||||||
public string MessengerBrokerDbConnectionString { get; set; }
|
|
||||||
|
|
||||||
public Guid BrokerId { get; set; }
|
|
||||||
|
|
||||||
public MasterServer[] Masters { get; set; }
|
|
||||||
|
|
||||||
public SlaveServer[] Slaves { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A server that we are a slave to. If this server goes down, their users will alternate to us and we have to provide service during outage. We pull data from this server.
|
|
||||||
/// </summary>
|
|
||||||
public class MasterServer
|
|
||||||
{
|
|
||||||
public string BrokerApiUrl { get; set; }
|
|
||||||
|
|
||||||
public Guid BrokerId { set; get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A server that slaves to us in case of our own outage. They pull from us.
|
|
||||||
/// </summary>
|
|
||||||
public class SlaveServer
|
|
||||||
{
|
|
||||||
public Guid BrokerId { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"Logging": {
|
|
||||||
"LogLevel": {
|
|
||||||
"Default": "Information",
|
|
||||||
"Microsoft.AspNetCore": "Warning"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowedHosts": "*"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user