Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
SWA
Botolution
Platform
Commits
633f0131
Commit
633f0131
authored
Dec 05, 2021
by
Markus Esmann
Browse files
added message handler
parent
1af52b9b
Changes
17
Hide whitespace changes
Inline
Side-by-side
MatchManager.IntegrationTests/MatchControllerTests.cs
View file @
633f0131
...
...
@@ -11,6 +11,7 @@ using Botolution.ApiMsgLibrary.ApiObjects;
using
MatchManager.IntegrationTests.Fixtures
;
using
Microsoft.Extensions.DependencyInjection
;
using
MatchManager.IntegrationTests.Authentication
;
using
Botolution.ApiMsgLibrary.ApiMessages.GetMatch
;
using
Botolution.ApiMsgLibrary.ApiMessages.GetMatches
;
using
Microsoft.AspNetCore.Authorization.Policy
;
...
...
@@ -89,11 +90,11 @@ namespace MatchManager.IntegrationTests
var
contentString
=
await
response
.
Content
.
ReadAsStringAsync
();
var
matchDetails
=
JsonConvert
.
DeserializeObject
<
Match
Storag
e
>(
contentString
);
Assert
.
Equal
(
match
.
MatchId
,
matchDetails
?.
MatchId
);
Assert
.
NotNull
(
matchDetails
?.
Parameters
);
var
matchDetails
=
JsonConvert
.
DeserializeObject
<
Get
Match
Respons
e
>(
contentString
);
Assert
.
Equal
(
match
.
MatchId
,
matchDetails
?.
Match
.
MatchId
);
Assert
.
NotNull
(
matchDetails
?.
Match
.
Parameters
);
var
turnDetails
=
matchDetails
?.
Turns
[
0
].
ToObject
<
TurnParameter
>();
var
turnDetails
=
matchDetails
?.
Match
.
Turns
[
0
].
ToObject
<
TurnParameter
>();
Assert
.
Equal
(
"winner"
,
turnDetails
?.
Winner
);
}
}
...
...
MatchManager/Controllers/MatchManagerController.cs
View file @
633f0131
...
...
@@ -2,6 +2,7 @@ using MatchManager.Service;
using
Microsoft.AspNetCore.Mvc
;
using
Microsoft.AspNetCore.Authorization
;
using
Botolution.ApiMsgLibrary.ApiObjects
;
using
Botolution.ApiMsgLibrary.ApiMessages.GetMatch
;
using
Botolution.ApiMsgLibrary.ApiMessages.GetMatches
;
namespace
MatchManager.Controllers
...
...
@@ -34,7 +35,7 @@ namespace MatchManager.Controllers
{
var
matchOption
=
await
_matchManagerService
.
GetMatch
(
matchId
);
return
matchOption
.
Match
<
IActionResult
>(
Ok
,
NotFound
);
return
matchOption
.
Match
<
IActionResult
>(
(
match
)
=>
Ok
(
new
GetMatchResponse
()
{
Match
=
match
})
,
NotFound
);
}
}
}
\ No newline at end of file
MatchManager/Database/Repository/IMatchRepository.cs
View file @
633f0131
...
...
@@ -13,6 +13,6 @@ namespace MatchManager.Database.Repository
Task
<
bool
>
ExistsAsync
(
Guid
matchId
);
void
DeleteAsync
(
Guid
matchId
);
Task
DeleteAsync
(
Guid
matchId
);
}
}
MatchManager/Database/Repository/ITurnRepository.cs
View file @
633f0131
...
...
@@ -8,6 +8,6 @@ namespace MatchManager.Database.Repository
Task
<
bool
>
InsertAsync
(
Turn
turn
);
void
DeleteAllAsync
(
Guid
matchId
);
Task
DeleteAllAsync
(
Guid
matchId
);
}
}
MatchManager/Database/Repository/MatchRepository.cs
View file @
633f0131
...
...
@@ -90,7 +90,7 @@ namespace MatchManager.Database.Repository
}
}
public
async
void
DeleteAsync
(
Guid
matchId
)
public
async
Task
DeleteAsync
(
Guid
matchId
)
{
try
{
...
...
MatchManager/Database/Repository/TurnRepository.cs
View file @
633f0131
...
...
@@ -52,7 +52,7 @@ namespace MatchManager.Database.Repository
}
}
public
async
void
DeleteAllAsync
(
Guid
matchId
)
public
async
Task
DeleteAllAsync
(
Guid
matchId
)
{
try
{
...
...
MatchManager/MessageQueue/MessageHandler/AbstractMessageHandler.cs
0 → 100644
View file @
633f0131
using
MatchManager.Service
;
using
RabbitMQ.Client.Events
;
using
RabbitMQ.Client.Core.DependencyInjection.MessageHandlers
;
namespace
MatchManager.MessageQueue.MessageHandler
{
public
abstract
class
AbstractMessageHandler
:
IMessageHandler
{
protected
readonly
ILogger
Logger
;
protected
readonly
IMatchManagerService
MatchManagerService
;
protected
AbstractMessageHandler
(
ILogger
<
AbstractMessageHandler
>
logger
,
IMatchManagerService
matchManagerService
)
{
Logger
=
logger
;
MatchManagerService
=
matchManagerService
;
}
public
abstract
void
Handle
(
BasicDeliverEventArgs
eventArgs
,
string
matchingRoute
);
}
}
MatchManager/MessageQueue/MessageHandler/DeleteMatchMessageHandler.cs
0 → 100644
View file @
633f0131
using
Newtonsoft.Json
;
using
MatchManager.Service
;
using
RabbitMQ.Client.Events
;
using
RabbitMQ.Client.Core.DependencyInjection
;
using
Botolution.ApiMsgLibrary.ApiMessages.DeleteMatch
;
using
RabbitMQ.Client.Core.DependencyInjection.MessageHandlers
;
namespace
MatchManager.MessageQueue.MessageHandler
{
public
class
DeleteMatchMessageHandler
:
IMessageHandler
{
private
readonly
ILogger
<
PostMatchMessageHandler
>
_logger
;
private
readonly
IMatchManagerService
_matchManagerService
;
public
DeleteMatchMessageHandler
(
ILogger
<
PostMatchMessageHandler
>
logger
,
IMatchManagerService
matchManagerService
)
{
_logger
=
logger
;
_matchManagerService
=
matchManagerService
;
}
public
void
Handle
(
BasicDeliverEventArgs
eventArgs
,
string
matchingRoute
)
{
var
message
=
eventArgs
.
GetMessage
();
var
messageObject
=
JsonConvert
.
DeserializeObject
<
DeleteMatchRequest
>(
message
);
_logger
.
LogInformation
(
$"received delete match request:
{
message
}
"
);
_matchManagerService
.
DeleteMatch
(
messageObject
?.
MatchId
??
default
);
}
}
}
MatchManager/MessageQueue/MessageHandler/PostMatchMessageHandler.cs
View file @
633f0131
using
RabbitMQ.Client.Events
;
using
Newtonsoft.Json
;
using
MatchManager.Service
;
using
RabbitMQ.Client.Events
;
using
RabbitMQ.Client.Core.DependencyInjection
;
using
Botolution.ApiMsgLibrary.ApiMessages.PostMatch
;
using
RabbitMQ.Client.Core.DependencyInjection.MessageHandlers
;
namespace
MatchManager.MessageQueue.MessageHandler
{
public
class
PostMatchMessageHandler
:
IMessageHandler
{
private
readonly
ILogger
<
PostMatchMessageHandler
>
_logger
;
private
readonly
IMatchManagerService
_matchManagerService
;
public
PostMatchMessageHandler
(
ILogger
<
PostMatchMessageHandler
>
logger
,
IMatchManagerService
matchManagerService
)
{
_logger
=
logger
;
_matchManagerService
=
matchManagerService
;
}
public
void
Handle
(
BasicDeliverEventArgs
eventArgs
,
string
matchingRoute
)
{
return
;
var
message
=
eventArgs
.
GetMessage
();
var
messageObject
=
JsonConvert
.
DeserializeObject
<
PostMatchRequest
>(
message
);
_logger
.
LogInformation
(
$"received post match request:
{
message
}
"
);
_matchManagerService
.
InsertMatch
(
messageObject
?.
Match
);
}
}
}
MatchManager/MessageQueue/MessageHandler/PostTurnMessageHandler.cs
0 → 100644
View file @
633f0131
using
Newtonsoft.Json
;
using
MatchManager.Service
;
using
RabbitMQ.Client.Events
;
using
RabbitMQ.Client.Core.DependencyInjection
;
using
Botolution.ApiMsgLibrary.ApiMessages.PostTurn
;
using
RabbitMQ.Client.Core.DependencyInjection.MessageHandlers
;
namespace
MatchManager.MessageQueue.MessageHandler
{
public
class
PostTurnMessageHandler
:
IMessageHandler
{
private
readonly
ILogger
<
PostMatchMessageHandler
>
_logger
;
private
readonly
IMatchManagerService
_matchManagerService
;
public
PostTurnMessageHandler
(
ILogger
<
PostMatchMessageHandler
>
logger
,
IMatchManagerService
matchManagerService
)
{
_logger
=
logger
;
_matchManagerService
=
matchManagerService
;
}
public
void
Handle
(
BasicDeliverEventArgs
eventArgs
,
string
matchingRoute
)
{
var
message
=
eventArgs
.
GetMessage
();
var
messageObject
=
JsonConvert
.
DeserializeObject
<
PostTurnRequest
>(
message
);
_logger
.
LogInformation
(
$"received post turn request:
{
message
}
"
);
_matchManagerService
.
InsertTurn
(
messageObject
?.
Turn
);
}
}
}
MatchManager/MessageQueue/Producing/AbstractProducingService.cs
View file @
633f0131
...
...
@@ -7,11 +7,15 @@ namespace MatchManager.MessageQueue.Producing
public
class
AbstractProducingService
{
protected
readonly
ILogger
Logger
;
private
readonly
IQueueService
_queueService
;
private
IQueueService
?
_queueService
;
protected
AbstractProducingService
(
IQueueService
queueService
,
ILogger
<
ProducingService
>
logger
)
protected
AbstractProducingService
(
ILogger
<
ProducingService
>
logger
)
{
Logger
=
logger
;
}
public
void
SetQueueService
(
IQueueService
queueService
)
{
_queueService
=
queueService
;
}
...
...
MatchManager/MessageQueue/Producing/IProducingService.cs
View file @
633f0131
namespace
MatchManager.MessageQueue.Producing
using
Botolution.ApiMsgLibrary.ApiObjects
;
namespace
MatchManager.MessageQueue.Producing
{
public
interface
IProducingService
{
void
PostMatchToFrontend
(
bool
insertResult
);
void
SendPostMatchResponse
(
MatchDefinition
?
match
,
bool
result
);
void
SendPostTurnResponse
(
TurnObject
?
turn
,
bool
result
);
}
}
MatchManager/MessageQueue/Producing/ProducingService.cs
View file @
633f0131
using
RabbitMQ.Client.Core.DependencyInjection.Services
;
using
Newtonsoft.Json
;
using
Botolution.ApiMsgLibrary.ApiObjects
;
using
Botolution.ApiMsgLibrary.ApiMessages.PostTurn
;
using
Botolution.ApiMsgLibrary.ApiMessages.PostMatch
;
namespace
MatchManager.MessageQueue.Producing
{
public
class
ProducingService
:
AbstractProducingService
,
IProducingService
{
public
ProducingService
(
IQueueService
queueService
,
ILogger
<
ProducingService
>
logger
)
:
base
(
queueService
,
logger
)
public
ProducingService
(
ILogger
<
ProducingService
>
logger
)
:
base
(
logger
)
{
}
public
void
PostMatch
ToFrontend
(
bool
insertR
esult
)
public
void
Send
PostMatch
Response
(
MatchDefinition
?
match
,
bool
r
esult
)
{
Send
(
""
,
"amq.topic"
,
"MatchManagerQueue.MatchUpdate"
);
var
sendMsg
=
new
PostMatchResponse
()
{
Match
=
match
,
Result
=
result
};
Logger
.
LogInformation
(
$"send post match response:
{
JsonConvert
.
SerializeObject
(
sendMsg
)}
"
);
Send
(
sendMsg
,
"amq.topic"
,
$"MatchMakerQueue.PostMatchResponse"
);
if
(
result
)
{
MatchListUpdate
();
return
;
}
ErrorUpdate
(
"match insert failed"
);
}
public
void
SendPostTurnResponse
(
TurnObject
?
turn
,
bool
result
)
{
var
sendMsg
=
new
PostTurnResponse
()
{
Turn
=
turn
,
Result
=
result
};
Logger
.
LogInformation
(
$"send post turn response:
{
JsonConvert
.
SerializeObject
(
sendMsg
)}
"
);
Send
(
sendMsg
,
"amq.topic"
,
$"MatchMakerQueue.PostTurnResponse"
);
if
(
result
)
{
TurnUpdate
(
turn
!);
return
;
}
ErrorUpdate
(
$"turn insert of match
{
turn
!.
MatchId
}
failed"
);
}
private
void
MatchListUpdate
()
{
Logger
.
LogInformation
(
"match list update"
);
Send
(
""
,
"amq.topic"
,
"GuiQueue.MatchUpdate"
);
}
private
void
TurnUpdate
(
TurnObject
turnObject
)
{
Logger
.
LogInformation
(
$"turn update:
{
JsonConvert
.
SerializeObject
(
turnObject
)}
"
);
Send
(
turnObject
,
"amq.topic"
,
"GuiQueue.TurnUpdate"
);
}
private
void
ErrorUpdate
(
string
message
)
{
Logger
.
LogInformation
(
$"error update:
{
message
}
"
);
Send
(
message
,
"amq.topic"
,
"GuiQueue.ErrorUpdate"
);
}
}
}
MatchManager/Program.cs
View file @
633f0131
using
Serilog
;
using
ServiceHelper
;
using
IdentityModel
;
using
MatchManager.Service
;
using
MatchManager.Database.Context
;
using
MatchManager.Database.Settings
;
using
Microsoft.IdentityModel.Tokens
;
using
MatchManager.Database.Repository
;
using
MatchManager.MessageQueue.Consuming
;
using
MatchManager.MessageQueue.Producing
;
using
MatchManager.MessageQueue.MessageHandler
;
using
RabbitMQ.Client.Core.DependencyInjection
;
using
Microsoft.AspNetCore.Authentication.JwtBearer
;
using
Steeltoe.Extensions.Configuration.ConfigServer
;
using
IProducingService
=
MatchManager
.
MessageQueue
.
Producing
.
IProducingService
;
// Setup web builder
var
builder
=
WebApplication
.
CreateBuilder
(
args
);
// Setup Logging
builder
.
Host
.
UseSerilog
(
SerilogElasticSinkLogger
.
Configure
);
// Setup config service and configuration
builder
.
Host
.
AddConfigServer
();
var
configuration
=
builder
.
Configuration
;
// Setup Authentication and Cors
builder
.
Services
.
AddAuthentication
(
JwtBearerDefaults
.
AuthenticationScheme
).
AddJwtBearer
(
options
=>
{
options
.
Authority
=
"http://keycloak:8080/auth/realms/Botolution"
;
options
.
RequireHttpsMetadata
=
false
;
options
.
TokenValidationParameters
=
new
TokenValidationParameters
{
ValidateAudience
=
false
,
ValidateIssuer
=
false
,
NameClaimType
=
JwtClaimTypes
.
Name
,
};
});
builder
.
Services
.
AddCors
(
options
=>
namespace
MatchManager
{
options
.
AddDefaultPolicy
(
builder
=>
public
class
Program
{
builder
.
AllowAnyOrigin
();
builder
.
AllowAnyHeader
();
builder
.
AllowAnyMethod
();
});
});
// Setup RabbitMQ
var
rabbitMqSection
=
configuration
.
GetSection
(
"RabbitMq"
);
var
exchangeSection
=
configuration
.
GetSection
(
"RabbitMqExchange"
);
builder
.
Services
.
AddRabbitMqClient
(
rabbitMqSection
)
.
AddExchange
(
"amq.topic"
,
true
,
exchangeSection
)
.
AddMessageHandlerSingleton
<
PostMatchMessageHandler
>(
"*.PostMatchRequest"
);
builder
.
Services
.
AddSingleton
<
IHostedService
,
ConsumingService
>();
builder
.
Services
.
AddSingleton
<
IProducingService
,
ProducingService
>();
// Add services to DI-Container
builder
.
Services
.
Configure
<
MatchDbSettings
>(
configuration
.
GetSection
(
"MatchDatabase"
));
builder
.
Services
.
AddSingleton
<
MatchDbContext
>();
builder
.
Services
.
AddSingleton
<
ITurnRepository
,
TurnRepository
>();
builder
.
Services
.
AddSingleton
<
IMatchRepository
,
MatchRepository
>();
builder
.
Services
.
AddSingleton
<
IMatchManagerService
,
MatchManagerService
>();
builder
.
Services
.
AddControllers
();
builder
.
Services
.
AddAutoMapper
(
typeof
(
Program
));
builder
.
Services
.
AddMvc
().
AddNewtonsoftJson
();
builder
.
Services
.
AddEndpointsApiExplorer
();
// Build app
var
app
=
builder
.
Build
();
app
.
UseHttpsRedirection
();
app
.
UseAuthorization
();
app
.
UseAuthentication
();
app
.
MapControllers
();
app
.
Run
();
public
partial
class
Program
{
}
public
static
void
Main
(
string
[]
args
)
{
CreateHostBuilder
(
args
).
Build
().
Run
();
}
public
static
IHostBuilder
CreateHostBuilder
(
string
[]
args
)
=>
Host
.
CreateDefaultBuilder
(
args
)
.
ConfigureWebHostDefaults
(
webBuilder
=>
{
webBuilder
.
AddConfigServer
();
webBuilder
.
UseStartup
<
Startup
>();
})
.
UseSerilog
(
SerilogElasticSinkLogger
.
Configure
);
}
}
MatchManager/Service/IMatchManagerService.cs
View file @
633f0131
...
...
@@ -5,8 +5,14 @@ namespace MatchManager.Service
{
public
interface
IMatchManagerService
{
Task
<
IEnumerable
<
MatchDefinition
>>
GetMatchDefinitions
();
Task
InsertMatch
(
MatchStorage
?
match
);
Task
InsertTurn
(
TurnObject
?
turn
);
Task
<
Option
<
MatchStorage
>>
GetMatch
(
Guid
matchId
);
Task
<
IEnumerable
<
MatchDefinition
>>
GetMatchDefinitions
();
Task
DeleteMatch
(
Guid
matchId
);
}
}
MatchManager/Service/MatchManagerService.cs
View file @
633f0131
using
AutoMapper
;
using
LanguageExt
;
using
Newtonsoft.Json
;
using
MatchManager.Database.Model
;
using
MatchManager.Database.Repository
;
using
Botolution.ApiMsgLibrary.ApiObjects
;
using
MatchManager.MessageQueue.Producing
;
...
...
@@ -51,5 +53,47 @@ namespace MatchManager.Service
return
match
;
}
public
async
Task
InsertMatch
(
MatchStorage
?
match
)
{
if
(
match
!=
default
&&
!
await
_matchRepository
.
ExistsAsync
(
match
.
MatchId
))
{
var
dbMatch
=
_mapper
.
Map
<
Match
>(
match
);
bool
insertResult
=
await
_matchRepository
.
InsertAsync
(
dbMatch
);
_producingService
.
SendPostMatchResponse
(
match
,
insertResult
);
return
;
}
_logger
.
LogError
(
$"invalid match:
{
JsonConvert
.
SerializeObject
(
match
)}
"
);
_producingService
.
SendPostMatchResponse
(
match
,
false
);
}
public
async
Task
InsertTurn
(
TurnObject
?
turn
)
{
if
(
turn
!=
default
&&
await
_matchRepository
.
ExistsAsync
(
turn
.
MatchId
))
{
var
dbTurn
=
_mapper
.
Map
<
Turn
>(
turn
);
bool
insertResult
=
await
_turnRepository
.
InsertAsync
(
dbTurn
);
_producingService
.
SendPostTurnResponse
(
turn
,
insertResult
);
return
;
}
_logger
.
LogError
(
$"invalid turn:
{
JsonConvert
.
SerializeObject
(
turn
)}
"
);
_producingService
.
SendPostTurnResponse
(
turn
,
false
);
}
public
async
Task
DeleteMatch
(
Guid
matchId
)
{
var
deleteMatchTAsk
=
_matchRepository
.
DeleteAsync
(
matchId
);
var
deleteTurnTask
=
_turnRepository
.
DeleteAllAsync
(
matchId
);
await
Task
.
WhenAll
(
deleteMatchTAsk
,
deleteTurnTask
);
}
}
}
MatchManager/Startup.cs
0 → 100644
View file @
633f0131
using
IdentityModel
;
using
MatchManager.Service
;
using
Microsoft.IdentityModel.Tokens
;
using
MatchManager.Database.Context
;
using
MatchManager.Database.Settings
;
using
MatchManager.Database.Repository
;
using
MatchManager.MessageQueue.Producing
;
using
MatchManager.MessageQueue.Consuming
;
using
MatchManager.MessageQueue.MessageHandler
;
using
RabbitMQ.Client.Core.DependencyInjection
;
using
Microsoft.AspNetCore.Authentication.JwtBearer
;
using
RabbitMQ.Client.Core.DependencyInjection.Services
;
using
IProducingService
=
MatchManager
.
MessageQueue
.
Producing
.
IProducingService
;
namespace
MatchManager
{
public
class
Startup
{
private
readonly
IConfiguration
_configuration
;
public
Startup
(
IConfiguration
configuration
)
{
_configuration
=
configuration
;
}
public
void
ConfigureServices
(
IServiceCollection
services
)
{
// Setup Authentication and Cors
services
.
AddAuthentication
(
JwtBearerDefaults
.
AuthenticationScheme
).
AddJwtBearer
(
options
=>
{
options
.
Authority
=
"http://keycloak:8080/auth/realms/Botolution"
;
options
.
RequireHttpsMetadata
=
false
;
options
.
TokenValidationParameters
=
new
TokenValidationParameters
{
ValidateAudience
=
false
,
ValidateIssuer
=
false
,
NameClaimType
=
JwtClaimTypes
.
Name
,
};
});
services
.
AddCors
(
options
=>
{
options
.
AddDefaultPolicy
(
builder
=>
{
builder
.
AllowAnyOrigin
();
builder
.
AllowAnyHeader
();
builder
.
AllowAnyMethod
();
});
});
// Setup RabbitMQ
var
rabbitMqSection
=
_configuration
.
GetSection
(
"RabbitMq"
);
var
exchangeSection
=
_configuration
.
GetSection
(
"RabbitMqExchange"
);
services
.
AddRabbitMqClient
(
rabbitMqSection
)
.
AddExchange
(
"amq.topic"
,
true
,
exchangeSection
)
.
AddMessageHandlerSingleton
<
PostMatchMessageHandler
>(
"*.PostMatchRequest"
)
.
AddMessageHandlerSingleton
<
DeleteMatchMessageHandler
>(
"*.DeleteMatchRequest"
)
.
AddMessageHandlerSingleton
<
PostTurnMessageHandler
>(
"*.PostTurnRequest"
);
services
.
AddSingleton
<
IHostedService
,
ConsumingService
>();
services
.
AddSingleton
<
IProducingService
,
ProducingService
>();
// Add services to DI-Container
services
.
Configure
<
MatchDbSettings
>(
_configuration
.
GetSection
(
"MatchDatabase"
));
services
.
AddSingleton
<
MatchDbContext
>();
services
.
AddSingleton
<
ITurnRepository
,
TurnRepository
>();
services
.
AddSingleton
<
IMatchRepository
,
MatchRepository
>();
services
.
AddSingleton
<
IMatchManagerService
,
MatchManagerService
>();
services
.
AddControllers
();
services
.
AddAutoMapper
(
typeof
(
Startup
));
services
.
AddMvc
().
AddNewtonsoftJson
();
services
.
AddEndpointsApiExplorer
();
}
public
void
Configure
(
IApplicationBuilder
app
,
IWebHostEnvironment
env
,
IQueueService
queueService
,
IProducingService
producingService
)
{
(
producingService
as
AbstractProducingService
)?.
SetQueueService
(
queueService
);
app
.
UseRouting
();
app
.
UseCors
();
app
.
UseAuthorization
();
app
.
UseAuthentication
();
app
.
UseEndpoints
(
endpoints
=>
{
endpoints
.
MapControllers
();
});
}
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment