Lesson 35 - Get Compute Auth Token Working

This commit is contained in:
Norman Lansing
2026-02-28 12:32:28 -05:00
parent 1d477ee42a
commit 4fde462bce
7743 changed files with 1397833 additions and 18 deletions

View File

@@ -0,0 +1,177 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -0,0 +1,5 @@
Amazon GameLift SDK
Copyright 2016-2025 Amazon.com, Inc. or its affiliates. All Rights Reserved.
This product includes software developed by Amazon Technologies, Inc (http://www.amazon.com/).

View File

@@ -0,0 +1,122 @@
# Amazon GameLift Servers SDK for Unreal Engine
The Amazon GameLift Servers SDK for Unreal Engine is compatible with UE5 versions (5.0, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7), and supports development and packaging of game servers for Windows or Linux, as well as game clients for any Unreal-supported platform.
The SDK supports both x64 and ARM architectures, with ARM architecture being supported starting from Unreal Engine version 5.0 and above.
## Install the SDK for Unreal Engine
Follow these steps to set up the SDK for Unreal Engine and add it to your Unreal Engine editor.
### Step 1: Install prerequisites
Youll need the following tools to install and run the plugin with your Unreal projects.
* An AWS account to use with Amazon GameLift Servers. To use the plugin guided workflows, you need a user profile with your AWS account and access credentials. See [Set up an AWS account](https://docs.aws.amazon.com/gamelift/latest/developerguide/setting-up-aws-login.html) for help with these steps:
* Sign up for an AWS account.
* Create a user with permissions to use Amazon GameLift Servers.
* Set up programmatic access with long-term IAM credentials.
* A source-built version of the Unreal Engine editor. You need a source-built editor to package a multiplayer game server build. See these Unreal Engine documentation topics:
* [Accessing Unreal Engine source code on GitHub](https://www.unrealengine.com/ue-on-github) (requires GitHub and Epic Games accounts).
* [Building Unreal Engine from Source](https://docs.unrealengine.com/5.3/en-US/building-unreal-engine-from-source/)
* A multiplayer game project with C++ game code. (Blueprint-only projects arent compatible with the plugin.) If you dont have a project in progress, use one of the Unreal Engine sample games such as the [Third Person Template](https://dev.epicgames.com/documentation/en-us/unreal-engine/third-person-template-in-unreal-engine).
If you're starting a new Unreal project, create a game using the Third Person template and use the following settings:
* C++
* With starter content
* Desktop
* Custom project name (examples in this README use the name `GameLiftUnrealApp`)
* [Microsoft Visual Studio](https://visualstudio.microsoft.com/vs/) 2019 or newer.
* [Unreal Engine cross-compiling toolchain](https://dev.epicgames.com/documentation/en-us/unreal-engine/linux-development-requirements-for-unreal-engine#cross-compiletoolchain). This tool is required only if youre building a Linux game server.
### Step 2: Get the plugin
1. Download the plugin `GameLift-Cpp-ServerSDK-UnrealPlugin-<version>.zip` from the repositorys [**Releases**](https://github.com/amazon-gamelift/amazon-gamelift-plugin-unreal/releases) page or clone the repository if you plan to customize it.
2. If you downloaded the plugin from the [**Releases**](https://github.com/amazon-gamelift/amazon-gamelift-plugin-unreal/releases) page, unzip the downloaded file `GameLift-Cpp-ServerSDK-UnrealPlugin-<version>.zip`.
3. If you cloned the repository, run the following command in the root directory of the repository:
For Linux or Max:
```sh
chmod +x setup.sh
sh setup.sh
```
For Windows:
```
powershell -file setup.ps1
```
Once completed, the plugin is ready to be added to an Unreal game project.
### Step 3: Add the plugin to your Unreal game project
1. Locate the root folder of your Unreal game project. Look for a subfolder named `Plugins`. If it doesnt exist, create it.
2. Copy the entire `GameLiftServerSDK/` folder, either from this repository (after running the setup script) or from the unzipped release bundle, into the `Plugins` folder in your game project.
3. Open the `.uproject` file for your game project. Add the `GameLiftServerSDK` to the `Plugins` section:
```
"Plugins": [
......
{
"Name": "GameLiftServerSDK",
"Enabled": true
}
]
```
4. In a file browser, select the game project `.uproject` file and choose the option **Switch Unreal Engine Version**. Set the game project to use the source-built Unreal Editor (as mentioned in Step 1).
5. (Windows) In the game project root folder, right-click the `.uproject` file and choose the option to generate project files. Open the solution ( `*.sln`) file and build or rebuild the project.
## Next steps: Integrate your game server and deploy for hosting
After you add the server SDK to your game project, see these Amazon GameLift Servers documentation topics for help with integrating your game code and preparing your game server to work with Amazon GameLift Servers.
* [Configure your game project for the server SDK](https://docs.aws.amazon.com/gamelift/latest/developerguide/integration-engines-setup-unreal.html#integration-engines-setup-unreal-setup)
* [Integrate Amazon GameLift Servers functionality into your game server code](https://docs.aws.amazon.com/gamelift/latest/developerguide/integration-engines-setup-unreal.html#integration-engines-setup-unreal-code)
* [Package your game build files](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-build-packaging.html)
* [Set up local testing with an Anywhere fleet](https://docs.aws.amazon.com/gamelift/latest/developerguide/integration-testing.html)
* Deploy your game server to the cloud with managed EC2
* [Deploy a custom server build for Amazon GameLift Servers hosting](https://docs.aws.amazon.com/gamelift/latest/developerguide/gamelift-build-cli-uploading.html)
* [Create an Amazon GameLift Servers managed EC2 fleet](https://docs.aws.amazon.com/gamelift/latest/developerguide/fleets-creating.html)
* Deploy your game server to the cloud with managed containers
* [Build a container image for Amazon GameLift Servers](https://docs.aws.amazon.com/gamelift/latest/developerguide/containers-prepare-images.html)
* [Create an Amazon GameLift Servers managed container fleet](https://docs.aws.amazon.com/gamelift/latest/developerguide/containers-build-fleet.html)
## Metrics
This telemetry metrics solution enables the feature to collect and ship telemetry metrics from your game servers hosted on Amazon GameLift Servers to AWS services for monitoring and observability. For detailed setup and usage instructions, see [METRICS.md](../TelemetryMetrics/METRICS.md).
![Telemetry Metrics on Amazon Grafana Dashboard](../TelemetryMetrics/telemetry_metrics.png)
## Troubleshoot plugin installation
#### Issue: When rebuilding the game projects solution file after adding the plugin, I get some compile errors.
**Resolution:** Add the following line to your `<ProjectName>Editor.Target.cs` file to disable adaptive unity build, which may cause conflicts:
```
bUseAdaptiveUnityBuild = false;
```
## Metrics
The Amazon GameLift Servers SDK for Unreal Engine provides a comprehensive metrics system for collecting and sending custom metrics from your game servers to Amazon GameLift. These metrics can be integrated with various visualization and aggregation tools including Amazon Managed Grafana, Prometheus, Amazon CloudWatch, and other monitoring platforms.
See below for a simple usage guide and see [CUSTOM_METRICS.md](../TelemetryMetrics/CUSTOM_METRICS.md) for a detailed API description.
## Quick Start
### Initialize the GameLift Metrics SDK
1. Include GameLiftMetrics.h at the top of your game mode source. `#include "GameLiftMetrics.h"`
2. Initialize the GameLift Metrics SDK
```c
FGameLiftGenericOutcome InitSdkOutcome = GameLiftSdkModule->InitSDK(ServerParametersForAnywhere);
// Initialize the GameLift metrics SDK
FGameLiftMetricsModule::Load().Initialize();
if (InitSdkOutcome.IsSuccess())
{
UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_GREEN);
UE_LOG(GameServerLog, Log, TEXT("GameLift InitSDK succeeded!"));
UE_LOG(GameServerLog, SetColor, TEXT("%s"), COLOR_NONE);
}
else
...
```

View File

@@ -0,0 +1,3 @@
- Support for Windows and Linux operating systems.
- Support for Unreal Engine 4.13 or later
- Dependency on GameLift C++ Server SDK 3.1.5

View File

@@ -0,0 +1,3 @@
- Updated Google Protobuf to v3.3
- TargetInfo updated to ReadOnlyTargetRules for UE4.16-4.18
- Dependency on GameLift C++ Server SDK 3.2.0

View File

@@ -0,0 +1 @@
- New API GetTerminationTime

View File

@@ -0,0 +1,2 @@
- Support for Matchmaking backfill APIs
- Support for 4.19, 4.20 and 4.21 versions of Unreal Engine.

View File

@@ -0,0 +1,2 @@
- Support for 4.22, 4.23 and 4.24 versions of Unreal Engine.
- Bug fixes

View File

@@ -0,0 +1,2 @@
- Add missing delegate for OnUpdateGameSession
- Deprecate TerminateGameSession API

View File

@@ -0,0 +1 @@
- Support for Unreal Engine 4.25 and 4.25 plus

View File

@@ -0,0 +1,4 @@
- Support for Unreal Engine 4.26
- Support for DescribePlayerSessions API
- Support for GetInstanceCertificate API
- Bug fixes

View File

@@ -0,0 +1,6 @@
- Support for Unreal Engine 5.1.1
- Support for Amazon GameLift SDK 5.0
- Added support for new SDK 5.0 APIs
- Removed APIs no longer supported in SDK 5.0
- Changed InitSDK to reflect new FServerParameter requirement
- Added additional GameLift ERROR types

View File

@@ -0,0 +1,5 @@
- Add InitSDK() API with no parameters. This API reads server parameters from environment variables, such as fleet ID,
compute name, WebSocket URL, process ID and auth token. This API simplifies SDK initialization in Amazon GameLift
managed EC2 fleets. For initialization in Amazon GameLift Anywhere fleets, call InitSDK() with the ServerParameters parameter.
- Update ProcessReady() to retain a copy of FProcessParameters. This fixes segfaults that occur when Amazon GameLift C++ SDK
attempts to invoke user callbacks after FProcessParameters is freed in memory.

View File

@@ -0,0 +1,2 @@
- Improved the reliability of the SDK by adding automatic reconnection in the event of network interruption.
- Fixed a problem with converting the expiration time returned from GetFleetRoleCredentials.

View File

@@ -0,0 +1,2 @@
- Introduced logging capabilities for the C++ Server SDK; logs are now accessible.
- Improved the reliability of SDK message transmission by implementing more robust reconnection mechanisms in the event of network interruptions or random message drops.

View File

@@ -0,0 +1,2 @@
- Added support for GameLift container fleets.
- Added the option to initialize the SDK using AWS Region and AWS Credentials, providing an alternative to AuthToken based authentication.

View File

@@ -0,0 +1,15 @@
- Removes the need to manually download and build the server SDK. The new plugin version now includes the server SDK source code, which is automatically built along with the Unreal project using the Unreal Build Tool.
- CMake is no longer a prerequisite.
- Removes the need to install OpenSSL. The new plugin uses OpenSSL source in the Unreal Engine with static linking.
- When packaging a build for Amazon GameLift Servers, you no longer need to include the libcrypto and libssl files into your game server build.
- Integrates the Unreal cross-compiling toolkit that enables cross-compiled builds on native Windows and Linux. Removes the need for special steps, including the Amazon GameLift Servers toolkit to generate Linux libraries.
- Adds the missing Destroy() action.
- Supports ARM game server builds for UE5.
- Fixes MSVC 5130 Macro Warnings.
- Merges the two Unreal plugins (lightweight and standalone) into one repository.
- Adds or improves client-side validation in all server SDK actions.
- Adds more specific and improved error responses to API errors.
- Fixes an edge case in GetFleetRoleCredentials() that causes game server crash.
- Adds default logic to the onProcessTerminate() callback that terminates the game server process when this callback is invoked.
- Adds idempotency token support to allow InitSDK() retries to succeed.
- Includes autoBackfillMode in the data passed in the OnUpdateGameSession() callback.

View File

@@ -0,0 +1,2 @@
- Support the Unreal Plugin and Server SDK on Unreal Engine 5.6
- Fix compilation errors when packaging Android client targets.

View File

@@ -0,0 +1 @@
- Isolate the Asio namespace in the ServerSDK module to improve packaging compatibility with other modules

View File

@@ -0,0 +1,2 @@
- Adds support for publishing built-in and custom telemetry metrics, with pre-built dashboards for visualizing usage data.
- Fixes a potential null pointer exception in the client logging when attempting to re-establish the WebSocket connection.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,34 @@
/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0
*/
using UnrealBuildTool;
public class GameLiftMetrics : ModuleRules
{
public GameLiftMetrics(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableExceptions = true;
bUseRTTI = false;
PublicDependencyModuleNames.AddRange(
new string[]
{
"Core",
"GameLiftServerSDK",
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
"CoreUObject",
"Core",
"Engine",
"Sockets",
"Networking",
}
);
}
}

View File

@@ -0,0 +1,319 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "GameLiftMetrics.h"
#include "GameLiftMetricsTypes.h"
#include "GameLiftMetricsConfig.h"
#include "UnrealStatCollector.h"
#include "TickableCollector.h"
#include "GameLiftServerSDK.h"
#include "aws/gamelift/server/GameLiftServerAPI.h"
#include "Sockets.h"
#include "SocketSubsystem.h"
#include "IPAddress.h"
#include "Common/UdpSocketBuilder.h"
#include <aws/gamelift/metrics/GlobalMetricsProcessor.h>
#if PLATFORM_LINUX
#include <unistd.h>
#endif
FString FGameLiftMetricsModule::CurrentGameSessionId;
FThreadSafeCounter FGameLiftMetricsModule::CurrentPlayerCount(0);
FGameLiftMetricsModule& FGameLiftMetricsModule::Load()
{
return FModuleManager::LoadModuleChecked<FGameLiftMetricsModule>(FName("GameLiftMetrics"));
}
FGameLiftMetricsModule& FGameLiftMetricsModule::Get()
{
return FModuleManager::GetModuleChecked<FGameLiftMetricsModule>(FName("GameLiftMetrics"));
}
FGameLiftMetricsModule* FGameLiftMetricsModule::GetPtr()
{
return FModuleManager::GetModulePtr<FGameLiftMetricsModule>(FName("GameLiftMetrics"));
}
#if WITH_GAMELIFT_METRICS
namespace
{
const TCHAR* GAMELIFT_METRICS_FLEET_ID = TEXT("GAMELIFT_SDK_FLEET_ID");
const TCHAR* GAMELIFT_METRICS_PROCESS_ID = TEXT("GAMELIFT_SDK_PROCESS_ID");
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMaxPlayers, "server_max_players", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMaxPlayers);
GAMELIFT_METRICS_DECLARE_GAUGE(MetricPlayers, "server_players", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DEFINE_GAUGE(MetricPlayers);
GAMELIFT_METRICS_DECLARE_COUNTER(MetricServerCrashes, "game_server_crashes", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DEFINE_COUNTER(MetricServerCrashes);
}
void FGameLiftMetricsModule::StartupModule() {}
void FGameLiftMetricsModule::ShutdownModule()
{
// Terminate here just in case the user forgot.
Terminate();
}
void FGameLiftMetricsModule::StartMetricsCollector()
{
FPlatformMisc::SetCrashHandler(&FGameLiftMetricsModule::CrashHandler);
bMetricsRunning = true;
auto *Module = FGameLiftMetricsModule::GetPtr();
if (!Module)
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("GameLiftMetrics module no longer loaded."));
return;
}
/*
* Begin ticking the collector.
*/
const bool bComputeFallbackGameThreadTime = !STATS;
Module->Collector.Reset(new FTickableCollector(bComputeFallbackGameThreadTime));
/*
* Create stats collector.
*/
if (STATS)
{
Module->UnrealStatCollector = TSharedPtr<FUnrealStatCollector>(new FUnrealStatCollector());
Module->UnrealStatCollector->Subscribe();
}
UE_LOG(LogGameLiftMetrics, Log, TEXT("GameLift metrics initialized successfully."));
}
void FGameLiftMetricsModule::Initialize()
{
if (GIsEditor) return;
// Initialize GameLift Server SDK metrics
auto& ServerSDKModule = FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>("GameLiftServerSDK");
auto InitResult = ServerSDKModule.InitMetrics();
if (!InitResult.IsSuccess())
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("Failed to initialize GameLift metrics: %s"), *InitResult.GetError().m_errorMessage);
return;
}
StartMetricsCollector();
}
void FGameLiftMetricsModule::Initialize(const FMetricsParameters& metricsParameters)
{
if (GIsEditor) return;
// Initialize GameLift Server SDK metrics with parameters
auto& ServerSDKModule = FModuleManager::LoadModuleChecked<FGameLiftServerSDKModule>("GameLiftServerSDK");
auto InitResult = ServerSDKModule.InitMetrics(metricsParameters);
if (!InitResult.IsSuccess())
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("Failed to initialize GameLift metrics with parameters: %s"), *InitResult.GetError().m_errorMessage);
return;
}
StartMetricsCollector();
}
void FGameLiftMetricsModule::Terminate()
{
if (GIsEditor) { return; }
if (UnrealStatCollector)
{
UnrealStatCollector->Unsubscribe();
UnrealStatCollector.Reset();
}
Collector.Reset();
UE_LOG(LogGameLiftMetrics, Log, TEXT("GameLift metrics terminated successfully."));
}
void FGameLiftMetricsModule::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& Session)
{
if (GIsEditor) { return; }
// Store the session ID regardless of metrics being enabled
CurrentGameSessionId = FString(Session.GetGameSessionId());
CurrentPlayerCount.Set(0);
const UGameLiftMetricsConfig& Config = UGameLiftMetricsConfig::Get();
if (!Config.bEnableMetrics)
{
UE_LOG(LogGameLiftMetrics, Verbose, TEXT("Metrics disabled: Skipping OnStartGameSession metrics"));
return;
}
GAMELIFT_METRICS_SET(MetricMaxPlayers, Session.GetMaximumPlayerSessionCount());
GAMELIFT_METRICS_RESET(MetricPlayers);
}
void FGameLiftMetricsModule::OnAcceptPlayerSession()
{
if (GIsEditor) { return; }
// Always track player count even if metrics are disabled
int32 NewPlayerCount = CurrentPlayerCount.Increment();
const UGameLiftMetricsConfig& Config = UGameLiftMetricsConfig::Get();
if (!Config.bEnableMetrics)
{
return;
}
GAMELIFT_METRICS_SET(MetricPlayers, NewPlayerCount);
}
void FGameLiftMetricsModule::OnRemovePlayerSession()
{
if (GIsEditor) { return; }
// Always track player count even if metrics are disabled
int32 NewPlayerCount = CurrentPlayerCount.Decrement();
if (NewPlayerCount < 0)
{
CurrentPlayerCount.Set(0);
NewPlayerCount = 0;
}
const UGameLiftMetricsConfig& Config = UGameLiftMetricsConfig::Get();
if (!Config.bEnableMetrics)
{
return;
}
GAMELIFT_METRICS_SET(MetricPlayers, NewPlayerCount);
}
void FGameLiftMetricsModule::ReEmitMetrics()
{
if (GIsEditor) { return; }
const UGameLiftMetricsConfig& Config = UGameLiftMetricsConfig::Get();
if (!Config.bEnableMetrics)
{
return;
}
GAMELIFT_METRICS_SET(MetricPlayers, CurrentPlayerCount.GetValue());
}
void FGameLiftMetricsModule::CrashHandler(const FGenericCrashContext& GenericContext)
{
UE_LOG(LogGameLiftMetrics, Log, TEXT("Server crashed, CrashHandler being called..."));
const UGameLiftMetricsConfig& Config = UGameLiftMetricsConfig::Get();
if (!Config.bEnableMetrics)
{
UE_LOG(LogGameLiftMetrics, Log, TEXT("Metrics disabled: Skipping crash metrics"));
return;
}
if (!CurrentGameSessionId.IsEmpty())
{
UE_LOG(LogGameLiftMetrics, Log, TEXT("Incrementing crash metrics for session: %s"), *CurrentGameSessionId);
GAMELIFT_METRICS_INCREMENT(MetricServerCrashes);
GAMELIFT_METRICS_TAG_SET(MetricServerCrashes, "game_session_id", TCHAR_TO_UTF8(*CurrentGameSessionId));
UE_LOG(LogGameLiftMetrics, Log, TEXT("Crash metrics incremented"));
// Force process the metrics
UE_LOG(LogGameLiftMetrics, Log, TEXT("Sending crash metrics..."));
Aws::GameLift::Metrics::MetricsProcess();
// Small sleep to allow the metrics to be sent
UE_LOG(LogGameLiftMetrics, Log, TEXT("Waiting for metrics to send..."));
FPlatformProcess::Sleep(0.2f);
UE_LOG(LogGameLiftMetrics, Log, TEXT("Crash metrics incremented and processed"));
}
else
{
UE_LOG(LogGameLiftMetrics, Warning, TEXT("Server crashed with no active game session"));
}
}
bool FGameLiftMetricsModule::SetMetricsEnabled(bool bEnable)
{
if (GIsEditor)
{
UE_LOG(LogGameLiftMetrics, Warning, TEXT("Cannot enable/disable metrics in editor - only applicable in game server"));
return false;
}
// If the state is already what's requested, no change needed
if (bEnable == bMetricsRunning)
{
UE_LOG(LogGameLiftMetrics, Log, TEXT("Metrics already %s, no change needed"),
bEnable ? TEXT("enabled") : TEXT("disabled"));
return true;
}
// Get current configuration and check current state
UGameLiftMetricsConfig* Config = const_cast<UGameLiftMetricsConfig*>(&UGameLiftMetricsConfig::Get());
if (bEnable)
{
// Enable metrics
UE_LOG(LogGameLiftMetrics, Log, TEXT("Enabling GameLift metrics at runtime"));
// Initialize with default parameters
Initialize();
// Flag is set inside Initialize method based on success
return bMetricsRunning;
}
else
{
// Disable metrics
UE_LOG(LogGameLiftMetrics, Log, TEXT("Disabling GameLift metrics at runtime"));
// Terminate metrics system
Terminate();
Config->bEnableMetrics = false;
bMetricsRunning = false;
return true;
}
}
bool FGameLiftMetricsModule::IsMetricsEnabled() const
{
return bMetricsRunning;
}
#else
void FGameLiftMetricsModule::StartupModule() {}
void FGameLiftMetricsModule::ShutdownModule() {}
void FGameLiftMetricsModule::Initialize() {}
void FGameLiftMetricsModule::Initialize(const FMetricsParameters& metricsParameters) {}
void FGameLiftMetricsModule::Terminate() {}
void FGameLiftMetricsModule::OnStartGameSession(const Aws::GameLift::Server::Model::GameSession& Session) {}
void FGameLiftMetricsModule::OnAcceptPlayerSession() {}
void FGameLiftMetricsModule::OnRemovePlayerSession() {}
void FGameLiftMetricsModule::ReEmitMetrics() {}
bool FGameLiftMetricsModule::SetMetricsEnabled(bool bEnable) { return false; }
bool FGameLiftMetricsModule::IsMetricsEnabled() const { return false; }
#endif // WITH_GAMELIFT_METRICS
IMPLEMENT_MODULE(FGameLiftMetricsModule, GameLiftMetrics)

View File

@@ -0,0 +1,21 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "GameLiftMetricsConfig.h"
const UGameLiftMetricsConfig& UGameLiftMetricsConfig::Get()
{
UGameLiftMetricsConfig* CDO = Cast<UGameLiftMetricsConfig>(StaticClass()->GetDefaultObject());
check(IsValid(CDO));
return *CDO;
}

View File

@@ -0,0 +1,15 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "GameLiftMetricsTypes.h"
DEFINE_LOG_CATEGORY(LogGameLiftMetrics);

View File

@@ -0,0 +1,50 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "MemoryStats.h"
// Windows headers define GetObject as a macro (GetObjectW) which conflicts with
// Unreal's FUObjectItem::GetObject() method. Undefine it after includes.
#ifdef _WIN32
#ifdef GetObject
#undef GetObject
#endif
#endif
#include "Engine.h"
#include "EngineStats.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryPhysicalTotal);
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryPhysicalAvailable);
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryPhysicalUsed);
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryVirtualTotal);
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryVirtualAvailable);
GAMELIFT_METRICS_DEFINE_GAUGE(MetricMemoryVirtualUsed);
}
}
}
void FMemoryStats::Collect()
{
auto MemoryStats = FPlatformMemory::GetStats();
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryPhysicalTotal, MemoryStats.TotalPhysical);
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryPhysicalAvailable, MemoryStats.AvailablePhysical);
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryPhysicalUsed, MemoryStats.UsedPhysical);
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryVirtualTotal, MemoryStats.TotalVirtual);
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryVirtualAvailable, MemoryStats.AvailableVirtual);
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricMemoryVirtualUsed, MemoryStats.UsedVirtual);
}

View File

@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "GameLiftMetricsTypes.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryPhysicalTotal, "server_mem_physical_total", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryPhysicalAvailable, "server_mem_physical_available", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryPhysicalUsed, "server_mem_physical_used", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryVirtualTotal, "server_mem_virtual_total", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryVirtualAvailable, "server_mem_virtual_available", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_GAUGE(MetricMemoryVirtualUsed, "server_mem_virtual_used", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
}
}
}
class FMemoryStats
{
public:
void Collect();
};

View File

@@ -0,0 +1,114 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "NetworkStats.h"
// Windows headers define GetObject as a macro (GetObjectW) which conflicts with
// Unreal's FUObjectItem::GetObject() method. Undefine it after includes.
#ifdef _WIN32
#ifdef GetObject
#undef GetObject
#endif
#endif
#include "Engine/NetDriver.h"
#include "Engine.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DEFINE_GAUGE(MetricConnectionCount);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricBytesIn);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricBytesOut);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricPacketsIn);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricPacketsInLost);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricPacketsOut);
GAMELIFT_METRICS_DEFINE_COUNTER(MetricPacketsOutLost);
}
}
}
FNetworkStats::FNetworkStats()
{
if (auto NetDriver = GetNetDriver())
{
LastInBytes = NetDriver->InTotalBytes;
LastOutBytes = NetDriver->OutTotalBytes;
LastInPackets = NetDriver->InTotalPackets;
LastOutPackets = NetDriver->OutTotalPackets;
LastInPacketsLost = NetDriver->InTotalPacketsLost;
LastOutPacketsLost = NetDriver->OutTotalPacketsLost;
}
}
void FNetworkStats::Collect()
{
if (auto NetDriver = GetNetDriver())
{
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricBytesIn, NetDriver->InTotalBytes - LastInBytes);
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricBytesOut, NetDriver->OutTotalBytes - LastOutBytes);
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricPacketsIn, NetDriver->InTotalPackets - LastInPackets);
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricPacketsOut, NetDriver->OutTotalPackets - LastOutPackets);
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricPacketsInLost, NetDriver->InTotalPacketsLost - LastInPacketsLost);
GAMELIFT_METRICS_ADD(Aws::GameLift::Metrics::MetricPacketsOutLost, NetDriver->OutTotalPacketsLost - LastOutPacketsLost);
LastInBytes = NetDriver->InTotalBytes;
LastOutBytes = NetDriver->OutTotalBytes;
LastInPackets = NetDriver->InTotalPackets;
LastOutPackets = NetDriver->OutTotalPackets;
LastInPacketsLost = NetDriver->InTotalPacketsLost;
LastOutPacketsLost = NetDriver->OutTotalPacketsLost;
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricConnectionCount, NetDriver->ClientConnections.Num());
}
else
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("Net driver is null. Cannot log network metrics."));
}
}
const UNetDriver* FNetworkStats::GetNetDriver() const
{
UEngine* Engine = GEngine;
if (!IsValid(Engine))
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("Engine pointer is not valid when retrieving net driver."));
return nullptr;
}
const auto& WorldContexts = Engine->GetWorldContexts();
if (WorldContexts.Num() == 0)
{
// no worlds are loaded
// generally can only be true before everything is fully initialized
UE_LOG(LogGameLiftMetrics, Error, TEXT("No world is loaded when retrieving net driver."));
return nullptr;
}
// Only one world context should be present outside Editor.
// (editor has multiple)
// Refer to FWorldContext comment in Engine.h
const FWorldContext& WorldContext = WorldContexts[0];
check(WorldContext.WorldType == EWorldType::Game);
// In theory multiple net drivers might be present.
// One will be for gameplay but additional ones might be opened for non-gameplay traffic.
// Might be null during initialisation.
if (WorldContext.ActiveNetDrivers.Num() == 0)
{
UE_LOG(LogGameLiftMetrics, Error, TEXT("No active net drivers. Cannot acquire network metrics."));
return nullptr;
}
return WorldContext.ActiveNetDrivers[0].NetDriver;
}

View File

@@ -0,0 +1,53 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "GameLiftMetricsTypes.h"
class UNetDriver;
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DECLARE_GAUGE(MetricConnectionCount, "server_connections", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricBytesIn, "server_bytes_in", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricBytesOut, "server_bytes_out", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricPacketsIn, "server_packets_in", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricPacketsInLost, "server_packets_in_lost", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricPacketsOut, "server_packets_out", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
GAMELIFT_METRICS_DECLARE_COUNTER(MetricPacketsOutLost, "server_packets_out_lost", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
}
}
}
class FNetworkStats
{
public:
FNetworkStats();
void Collect();
private:
const UNetDriver* GetNetDriver() const;
private:
int32 LastInBytes = 0;
int32 LastOutBytes = 0;
int32 LastInPackets = 0;
int32 LastOutPackets = 0;
int32 LastInPacketsLost = 0;
int32 LastOutPacketsLost = 0;
};

View File

@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "TickableCollector.h"
#include "TimeStats.h"
#include "GameLiftMetrics.h"
#include "Misc/App.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DEFINE_GAUGE(MetricServerUp);
}
}
}
#if WITH_GAMELIFT_METRICS
void FTickableCollector::Tick(float)
{
GAMELIFT_METRICS_SET(Aws::GameLift::Metrics::MetricServerUp, 1);
NetworkStats.Collect();
MemoryStats.Collect();
const double DeltaTime = FApp::GetDeltaTime();
GAMELIFT_METRICS_SET_SEC(Aws::GameLift::Metrics::MetricGameDeltaTime, DeltaTime);
if (bComputeFallbackGameThreadTime)
{
const double EstimatedGameThreadTime = DeltaTime - FApp::GetIdleTime();
GAMELIFT_METRICS_SET_SEC(Aws::GameLift::Metrics::MetricGameTickTime, EstimatedGameThreadTime);
}
// Re-emit specific metrics so that they don't go stale.
// Grafana reports no data for the metric after 5 minutes of it being stale.
FGameLiftMetricsModule::Get().ReEmitMetrics();
Aws::GameLift::Metrics::MetricsProcess();
}
#else
void FTickableCollector::Tick(float) {}
#endif // WITH_GAMELIFT_METRICS
TStatId FTickableCollector::GetStatId() const
{
return TStatId{};
}

View File

@@ -0,0 +1,53 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "CoreMinimal.h"
#include "Tickable.h"
#include "GameLiftMetricsTypes.h"
#include "NetworkStats.h"
#include "MemoryStats.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DECLARE_GAUGE(MetricServerUp, "server_up", Aws::GameLift::Metrics::Server, Aws::GameLift::Metrics::SampleAll());
}
}
}
class FTickableCollector : public FTickableGameObject
{
public:
FTickableCollector(bool bComputeFallbackGameThreadTime)
: bComputeFallbackGameThreadTime(bComputeFallbackGameThreadTime) {}
// FTickableGameObject
virtual void Tick(float) override;
virtual bool IsTickable() const override { return true; }
virtual bool IsTickableWhenPaused() const override { return true; }
virtual bool IsTickableInEditor() const override { return false; }
virtual ETickableTickType GetTickableTickType() const override { return ETickableTickType::Always; }
virtual TStatId GetStatId() const override;
// ~FTickableGameObject
private:
bool bComputeFallbackGameThreadTime = false;
FNetworkStats NetworkStats;
FMemoryStats MemoryStats;
};

View File

@@ -0,0 +1,24 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "TimeStats.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
GAMELIFT_METRICS_DEFINE_TIMER(MetricGameDeltaTime);
GAMELIFT_METRICS_DEFINE_TIMER(MetricGameTickTime);
GAMELIFT_METRICS_DEFINE_TIMER(MetricWorldTickTime);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "GameLiftMetricsTypes.h"
namespace Aws {
namespace GameLift {
namespace Metrics {
/**
* Server time-step in milliseconds.
*
* This is the time between consecutive ticks.
*
* When the server is under performing, this will exceed the target tick rate,
* otherwise it should hover in its vicinity.
*
* To compute the tick rate, compute the reciprocal: (1000 / server_delta_time)
*/
GAMELIFT_METRICS_DECLARE_TIMER(
MetricGameDeltaTime, "server_delta_time",
Aws::GameLift::Metrics::Server,
Aws::GameLift::Metrics::SampleAll(),
Aws::GameLift::Metrics::Percentiles(0.5, 0.9, 0.95)
);
/**
* The time it takes to process a single tick.
*
* A subset of delta time.
* server_tick_time <= server_delta_time at all times. Typically (much) smaller.
*
* This is the time it takes to actually process the tick. The remaining
* time-step duration is spent waiting for the next tick.
*/
GAMELIFT_METRICS_DECLARE_TIMER(
MetricGameTickTime, "server_tick_time",
Aws::GameLift::Metrics::Server,
Aws::GameLift::Metrics::SampleAll(),
Aws::GameLift::Metrics::Percentiles(0.5, 0.9, 0.95)
);
/**
* The time it takes to process the world update.
*
* A subset of tick time.
*
* This is the time it takes to process the Actors and Blueprints in the
* currently loaded Map. The remainder of server_tick_time is spent in
* other engine subsystems like network replication or physics.
*
* Only available in Debug or Development builds, or Shipping builds with
* USE_FORCE_STATS=1.
*/
GAMELIFT_METRICS_DECLARE_TIMER(
MetricWorldTickTime,
"server_world_tick_time",
Aws::GameLift::Metrics::Server,
Aws::GameLift::Metrics::SampleAll(),
Aws::GameLift::Metrics::Percentiles(0.5, 0.9, 0.95)
);
}
}
}

View File

@@ -0,0 +1,136 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "UnrealStatCollector.h"
#include "Runtime/Launch/Resources/Version.h"
#include "TimeStats.h"
#include "Async/TaskGraphInterfaces.h"
#include "Stats/Stats.h"
#include "Stats/StatsData.h"
#include "EngineStats.h"
#if STATS
namespace
{
#if ENGINE_MAJOR_VERSION >= 5
void IncrementStatsRefCount()
{
StatsPrimaryEnableAdd();
}
void DecrementStatsRefCount()
{
StatsPrimaryEnableSubtract();
}
#else
void IncrementStatsRefCount()
{
StatsMasterEnableAdd();
}
void DecrementStatsRefCount()
{
StatsMasterEnableSubtract();
}
#endif
}
void FUnrealStatCollector::Subscribe()
{
IncrementStatsRefCount();
/*
* From 5.2.0 onwards, UE_STATS_THREAD_AS_PIPE is undefined and the only way to
* access the stat system is via the new API.
*
* Between 5.0.0 and 5.2.0, UE_STATS_THREAD_AS_PIPE enables new API. If it is 0,
* the old API can be used.
*
* See UE engine source commits 10b5e05d00df4f23d3b75f6af5ec08f8ae0e8618
* 327a94d1a4e021714f2c3ca820fe9ed5606465bf
* d48f6660b807c7377926cffd12020645f91772f8
*
* All references to UE_STATS_THREAD_AS_PIPE are removed in
* d48f6660b807c7377926cffd12020645f91772f8.
*/
#if ENGINE_MAJOR_VERSION >= 5 && (ENGINE_MINOR_VERSION >= 2 || UE_STATS_THREAD_AS_PIPE)
{
auto& StatsState = FStatsThreadState::GetLocalState();
StatsState.NewFrameDelegate.AddSP(this, &FUnrealStatCollector::OnNewFrame);
}
#else
FSimpleDelegateGraphTask::CreateAndDispatchWhenReady
(
FSimpleDelegateGraphTask::FDelegate::CreateLambda(
[WeakCollector = TWeakPtr<FUnrealStatCollector>(this->AsShared())]() {
if (!WeakCollector.IsValid()) { return; }
auto& StatsState = FStatsThreadState::GetLocalState();
StatsState.NewFrameDelegate.AddSP(WeakCollector.Pin().Get(), &FUnrealStatCollector::OnNewFrame);
}
),
TStatId{},
nullptr,
/*
* StatsThread is deprecated since 5.0
*
* Need to verify post-5.0 behaviour but:
* - 4.27 to 5.0 should use the current method to subscribe to NewFrameDelegate
* - 5.0 on can subscribe from game thread directly. (See FThreadStats::bUseThreadAsPipe)
*/
ENamedThreads::StatsThread
);
#endif // UE_STATS_THREAD_AS_PIPE
}
void FUnrealStatCollector::Unsubscribe()
{
DecrementStatsRefCount();
}
void FUnrealStatCollector::OnNewFrame(int64 Frame)
{
TArray<FStatMessage> OutStats;
auto& Stats = FStatsThreadState::GetLocalState();
Stats.GetInclusiveAggregateStackStats(Frame, OutStats);
for (auto& Message : OutStats)
{
// GetShortName() is expensive and we're calling it for every stat.
// In practice: we'll stick filter by GetRawName first and stick things in a hashmap
// might also be able to compare FName indices
FName ShortName = Message.NameAndInfo.GetShortName();
// Robustness: we can check the value type from message before blindly grabbing duration (or other types)
// Consult EngineStats.h for stat names
// (There's also many other stats in other subsystems.)
if (ShortName == TEXT("STAT_GameEngineTick"))
{
GAMELIFT_METRICS_SET_MS(Aws::GameLift::Metrics::MetricGameTickTime, FPlatformTime::ToMilliseconds(Message.GetValue_Duration()));
}
else if (ShortName == TEXT("STAT_WorldTickTime"))
{
GAMELIFT_METRICS_SET_MS(Aws::GameLift::Metrics::MetricWorldTickTime, FPlatformTime::ToMilliseconds(Message.GetValue_Duration()));
}
}
}
#else
void FUnrealStatCollector::Subscribe() {}
void FUnrealStatCollector::Unsubscribe() {}
void FUnrealStatCollector::OnNewFrame(int64 Frame) {}
#endif // STATS

View File

@@ -0,0 +1,31 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "CoreMinimal.h"
class FUnrealStatCollector : public TSharedFromThis<FUnrealStatCollector>
{
public:
/**
* Subscribes to NewFrameDelegate in Unreal stats system.
*/
void Subscribe();
/**
* Unsubscribes from NewFrameDelegate in Unreal stats system.
*/
void Unsubscribe();
void OnNewFrame(int64 Frame);
};

View File

@@ -0,0 +1,125 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"
#include "GameLiftMetricsTypes.h"
#include <aws/gamelift/metrics/GameLiftMetrics.h>
// Forward declarations
struct FMetricsParameters;
class FSocket;
class FUnrealStatCollector;
class FTickableCollector;
class UGameLiftMetricsConfig;
namespace Aws {
namespace GameLift {
namespace Server {
namespace Model {
class GameSession;
} // Model
} // Server
} // GameLift
} // Aws
class GAMELIFTMETRICS_API FGameLiftMetricsModule : public IModuleInterface
{
public:
// IModuleInterface
virtual void StartupModule() override;
virtual void ShutdownModule() override;
virtual bool SupportsDynamicReloading() override { return false; }
virtual bool SupportsAutomaticShutdown() override { return true; }
// ~IModuleInterface
static FGameLiftMetricsModule& Load();
static FGameLiftMetricsModule& Get();
static FGameLiftMetricsModule* GetPtr();
/**
* Initialize GameLift Metrics using default configuration. These
* may be overriden by environment variables.
*/
void Initialize();
/**
* Initialize GameLift Metrics with metrics parameters.
*
* @param metricsParameters Metrics parameters to use.
*/
void Initialize(const FMetricsParameters& metricsParameters);
/**
* Terminate the GameLift Metrics SDK.
*/
void Terminate();
/**
* Enable or disable metrics at runtime.
* If metrics were previously disabled, this will initialize the metrics system.
* If metrics were previously enabled, this will terminate the metrics system.
*
* @param bEnable Whether to enable or disable metrics
* @return True if the operation was successful
*/
bool SetMetricsEnabled(bool bEnable);
/**
* Check if metrics are currently enabled and running
*
* @return True if metrics are currently enabled and running
*/
bool IsMetricsEnabled() const;
/**
* Records a new game session.
* Call when starting a new session from the FProcessSettings::OnStartGameSession callback.
*/
void OnStartGameSession(const Aws::GameLift::Server::Model::GameSession&);
/**
* Records a new player session.
*
* Call when accepting a player session.
*/
void OnAcceptPlayerSession();
/**
* Records a removed player session.
*
* Call when removing a player session.
*/
void OnRemovePlayerSession();
private:
void StartMetricsCollector();
TSharedPtr<FSocket> Socket;
TUniquePtr<FTickableCollector> Collector;
TSharedPtr<FUnrealStatCollector> UnrealStatCollector;
static FString CurrentGameSessionId;
static FThreadSafeCounter CurrentPlayerCount;
bool bMetricsRunning = false; // Tracks if metrics are currently running
static void CrashHandler(const FGenericCrashContext& Context);
void ReEmitMetrics();
friend class FTickableCollector;
};

View File

@@ -0,0 +1,80 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "CoreMinimal.h"
#include "GameLiftMetricsConfig.generated.h"
/**
* GameLift Metrics module configuration.
*
* Can be configured in `DefaultGame.ini`:
* ```
* [/Script/GameLiftMetricsUnreal.GameLiftMetricsConfig]
* CollectorHost = "127.0.0.1"
* CollectorPort = 8125
* MaxPacketSize = 2048
* CaptureIntervalSeconds = 10
* bEnableMetrics = true
* ```
*/
UCLASS(config=Game, defaultconfig)
class GAMELIFTMETRICS_API UGameLiftMetricsConfig : public UObject
{
GENERATED_BODY()
public:
UGameLiftMetricsConfig() = default;
/**
* Returns the current configuration.
*/
static const UGameLiftMetricsConfig& Get();
/**
* Whether metrics collection is enabled.
* When disabled, no metrics will be collected or sent.
*/
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GameLift Metrics")
bool bEnableMetrics = true;
/**
* Host to send metrics to.
*/
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GameLift Metrics")
FString CollectorHost = TEXT("127.0.0.1");
/**
* UDP port number to send metrics to.
*/
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GameLift Metrics")
int32 CollectorPort = 8125;
/**
* Metrics capture interval before sending data to the collector.
*/
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GameLift Metrics")
float CaptureIntervalSeconds = 10.0f;
/**
* Maximum UDP packet size.
*
* Typical MTU for Internet packets is 1500 bytes.
* We set the default to 1472, leaving room for headers.
*
* For use with collector on same machine or with AWS jumbo packets this value can be bumped up past 1500 bytes.
*/
UPROPERTY(Config, EditAnywhere, BlueprintReadOnly, Category="GameLift Metrics")
int32 MaxPacketSize = 1472;
};

View File

@@ -0,0 +1,42 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include "CoreMinimal.h"
#include <aws/gamelift/metrics/GameLiftMetrics.h>
DECLARE_LOG_CATEGORY_EXTERN(LogGameLiftMetrics, Log, All);
#define WITH_GAMELIFT_METRICS (WITH_GAMELIFT && UE_SERVER)
namespace Aws {
namespace GameLift {
namespace Metrics {
/**
* Logs in all server builds.
*/
GAMELIFT_METRICS_DEFINE_PLATFORM_API(GAMELIFTMETRICS_API, Server, WITH_GAMELIFT_METRICS && UE_SERVER);
/**
* Logs in all development or debug server builds.
*/
GAMELIFT_METRICS_DEFINE_PLATFORM_API(GAMELIFTMETRICS_API, ServerDevelopment, WITH_GAMELIFT_METRICS && UE_SERVER && (UE_BUILD_DEVELOPMENT || UE_BUILD_DEBUG));
/**
* Logs only in debug builds.
*/
GAMELIFT_METRICS_DEFINE_PLATFORM_API(GAMELIFTMETRICS_API, ServerDebug, WITH_GAMELIFT_METRICS && UE_SERVER && UE_BUILD_DEBUG);
} // Metrics
} // GameLift
} // Aws

View File

@@ -0,0 +1,86 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
using System.IO;
using UnrealBuildTool;
public class GameLiftServerSDK : ModuleRules
{
public GameLiftServerSDK(ReadOnlyTargetRules Target) : base(Target)
{
PrivateDependencyModuleNames.AddRange(new string[] { "Core", "Projects", "OpenSSL" });
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableExceptions = true;
bUseRTTI = true;
// Disable windows min/max macros
PublicDefinitions.Add("NOMINMAX");
if (Target.Type == TargetRules.TargetType.Server)
{
PublicDefinitions.Add("WITH_GAMELIFT=1");
}
else
{
PublicDefinitions.Add("WITH_GAMELIFT=0");
}
// Isolate asio namespace to improve packaging compatibility with other modules
PrivateDefinitions.Add("asio=gamelift_asio");
PrivateDefinitions.Add("asio_signal_handler=gamelift_asio_signal_handler");
PrivateDefinitions.Add("AWS_GAMELIFT_EXPORTS");
PrivateDefinitions.Add("ASIO_STANDALONE=1");
PublicDefinitions.Add("SPDLOG_NO_EXCEPTIONS");
// std::invoke_result replaces std::result_of for C++17 and later
// Asio only auto-detects this for MSVC, so override for all compilers
if (Target.CppStandard >= CppStandardVersion.Cpp17) {
PrivateDefinitions.Add("ASIO_HAS_STD_INVOKE_RESULT");
}
PrivateDefinitions.Add("USE_IMPORT_EXPORT=1");
if (Target.Platform == UnrealTargetPlatform.Win64)
{
PrivateDefinitions.Add("_WEBSOCKETPP_CPP11_STRICT_=1");
PrivateDefinitions.Add("SPDLOG_WCHAR_TO_UTF8_SUPPORT=1");
PrivateDefinitions.AddRange(new string[] {
"_WIN32_WINNT_WIN10_TH2=0x0A00",
"_WIN32_WINNT_WIN10_RS1=0x0A00",
"_WIN32_WINNT_WIN10_RS2=0x0A00",
"_WIN32_WINNT_WIN10_RS3=0x0A00",
"_WIN32_WINNT_WIN10_RS4=0x0A00",
"_WIN32_WINNT_WIN10_RS5=0x0A00",
});
}
else if (Target.Platform == UnrealTargetPlatform.Linux || Target.Platform == UnrealTargetPlatform.LinuxArm64)
{
PrivateDefinitions.Add("ASIO_DISABLE_CO_AWAIT");
PrivateDefinitions.Add("RAPIDJSON_NOMEMBERITERATORCLASS");
}
string SpdlogPath = Path.Combine(ModuleDirectory, "../../ThirdParty/spdlog/include");
string SpdlogSrcPath = Path.Combine(ModuleDirectory, "../../ThirdParty/spdlog/src");
string RapidJSONPath = Path.Combine(ModuleDirectory, "../../ThirdParty/rapidjson/include");
string AsioPath = Path.Combine(ModuleDirectory, "../../ThirdParty/asio/include");
string WebSocketPPPath = Path.Combine(ModuleDirectory, "../../ThirdParty/websocketpp");
string ConcurrentQueuePath = Path.Combine(ModuleDirectory, "../../ThirdParty/concurrentqueue");
PublicIncludePaths.Add(SpdlogPath);
PublicIncludePaths.Add(SpdlogSrcPath);
PrivateIncludePaths.Add(RapidJSONPath);
PrivateIncludePaths.Add(AsioPath);
PrivateIncludePaths.Add(WebSocketPPPath);
PrivateIncludePaths.Add(ConcurrentQueuePath);
}
}

View File

@@ -0,0 +1,558 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "GameLiftServerSDK.h"
#include "Core.h"
#include "Modules/ModuleManager.h"
#include "Interfaces/IPluginManager.h"
#include <cstdlib>
#define LOCTEXT_NAMESPACE "FGameLiftServerSDKModule"
void* FGameLiftServerSDKModule::GameLiftServerSDKLibraryHandle = nullptr;
static FProcessParameters GameLiftProcessParameters;
void FGameLiftServerSDKModule::StartupModule()
{
}
bool FGameLiftServerSDKModule::LoadDependency(const FString& Dir, const FString& Name, void*& Handle)
{
FString Lib = Name + TEXT(".") + FPlatformProcess::GetModuleExtension();
FString Path = Dir.IsEmpty() ? *Lib : FPaths::Combine(*Dir, *Lib);
Handle = FPlatformProcess::GetDllHandle(*Path);
if (Handle == nullptr)
{
return false;
}
return true;
}
void FGameLiftServerSDKModule::FreeDependency(void*& Handle)
{
#if !PLATFORM_LINUX
if (Handle != nullptr)
{
FPlatformProcess::FreeDllHandle(Handle);
Handle = nullptr;
}
#endif
}
void FGameLiftServerSDKModule::ShutdownModule()
{
FreeDependency(GameLiftServerSDKLibraryHandle);
}
FGameLiftStringOutcome FGameLiftServerSDKModule::GetSdkVersion() {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::GetSdkVersion();
if (outcome.IsSuccess()){
return FGameLiftStringOutcome(outcome.GetResult());
}
else {
return FGameLiftStringOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftStringOutcome("");
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::InitSDK() {
#if WITH_GAMELIFT
auto initSDKOutcome = Aws::GameLift::Server::InitSDK();
if (initSDKOutcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else{
return FGameLiftGenericOutcome(FGameLiftError(initSDKOutcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::InitSDK(const FServerParameters &serverParameters) {
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::ServerParameters sdkServerParameters;
sdkServerParameters.SetWebSocketUrl(TCHAR_TO_UTF8(*serverParameters.m_webSocketUrl));
sdkServerParameters.SetFleetId(TCHAR_TO_UTF8(*serverParameters.m_fleetId));
sdkServerParameters.SetProcessId(TCHAR_TO_UTF8(*serverParameters.m_processId));
sdkServerParameters.SetHostId(TCHAR_TO_UTF8(*serverParameters.m_hostId));
sdkServerParameters.SetAuthToken(TCHAR_TO_UTF8(*serverParameters.m_authToken));
sdkServerParameters.SetAwsRegion(TCHAR_TO_UTF8(*serverParameters.m_awsRegion));
sdkServerParameters.SetAccessKey(TCHAR_TO_UTF8(*serverParameters.m_accessKey));
sdkServerParameters.SetSecretKey(TCHAR_TO_UTF8(*serverParameters.m_secretKey));
sdkServerParameters.SetSessionToken(TCHAR_TO_UTF8(*serverParameters.m_sessionToken));
auto initSDKOutcome = Aws::GameLift::Server::InitSDK(sdkServerParameters);
if (initSDKOutcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else{
return FGameLiftGenericOutcome(FGameLiftError(initSDKOutcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::InitMetrics() {
#if WITH_GAMELIFT
auto initMetricsOutcome = Aws::GameLift::Server::InitMetrics();
if (initMetricsOutcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(initMetricsOutcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::InitMetrics(const FMetricsParameters &metricsParameters) {
#if WITH_GAMELIFT
Aws::GameLift::Server::MetricsParameters sdkMetricsParameters(
TCHAR_TO_UTF8(*metricsParameters.m_statsDHost),
metricsParameters.m_statsDPort,
TCHAR_TO_UTF8(*metricsParameters.m_crashReporterHost),
metricsParameters.m_crashReporterPort,
metricsParameters.m_flushIntervalMs,
metricsParameters.m_maxPacketSize
);
auto initMetricsOutcome = Aws::GameLift::Server::InitMetrics(sdkMetricsParameters);
if (initMetricsOutcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(initMetricsOutcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::ProcessEnding() {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::ProcessEnding();
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::ActivateGameSession() {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::ActivateGameSession();
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::AcceptPlayerSession(const FString& playerSessionId) {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::AcceptPlayerSession(TCHAR_TO_UTF8(*playerSessionId));
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::RemovePlayerSession(const FString& playerSessionId) {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::RemovePlayerSession(TCHAR_TO_UTF8(*playerSessionId));
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::Destroy()
{
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::Destroy();
if (outcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftDescribePlayerSessionsOutcome FGameLiftServerSDKModule::DescribePlayerSessions(const FGameLiftDescribePlayerSessionsRequest &describePlayerSessionsRequest)
{
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::DescribePlayerSessionsRequest request;
request.SetGameSessionId(TCHAR_TO_UTF8(*describePlayerSessionsRequest.m_gameSessionId));
request.SetPlayerId(TCHAR_TO_UTF8(*describePlayerSessionsRequest.m_playerId));
request.SetPlayerSessionId(TCHAR_TO_UTF8(*describePlayerSessionsRequest.m_playerSessionId));
request.SetPlayerSessionStatusFilter(TCHAR_TO_UTF8(*describePlayerSessionsRequest.m_playerSessionStatusFilter));
request.SetLimit(describePlayerSessionsRequest.m_limit);
request.SetNextToken(TCHAR_TO_UTF8(*describePlayerSessionsRequest.m_nextToken));
auto outcome = Aws::GameLift::Server::DescribePlayerSessions(request);
if (outcome.IsSuccess()) {
auto& outres = outcome.GetResult();
FGameLiftDescribePlayerSessionsResult result;
int sessionCount = 0;
auto sessions = outres.GetPlayerSessions(sessionCount);
if (sessionCount > 0) {
TArray<FGameLiftPlayerSession> outSessions;
outSessions.Reserve(sessionCount);
for (int i = 0; i < sessionCount; ++i) {
auto session = sessions + i;
FGameLiftPlayerSession& outSession = outSessions.AddDefaulted_GetRef();
outSession.m_playerSessionId = UTF8_TO_TCHAR(session->GetPlayerSessionId());
outSession.m_playerId = UTF8_TO_TCHAR(session->GetPlayerId());
outSession.m_gameSessionId = UTF8_TO_TCHAR(session->GetGameSessionId());
outSession.m_fleetId = UTF8_TO_TCHAR(session->GetFleetId());
outSession.m_creationTime = session->GetCreationTime();
outSession.m_terminationTime = session->GetTerminationTime();
switch (session->GetStatus()) {
case Aws::GameLift::Server::Model::PlayerSessionStatus::NOT_SET: outSession.m_status = EPlayerSessionStatus::NOT_SET; break;
case Aws::GameLift::Server::Model::PlayerSessionStatus::RESERVED: outSession.m_status = EPlayerSessionStatus::RESERVED; break;
case Aws::GameLift::Server::Model::PlayerSessionStatus::ACTIVE: outSession.m_status = EPlayerSessionStatus::ACTIVE; break;
case Aws::GameLift::Server::Model::PlayerSessionStatus::COMPLETED: outSession.m_status = EPlayerSessionStatus::COMPLETED; break;
case Aws::GameLift::Server::Model::PlayerSessionStatus::TIMEDOUT: outSession.m_status = EPlayerSessionStatus::TIMEDOUT; break;
}
outSession.m_ipAddress = UTF8_TO_TCHAR(session->GetIpAddress());
outSession.m_port = session->GetPort();
outSession.m_playerData = UTF8_TO_TCHAR(session->GetPlayerData());
outSession.m_dnsName = UTF8_TO_TCHAR(session->GetDnsName());
}
result.m_playerSessions = outSessions;
}
result.m_nextToken = (UTF8_TO_TCHAR(outres.GetNextToken()));
return FGameLiftDescribePlayerSessionsOutcome(result);
}
else {
return FGameLiftDescribePlayerSessionsOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftDescribePlayerSessionsOutcome(FGameLiftDescribePlayerSessionsResult());
#endif
}
static void OnActivateFunctionInternal(Aws::GameLift::Server::Model::GameSession gameSession, void* state) {
GameLiftProcessParameters.OnActivateFunction(gameSession);
}
static void OnUpdateFunctionInternal(Aws::GameLift::Server::Model::UpdateGameSession updateGameSession, void* state) {
GameLiftProcessParameters.OnUpdateFunction(updateGameSession);
}
static void OnTerminateFunctionInternal(void* state) {
GameLiftProcessParameters.OnTerminateFunction();
}
static bool OnHealthCheckInternal(void* state) {
return GameLiftProcessParameters.OnHealthCheckFunction();
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::ProcessReady(FProcessParameters &processParameters) {
#if WITH_GAMELIFT
GameLiftProcessParameters = processParameters;
char logPathsBuffer[MAX_LOG_PATHS][MAX_PATH_LENGTH];
const char* logPaths[MAX_LOG_PATHS];
memset(logPaths, 0, sizeof(logPaths));
memset(logPathsBuffer, 0, sizeof(logPathsBuffer));
//only use the first MAX_LOG_PATHS values (duplicate logic in cpp SDK)
int32 numLogs = FMath::Min(processParameters.logParameters.Num(), MAX_LOG_PATHS);
for (int i = 0; i < numLogs; i++)
{
FTCHARToUTF8 utf8text(*processParameters.logParameters[i]);
if (utf8text.Length() < MAX_PATH_LENGTH)
{
memcpy(logPathsBuffer[i], utf8text.Get(), utf8text.Length());
}
logPaths[i] = logPathsBuffer[i];
}
const TSharedPtr<IPlugin> StandalonePlugin = IPluginManager::Get().FindPlugin(TEXT("GameLiftPlugin"));
const TSharedPtr<IPlugin> LightweightPlugin = IPluginManager::Get().FindPlugin(TEXT("GameLiftServerSDK"));
FString pluginName;
FString pluginVersion;
if (LightweightPlugin.IsValid())
{
pluginName = LightweightPlugin->GetName();
pluginVersion = LightweightPlugin->GetDescriptor().VersionName;
}
else if (StandalonePlugin.IsValid())
{
pluginName = StandalonePlugin->GetName();
pluginVersion = StandalonePlugin->GetDescriptor().VersionName;
}
else
{
return FGameLiftGenericOutcome(FGameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::SDK_VERSION_DETECTION_FAILED, "Unknown SDK Tool Name", "Couldn't find the GameLift plugin name or version. "
"Please update this code to search for a valid name defined inside GameLift's .uplugin file.")
);
}
// Don't use Unreal's FPlatformMisc::SetEnvironmentVar because it uses Windows specific SetEnvironmentVariable API
// which doesn't mix with GameLift SDK's use of C++ std::getenv()
FString pluginNameEnv = "GAMELIFT_SDK_TOOL_NAME=Unreal" + pluginName;
FString pluginVersionEnv = "GAMELIFT_SDK_TOOL_VERSION=" + pluginVersion;
static std::string pluginNameEnvStr = TCHAR_TO_UTF8(*pluginNameEnv);
static std::string pluginVersionEnvStr = TCHAR_TO_UTF8(*pluginVersionEnv);
#if PLATFORM_WINDOWS
_putenv(pluginNameEnvStr.c_str());
_putenv(pluginVersionEnvStr.c_str());
#else
putenv(const_cast<char*>(pluginNameEnvStr.c_str()));
putenv(const_cast<char*>(pluginVersionEnvStr.c_str()));
#endif
Aws::GameLift::Server::ProcessParameters processParams = Aws::GameLift::Server::ProcessParameters(
OnActivateFunctionInternal,
nullptr,
OnUpdateFunctionInternal,
nullptr,
OnTerminateFunctionInternal,
nullptr,
OnHealthCheckInternal,
nullptr,
processParameters.port,
Aws::GameLift::Server::LogParameters(logPaths, numLogs)
);
auto outcome = Aws::GameLift::Server::ProcessReady(processParams);
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::UpdatePlayerSessionCreationPolicy(EPlayerSessionCreationPolicy policy)
{
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::PlayerSessionCreationPolicy internalPolicy = Aws::GameLift::Server::Model::PlayerSessionCreationPolicyMapper::GetPlayerSessionCreationPolicyForName(TCHAR_TO_UTF8(*GetNameForPlayerSessionCreationPolicy(policy)));
auto outcome = Aws::GameLift::Server::UpdatePlayerSessionCreationPolicy(internalPolicy);
if (outcome.IsSuccess()){
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftStringOutcome FGameLiftServerSDKModule::GetGameSessionId() {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::GetGameSessionId();
if (outcome.IsSuccess()){
return FGameLiftStringOutcome(outcome.GetResult());
}
else {
return FGameLiftStringOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftStringOutcome("");
#endif
}
FGameLiftLongOutcome FGameLiftServerSDKModule::GetTerminationTime() {
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::GetTerminationTime();
if (outcome.IsSuccess()) {
return FGameLiftLongOutcome(outcome.GetResult());
}
else {
return FGameLiftLongOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftLongOutcome(-1);
#endif
}
FGameLiftStringOutcome FGameLiftServerSDKModule::StartMatchBackfill(const FStartMatchBackfillRequest& request) {
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::StartMatchBackfillRequest sdkRequest;
sdkRequest.SetTicketId(TCHAR_TO_UTF8(*request.m_ticketId));
sdkRequest.SetGameSessionArn(TCHAR_TO_UTF8(*request.m_gameSessionArn));
sdkRequest.SetMatchmakingConfigurationArn(TCHAR_TO_UTF8(*request.m_matchmakingConfigurationArn));
for (auto player : request.m_players) {
Aws::GameLift::Server::Model::Player sdkPlayer;
sdkPlayer.SetPlayerId(TCHAR_TO_UTF8(*player.m_playerId));
sdkPlayer.SetTeam(TCHAR_TO_UTF8(*player.m_team));
for (auto entry : player.m_latencyInMs) {
sdkPlayer.WithLatencyMs(TCHAR_TO_UTF8(*entry.Key), entry.Value);
}
std::map<std::string, Aws::GameLift::Server::Model::AttributeValue> sdkAttributeMap;
for (auto attributeEntry : player.m_playerAttributes) {
FAttributeValue value = attributeEntry.Value;
Aws::GameLift::Server::Model::AttributeValue attribute;
switch (value.m_type)
{
case FAttributeType::STRING:
attribute = Aws::GameLift::Server::Model::AttributeValue(TCHAR_TO_UTF8(*value.m_S));
break;
case FAttributeType::DOUBLE:
attribute = Aws::GameLift::Server::Model::AttributeValue(value.m_N);
break;
case FAttributeType::STRING_LIST:
attribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringList();
for (auto sl : value.m_SL) {
attribute.AddString(TCHAR_TO_UTF8(*sl));
};
break;
case FAttributeType::STRING_DOUBLE_MAP:
attribute = Aws::GameLift::Server::Model::AttributeValue::ConstructStringDoubleMap();
for (auto sdm : value.m_SDM) {
attribute.AddStringAndDouble(TCHAR_TO_UTF8(*sdm.Key), sdm.Value);
};
break;
}
sdkPlayer.WithPlayerAttribute((TCHAR_TO_UTF8(*attributeEntry.Key)), attribute);
}
sdkRequest.AddPlayer(sdkPlayer);
}
auto outcome = Aws::GameLift::Server::StartMatchBackfill(sdkRequest);
if (outcome.IsSuccess()) {
return FGameLiftStringOutcome(outcome.GetResult().GetTicketId());
}
else {
return FGameLiftStringOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftStringOutcome("");
#endif
}
FGameLiftGenericOutcome FGameLiftServerSDKModule::StopMatchBackfill(const FStopMatchBackfillRequest& request)
{
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::StopMatchBackfillRequest sdkRequest;
sdkRequest.SetTicketId(TCHAR_TO_UTF8(*request.m_ticketId));
sdkRequest.SetGameSessionArn(TCHAR_TO_UTF8(*request.m_gameSessionArn));
sdkRequest.SetMatchmakingConfigurationArn(TCHAR_TO_UTF8(*request.m_matchmakingConfigurationArn));
auto outcome = Aws::GameLift::Server::StopMatchBackfill(sdkRequest);
if (outcome.IsSuccess()) {
return FGameLiftGenericOutcome(nullptr);
}
else {
return FGameLiftGenericOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGenericOutcome(nullptr);
#endif
}
FGameLiftGetComputeCertificateOutcome FGameLiftServerSDKModule::GetComputeCertificate()
{
#if WITH_GAMELIFT
auto outcome = Aws::GameLift::Server::GetComputeCertificate();
if (outcome.IsSuccess()) {
auto& outres = outcome.GetResult();
FGameLiftGetComputeCertificateResult result;
result.m_certificate_path = UTF8_TO_TCHAR(outres.GetCertificatePath());
result.m_computeName = UTF8_TO_TCHAR(outres.GetComputeName());
return FGameLiftGetComputeCertificateOutcome(result);
}
else {
return FGameLiftGetComputeCertificateOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGetComputeCertificateOutcome(FGameLiftGetComputeCertificateResult());
#endif
}
FGameLiftGetFleetRoleCredentialsOutcome FGameLiftServerSDKModule::GetFleetRoleCredentials(const FGameLiftGetFleetRoleCredentialsRequest &request)
{
#if WITH_GAMELIFT
Aws::GameLift::Server::Model::GetFleetRoleCredentialsRequest sdkRequest;
sdkRequest.SetRoleArn(TCHAR_TO_UTF8(*request.m_roleArn));
sdkRequest.SetRoleSessionName(TCHAR_TO_UTF8(*request.m_roleSessionName));
auto outcome = Aws::GameLift::Server::GetFleetRoleCredentials(sdkRequest);
if (outcome.IsSuccess()) {
auto& outres = outcome.GetResult();
FGameLiftGetFleetRoleCredentialsResult result;
result.m_assumedUserRoleArn = UTF8_TO_TCHAR(outres.GetAssumedUserRoleArn());
result.m_assumedRoleId = UTF8_TO_TCHAR(outres.GetAssumedRoleId());
result.m_accessKeyId = UTF8_TO_TCHAR(outres.GetAccessKeyId());
result.m_secretAccessKey = UTF8_TO_TCHAR(outres.GetSecretAccessKey());
result.m_sessionToken = UTF8_TO_TCHAR(outres.GetSessionToken());
result.m_expiration = FDateTime::FromUnixTimestamp(outres.GetExpiration());
return FGameLiftGetFleetRoleCredentialsOutcome(result);
}
else {
return FGameLiftGetFleetRoleCredentialsOutcome(FGameLiftError(outcome.GetError()));
}
#else
return FGameLiftGetFleetRoleCredentialsOutcome(FGameLiftGetFleetRoleCredentialsResult());
#endif
}
#undef LOCTEXT_NAMESPACE
IMPLEMENT_MODULE(FGameLiftServerSDKModule, GameLiftServerSDK)

View File

@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/GameLiftCommonState.h>
using namespace Aws::GameLift;
// This is a shared pointer because many contexts (DLLs) may point to the same state.
Aws::GameLift::Internal::GameLiftCommonState * Aws::GameLift::Internal::GameLiftCommonState::m_instance;
Aws::GameLift::Internal::GameLiftCommonState::GameLiftCommonState() {}
Aws::GameLift::Internal::GameLiftCommonState::~GameLiftCommonState() {}
GenericOutcome Aws::GameLift::Internal::GameLiftCommonState::SetInstance(Aws::GameLift::Internal::GameLiftCommonState *instance) {
// If there already is an instance, fail.
if (m_instance) {
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::ALREADY_INITIALIZED));
}
// take ownership of the new instance
m_instance = instance;
return GenericOutcome(nullptr);
}
Aws::GameLift::Internal::GetInstanceOutcome Aws::GameLift::Internal::GameLiftCommonState::GetInstance() {
if (!m_instance) {
return Internal::GetInstanceOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::NOT_INITIALIZED));
}
return m_instance;
}
Aws::GameLift::Internal::GetInstanceOutcome Aws::GameLift::Internal::GameLiftCommonState::GetInstance(Aws::GameLift::Internal::GAMELIFT_INTERNAL_STATE_TYPE stateType) {
if (!m_instance) {
return Internal::GetInstanceOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::NOT_INITIALIZED));
}
if (m_instance->GetStateType() != stateType) {
return Internal::GetInstanceOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::INITIALIZATION_MISMATCH));
}
return m_instance;
}
GenericOutcome Aws::GameLift::Internal::GameLiftCommonState::DestroyInstance() {
if (m_instance) {
delete m_instance;
m_instance = nullptr;
return GenericOutcome(nullptr);
}
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::NOT_INITIALIZED));
}

View File

@@ -0,0 +1,55 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/common/GameLiftToolDetector.h>
#include <cstdlib>
#include <cstring>
namespace Aws {
namespace GameLift {
namespace Common {
void GameLiftToolDetector::SetGameLiftTool() {
static constexpr const char* ENV_VAR_SDK_TOOL_NAME = "GAMELIFT_SDK_TOOL_NAME";
static constexpr const char* ENV_VAR_SDK_TOOL_VERSION = "GAMELIFT_SDK_TOOL_VERSION";
if (!IsToolRunning()) {
return;
}
const char* existingToolName = std::getenv(ENV_VAR_SDK_TOOL_NAME);
const char* existingToolVersion = std::getenv(ENV_VAR_SDK_TOOL_VERSION);
std::string toolName = GetToolName();
std::string toolVersion = GetToolVersion();
if (existingToolName != nullptr && strlen(existingToolName) > 0) {
std::string existingToolNameStr(existingToolName);
std::string existingToolVersionStr(existingToolVersion != nullptr ? existingToolVersion : "");
if (existingToolNameStr.find(toolName) == std::string::npos) {
toolName = existingToolNameStr + "," + toolName;
toolVersion = existingToolVersionStr + "," + toolVersion;
} else {
toolName = existingToolNameStr;
toolVersion = existingToolVersionStr;
}
}
#ifdef _WIN32
_putenv_s(ENV_VAR_SDK_TOOL_NAME, toolName.c_str());
_putenv_s(ENV_VAR_SDK_TOOL_VERSION, toolVersion.c_str());
#else
setenv(ENV_VAR_SDK_TOOL_NAME, toolName.c_str(), 1);
setenv(ENV_VAR_SDK_TOOL_VERSION, toolVersion.c_str(), 1);
#endif
}
} // namespace Common
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,84 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/common/MetricsDetector.h>
#include <cstdio>
#include <memory>
#include <stdexcept>
#include <string>
#include <algorithm>
namespace Aws {
namespace GameLift {
namespace Common {
bool MetricsDetector::IsToolRunning() {
try {
#ifdef _WIN32
std::string windowsServiceArgs = std::string(WINDOWS_SERVICE_ARGS) + WINDOWS_SERVICE_NAME;
return CheckService(WINDOWS_SERVICE_COMMAND, windowsServiceArgs, [](const std::string& output) {
return output.find(WINDOWS_RUNNING_STATUS) != std::string::npos;
});
#else
std::string linuxServiceArgs = std::string(LINUX_SERVICE_ARGS) + LINUX_SERVICE_NAME;
return CheckService(LINUX_SERVICE_COMMAND, linuxServiceArgs, [](const std::string& output) {
std::string trimmedOutput = output;
// Trim whitespace
trimmedOutput.erase(trimmedOutput.find_last_not_of(" \n\r\t") + 1);
trimmedOutput.erase(0, trimmedOutput.find_first_not_of(" \n\r\t"));
return trimmedOutput == LINUX_ACTIVE_STATUS;
});
#endif
} catch (...) {
return false;
}
}
bool MetricsDetector::CheckService(const std::string& command, const std::string& arguments, std::function<bool(const std::string&)> outputValidator) {
std::string fullCommand = command + " " + arguments;
#ifdef _WIN32
FILE* pipe = _popen(fullCommand.c_str(), "r");
#else
FILE* pipe = popen(fullCommand.c_str(), "r");
#endif
if (!pipe) {
return false;
}
std::string result;
char buffer[128];
while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
result.append(buffer);
}
#ifdef _WIN32
int exitCode = _pclose(pipe);
#else
int exitCode = pclose(pipe);
#endif
return exitCode == 0 && outputValidator(result);
}
std::string MetricsDetector::GetToolName() {
return TOOL_NAME;
}
std::string MetricsDetector::GetToolVersion() {
return TOOL_VERSION;
}
} // namespace Common
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,67 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/Message.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
#include <aws/gamelift/internal/util/RandomStringGenerator.h>
namespace Aws {
namespace GameLift {
namespace Internal {
std::string Message::Serialize() const {
// Create the buffer & Writer for the object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
// Start the object and call Serialize to serialize.
writer.StartObject();
if (Serialize(&writer)) {
writer.EndObject();
return buffer.GetString();
}
return "";
}
bool Message::Deserialize(const std::string &jsonString) {
// Parse the json into a document
rapidjson::Document doc;
if (doc.Parse(jsonString.c_str()).HasParseError()) {
return false;
}
// Call Deserialize to populate the object's member variables
return Deserialize(doc);
}
bool Message::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
JsonHelper::WriteNonEmptyString(writer, ACTION, m_action);
JsonHelper::WriteNonEmptyString(writer, REQUEST_ID, m_requestId);
return true;
}
bool Message::Deserialize(const rapidjson::Value &value) {
m_action = JsonHelper::SafelyDeserializeString(value, ACTION);
m_requestId = JsonHelper::SafelyDeserializeString(value, REQUEST_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const Message &message) {
os << message.Serialize();
return os;
}
std::string Message::GenerateRandomRequestId() { return RandomStringGenerator::GenerateRandomAlphaNumericString(32); }
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/ResponseMessage.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool ResponseMessage::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WritePositiveInt(writer, STATUS_CODE, m_statusCode);
JsonHelper::WriteNonEmptyString(writer, ERROR_MESSAGE, m_errorMessage);
return true;
}
bool ResponseMessage::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_statusCode = JsonHelper::SafelyDeserializeInt(value, STATUS_CODE);
m_errorMessage = JsonHelper::SafelyDeserializeString(value, ERROR_MESSAGE);
return true;
}
std::ostream &operator<<(std::ostream &os, const ResponseMessage &responseMessage) {
const Message *message = &responseMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,57 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/Uri.h>
#include <sstream>
namespace Aws {
namespace GameLift {
namespace Internal {
Uri::UriBuilder &Uri::UriBuilder::AddQueryParam(const std::string &key, const std::string &value) {
m_queryParams[key] = value;
return *this;
}
Uri::UriBuilder &Uri::UriBuilder::WithBaseUri(const std::string &baseUriString) {
m_baseUriString = baseUriString;
return *this;
}
Uri Uri::UriBuilder::Build() const { return Uri(m_baseUriString, m_queryParams); }
Uri::Uri(const std::string &baseUriString, const std::map<std::string, std::string> &queryMap) : m_baseUriString(baseUriString), m_queryMap(queryMap) {
SetQueryString(queryMap);
m_uriString = m_baseUriString + m_queryString;
}
void Uri::SetQueryString(const std::map<std::string, std::string> &queryMap) {
std::ostringstream queryStringStream;
queryStringStream << "?";
for (auto const &queryPair : queryMap) {
// All but first param requires "&" delimiter
if (queryStringStream.str().size() != 1) {
queryStringStream << "&";
}
queryStringStream << queryPair.first << "=" << queryPair.second;
}
m_queryString = queryStringStream.str();
}
std::ostream &operator<<(std::ostream &os, const Uri &uri) {
os << uri.GetUriString();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,125 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <aws/gamelift/internal/model/WebSocketAttributeValue.h>
#include <spdlog/spdlog.h>
namespace Aws {
namespace GameLift {
namespace Internal {
std::string WebSocketAttributeValue::Serialize() const {
// Create the buffer & Writer for the object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
// Start the object and call Serialize to serialize.
writer.StartObject();
if (Serialize(&writer)) {
writer.EndObject();
return buffer.GetString();
}
spdlog::warn("Could not parse into WebSocketAttributeValue");
return "";
}
bool WebSocketAttributeValue::Deserialize(const std::string &jsonString) {
// Parse the json into a document
rapidjson::Document doc;
if (doc.Parse(jsonString.c_str()).HasParseError()) {
spdlog::error("WebSocketAttributeValue: Parse error found for: {}", jsonString);
return false;
}
// Call Deserialize to populate the object's member variables
return Deserialize(doc);
}
bool WebSocketAttributeValue::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
writer->String(ATTR_TYPE);
writer->String(GetAttributeTypeAsString().c_str());
switch (m_attrType) {
case WebSocketAttrType::STRING:
writer->String(S);
writer->String(m_S.c_str());
break;
case WebSocketAttrType::DOUBLE:
writer->String(N);
writer->Double(m_N);
break;
case WebSocketAttrType::STRING_LIST:
writer->String(SL);
writer->StartArray();
for (auto it = m_SL.begin(); it != m_SL.end(); ++it) {
writer->String(it->c_str());
}
writer->EndArray();
break;
case WebSocketAttrType::STRING_DOUBLE_MAP:
writer->String(SDM);
writer->StartObject();
for (auto const &property : m_SDM) {
writer->String(property.first.c_str());
writer->Double(property.second);
}
writer->EndObject();
break;
default:
// Do Nothing
break;
}
return true;
}
bool WebSocketAttributeValue::Deserialize(const rapidjson::Value &value) {
std::string attrString = value.HasMember(ATTR_TYPE) ? value[ATTR_TYPE].GetString() : "";
SetAttributeType(attrString);
switch (m_attrType) {
case WebSocketAttrType::STRING:
m_S = value.HasMember(S) ? value[S].GetString() : "";
break;
case WebSocketAttrType::DOUBLE:
m_N = value.HasMember(N) ? value[N].GetDouble() : 0;
break;
case WebSocketAttrType::STRING_LIST:
if (value.HasMember(SL)) {
const rapidjson::Value &slValue = value[SL];
std::vector<std::string> sl;
for (rapidjson::SizeType i = 0; i < slValue.GetArray().Size(); i++) {
sl.push_back(slValue.GetArray()[i].GetString());
}
m_SL = sl;
}
break;
case WebSocketAttrType::STRING_DOUBLE_MAP:
if (value.HasMember(SDM)) {
const rapidjson::Value &sdmValue = value[SDM];
std::map<std::string, double> sdm;
for (rapidjson::Value::ConstMemberIterator iter = sdmValue.MemberBegin(); iter != sdmValue.MemberEnd(); ++iter) {
sdm[iter->name.GetString()] = iter->value.GetDouble();
}
m_SDM = sdm;
}
break;
default:
// Do Nothing
break;
}
return true;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,100 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/WebSocketGameSession.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
#include <spdlog/spdlog.h>
namespace Aws {
namespace GameLift {
namespace Internal {
std::string WebSocketGameSession::Serialize() const {
// Create the buffer & Writer for the object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
// Start the object and call Serialize to serialize.
writer.StartObject();
if (Serialize(&writer)) {
writer.EndObject();
return buffer.GetString();
}
spdlog::warn("Could not parse into WebSocketGameSession");
return "";
}
bool WebSocketGameSession::Deserialize(const std::string &jsonString) {
// Parse the json into a document
rapidjson::Document doc;
if (doc.Parse(jsonString.c_str()).HasParseError()) {
spdlog::error("WebSocketGameSession: Parse error found for: {}", jsonString);
return false;
}
// Call Deserialize to populate the object's member variables
return Deserialize(doc);
}
bool WebSocketGameSession::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, NAME, m_name);
JsonHelper::WriteNonEmptyString(writer, FLEET_ID, m_fleetId);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_DATA, m_gameSessionData);
JsonHelper::WriteNonEmptyString(writer, MATCHMAKER_DATA, m_matchmakerData);
JsonHelper::WriteNonEmptyString(writer, DNS_NAME, m_dnsName);
JsonHelper::WriteNonEmptyString(writer, IP_ADDRESS, m_ipAddress);
JsonHelper::WritePositiveInt(writer, MAXIMUM_PLAYER_SESSION_COUNT, m_maximumPlayerSessionCount);
JsonHelper::WritePositiveInt(writer, PORT, m_port);
writer->String(GAME_PROPERTIES);
writer->StartObject();
for (auto const &property : m_gameProperties) {
writer->String(property.first.c_str());
writer->String(property.second.c_str());
}
writer->EndObject();
return true;
}
bool WebSocketGameSession::Deserialize(const rapidjson::Value &value) {
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_name = JsonHelper::SafelyDeserializeString(value, NAME);
m_fleetId = JsonHelper::SafelyDeserializeString(value, FLEET_ID);
m_gameSessionData = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_DATA);
m_matchmakerData = JsonHelper::SafelyDeserializeString(value, MATCHMAKER_DATA);
m_dnsName = JsonHelper::SafelyDeserializeString(value, DNS_NAME);
m_ipAddress = JsonHelper::SafelyDeserializeString(value, IP_ADDRESS);
m_maximumPlayerSessionCount = JsonHelper::SafelyDeserializeInt(value, MAXIMUM_PLAYER_SESSION_COUNT);
m_port = JsonHelper::SafelyDeserializeInt(value, PORT);
if (value.HasMember(GAME_PROPERTIES) && !value[GAME_PROPERTIES].IsNull()) {
for (auto itr = value[GAME_PROPERTIES].MemberBegin(); itr != value[GAME_PROPERTIES].MemberEnd(); ++itr) {
if (itr->name.IsString() && itr->value.IsString()) {
m_gameProperties[itr->name.GetString()] = itr->value.GetString();
}
}
}
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketGameSession &gameSession) {
const WebSocketGameSession *message = &gameSession;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,107 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <aws/gamelift/internal/model/WebSocketPlayer.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
#include <iostream>
#include <spdlog/spdlog.h>
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wshadow" // Ignore shadow variable warning for Linux/Mac
#endif
namespace Aws {
namespace GameLift {
namespace Internal {
std::string WebSocketPlayer::Serialize() const {
// Create the buffer & Writer for the object
rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
// Start the object and call Serialize to serialize.
writer.StartObject();
if (Serialize(&writer)) {
writer.EndObject();
return buffer.GetString();
}
spdlog::warn("Could not parse into WebSocketPlayer");
return "";
}
bool WebSocketPlayer::Deserialize(const std::string &jsonString) {
// Parse the json into a document
rapidjson::Document doc;
if (doc.Parse(jsonString.c_str()).HasParseError()) {
spdlog::error("WebSocketPlayer: Parse error found for: {}", jsonString);
return false;
}
// Call Deserialize to populate the object's member variables
return Deserialize(doc);
}
bool WebSocketPlayer::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
JsonHelper::WriteNonEmptyString(writer, PLAYER_ID, m_playerId);
writer->String(PLAYER_ATTRIBUTES);
writer->StartObject();
for (auto const &playerAttributesIter : m_playerAttributes) {
writer->String(playerAttributesIter.first.c_str());
writer->StartObject();
playerAttributesIter.second.Serialize(writer);
writer->EndObject();
}
writer->EndObject();
writer->String(LATENCY_IN_MS);
writer->StartObject();
for (auto const &latencyMsIter : m_latencyInMs) {
writer->String(latencyMsIter.first.c_str());
writer->Int(latencyMsIter.second);
}
writer->EndObject();
JsonHelper::WriteNonEmptyString(writer, TEAM, m_team);
return true;
}
bool WebSocketPlayer::Deserialize(const rapidjson::Value &value) {
m_playerId = JsonHelper::SafelyDeserializeString(value, PLAYER_ID);
m_team = JsonHelper::SafelyDeserializeString(value, TEAM);
if (value.HasMember(PLAYER_ATTRIBUTES) && !value[PLAYER_ATTRIBUTES].IsNull()) {
for (auto itr = value[PLAYER_ATTRIBUTES].MemberBegin(); itr != value[PLAYER_ATTRIBUTES].MemberEnd(); ++itr) {
if (itr->name.IsString() && !itr->value.IsNull()) {
WebSocketAttributeValue value;
value.Deserialize(itr->value);
m_playerAttributes[itr->name.GetString()] = value;
}
}
}
if (value.HasMember(LATENCY_IN_MS) && !value[LATENCY_IN_MS].IsNull()) {
for (auto itr = value[LATENCY_IN_MS].MemberBegin(); itr != value[LATENCY_IN_MS].MemberEnd(); ++itr) {
if (itr->name.IsString() && itr->value.IsInt()) {
m_latencyInMs[itr->name.GetString()] = itr->value.GetInt();
}
}
}
return true;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,49 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include <aws/gamelift/internal/model/WebSocketPlayerSession.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketPlayerSession::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_ID, m_playerSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_ID, m_playerId);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, FLEET_ID, m_fleetId);
JsonHelper::WritePositiveInt64(writer, CREATION_TIME, m_creationTime);
JsonHelper::WritePositiveInt64(writer, TERMINATION_TIME, m_terminationTime);
JsonHelper::WriteNonEmptyString(writer, STATUS, WebSocketPlayerSessionStatusMapper::GetNameForStatus(m_status));
JsonHelper::WriteNonEmptyString(writer, IP_ADDRESS, m_ipAddress);
JsonHelper::WritePositiveInt(writer, PORT, m_port);
JsonHelper::WriteNonEmptyString(writer, PLAYER_DATA, m_playerData);
JsonHelper::WriteNonEmptyString(writer, DNS_NAME, m_dnsName);
return true;
}
bool WebSocketPlayerSession::Deserialize(const rapidjson::Value &value) {
m_playerSessionId = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_ID);
m_playerId = JsonHelper::SafelyDeserializeString(value, PLAYER_ID);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_fleetId = JsonHelper::SafelyDeserializeString(value, FLEET_ID);
m_creationTime = JsonHelper::SafelyDeserializeInt64(value, CREATION_TIME);
m_terminationTime = JsonHelper::SafelyDeserializeInt64(value, TERMINATION_TIME);
m_status = WebSocketPlayerSessionStatusMapper::GetStatusForName(JsonHelper::SafelyDeserializeString(value, STATUS));
m_ipAddress = JsonHelper::SafelyDeserializeString(value, IP_ADDRESS);
m_port = JsonHelper::SafelyDeserializeInt(value, PORT);
m_playerData = JsonHelper::SafelyDeserializeString(value, PLAYER_DATA);
m_dnsName = JsonHelper::SafelyDeserializeString(value, DNS_NAME);
return true;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,75 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/adapter/DescribePlayerSessionsAdapter.h>
#include <aws/gamelift/common/GameLift_EXPORTS.h>
#include <aws/gamelift/server/model/PlayerSession.h>
#include <aws/gamelift/server/model/PlayerSessionStatus.h>
namespace Aws {
namespace GameLift {
namespace Internal {
Server::Model::DescribePlayerSessionsResult DescribePlayerSessionsAdapter::convert(const WebSocketDescribePlayerSessionsResponse *webSocketResponse) {
Server::Model::DescribePlayerSessionsResult result;
#ifdef GAMELIFT_USE_STD
result.SetNextToken(webSocketResponse->GetNextToken());
for (auto &webSocketPlayerSession : webSocketResponse->GetPlayerSessions()) {
Server::Model::PlayerSession playerSession =
Server::Model::PlayerSession()
.WithPlayerSessionId(webSocketPlayerSession.GetPlayerSessionId())
.WithPlayerId(webSocketPlayerSession.GetPlayerId())
.WithGameSessionId(webSocketPlayerSession.GetGameSessionId())
.WithFleetId(webSocketPlayerSession.GetFleetId())
.WithCreationTime(webSocketPlayerSession.GetCreationTime())
.WithTerminationTime(webSocketPlayerSession.GetTerminationTime())
.WithStatus(static_cast<Server::Model::PlayerSessionStatus>(static_cast<int>(webSocketPlayerSession.GetStatus())))
.WithIpAddress(webSocketPlayerSession.GetIpAddress())
.WithPort(webSocketPlayerSession.GetPort())
.WithPlayerData(webSocketPlayerSession.GetPlayerData())
.WithDnsName(webSocketPlayerSession.GetDnsName());
result.AddPlayerSession(playerSession);
}
#else
result.SetNextToken(webSocketResponse->GetNextToken().c_str());
for (auto &webSocketPlayerSession : webSocketResponse->GetPlayerSessions()) {
Server::Model::PlayerSession playerSession =
Server::Model::PlayerSession()
.WithPlayerSessionId(webSocketPlayerSession.GetPlayerSessionId().c_str())
.WithPlayerId(webSocketPlayerSession.GetPlayerId().c_str())
.WithGameSessionId(webSocketPlayerSession.GetGameSessionId().c_str())
.WithFleetId(webSocketPlayerSession.GetFleetId().c_str())
.WithCreationTime(webSocketPlayerSession.GetCreationTime())
.WithTerminationTime(webSocketPlayerSession.GetTerminationTime())
.WithStatus(static_cast<Server::Model::PlayerSessionStatus>(static_cast<int>(webSocketPlayerSession.GetStatus())))
.WithIpAddress(webSocketPlayerSession.GetIpAddress().c_str())
.WithPort(webSocketPlayerSession.GetPort())
.WithPlayerData(webSocketPlayerSession.GetPlayerData().c_str())
.WithDnsName(webSocketPlayerSession.GetDnsName().c_str());
result.AddPlayerSession(playerSession);
}
#endif
return result;
}
WebSocketDescribePlayerSessionsRequest DescribePlayerSessionsAdapter::convert(const Server::Model::DescribePlayerSessionsRequest &request) {
return WebSocketDescribePlayerSessionsRequest()
.WithGameSessionId(request.GetGameSessionId())
.WithPlayerId(request.GetPlayerId())
.WithPlayerSessionId(request.GetPlayerSessionId())
.WithPlayerSessionStatusFilter(request.GetPlayerSessionStatusFilter())
.WithNextToken(request.GetNextToken())
.WithLimit(request.GetLimit());
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/adapter/GetFleetRoleCredentialsAdapter.h>
namespace Aws {
namespace GameLift {
namespace Internal {
Server::Model::GetFleetRoleCredentialsResult GetFleetRoleCredentialsAdapter::convert(const WebSocketGetFleetRoleCredentialsResponse *webSocketResponse) {
Server::Model::GetFleetRoleCredentialsResult result;
result.SetAssumedUserRoleArn(webSocketResponse->GetAssumedRoleUserArn().c_str());
result.SetAssumedRoleId(webSocketResponse->GetAssumedRoleId().c_str());
result.SetAccessKeyId(webSocketResponse->GetAccessKeyId().c_str());
result.SetSecretAccessKey(webSocketResponse->GetSecretAccessKey().c_str());
result.SetSessionToken(webSocketResponse->GetSessionToken().c_str());
// time_t is Unix epoch in seconds, and webSocketResponse->GetExpiration() returns time in milliseconds
// This is why we are dividing webSocketResponse->GetExpiration() by 1000
int64_t expirationTimeInMilliSeconds = webSocketResponse->GetExpiration();
int64_t expirationTimeInSeconds = expirationTimeInMilliSeconds / 1000;
result.SetExpiration(static_cast<time_t>(expirationTimeInSeconds));
return result;
}
WebSocketGetFleetRoleCredentialsRequest GetFleetRoleCredentialsAdapter::convert(const Server::Model::GetFleetRoleCredentialsRequest &request) {
return WebSocketGetFleetRoleCredentialsRequest().WithRoleArn(request.GetRoleArn()).WithRoleSessionName(request.GetRoleSessionName());
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,157 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/adapter/StartMatchBackfillAdapter.h>
namespace Aws {
namespace GameLift {
namespace Internal {
Server::Model::StartMatchBackfillResult StartMatchBackfillAdapter::convert(const WebSocketStartMatchBackfillResponse *webSocketResponse) {
Server::Model::StartMatchBackfillResult result;
if (webSocketResponse) {
result.SetTicketId(webSocketResponse->GetTicketId().c_str());
}
return result;
}
WebSocketStartMatchBackfillRequest StartMatchBackfillAdapter::convert(const Server::Model::StartMatchBackfillRequest &request) {
std::vector<Server::Model::Player> requestPlayersAsVector;
#ifdef GAMELIFT_USE_STD
requestPlayersAsVector = request.GetPlayers();
#else
int countOfPlayers;
const Server::Model::Player *requestPlayers = request.GetPlayers(countOfPlayers);
for (int i = 0; i < countOfPlayers; i++) {
Server::Model::Player playerToStore = *(requestPlayers + i);
requestPlayersAsVector.push_back(playerToStore);
}
#endif
std::vector<WebSocketPlayer> players;
for (auto it = requestPlayersAsVector.begin(); it != requestPlayersAsVector.end(); ++it) {
Server::Model::Player playerToConvert = *it;
WebSocketPlayer player = WebSocketPlayer()
.WithPlayerId(playerToConvert.GetPlayerId())
.WithTeam(playerToConvert.GetTeam())
.WithPlayerAttributes(fetchAndConvertAttributes(playerToConvert))
.WithLatencyInMs(fetchAndConvertLatency(playerToConvert));
players.push_back(player);
}
return WebSocketStartMatchBackfillRequest()
.WithTicketId(request.GetTicketId())
.WithGameSessionArn(request.GetGameSessionArn())
.WithMatchmakingConfigurationArn(request.GetMatchmakingConfigurationArn())
.WithPlayers(players);
}
std::map<std::string, int> StartMatchBackfillAdapter::fetchAndConvertLatency(const Server::Model::Player &player) {
std::map<std::string, int> result;
#ifdef GAMELIFT_USE_STD
result = player.GetLatencyInMs();
#else
int countOfLatencies;
const Server::Model::Player::RegionAndLatency *regionAndLatency = player.GetLatencyMs(countOfLatencies);
for (int i = 0; i < countOfLatencies; i++) {
Server::Model::Player::RegionAndLatency latencyToConvert = *(regionAndLatency + i);
result[latencyToConvert.GetRegion()] = latencyToConvert.GetLatencyMs();
}
#endif
return result;
}
std::map<std::string, WebSocketAttributeValue> StartMatchBackfillAdapter::fetchAndConvertAttributes(const Server::Model::Player &player) {
std::map<std::string, Server::Model::AttributeValue> attrs;
#ifdef GAMELIFT_USE_STD
attrs = player.GetPlayerAttributes();
#else
int countOfAttributes;
const Server::Model::Player::NamedAttribute *attributes = player.GetPlayerAttributes(countOfAttributes);
for (int i = 0; i < countOfAttributes; i++) {
Server::Model::Player::NamedAttribute attributeToConvert = *(attributes + i);
attrs[attributeToConvert.GetName()] = attributeToConvert.GetValue();
}
#endif
std::map<std::string, WebSocketAttributeValue> result;
for (auto const &attr : attrs) {
Server::Model::AttributeValue attributeValue = attr.second;
WebSocketAttributeValue value;
switch (attributeValue.GetType()) {
case Server::Model::AttributeValue::AttrType::NONE:
value.SetAttributeType(WebSocketAttrType::NONE);
break;
case Server::Model::AttributeValue::AttrType::STRING:
value.SetAttributeType(WebSocketAttrType::STRING);
value.SetS(attributeValue.GetS());
break;
case Server::Model::AttributeValue::AttrType::DOUBLE:
value.SetAttributeType(WebSocketAttrType::DOUBLE);
value.SetN(attributeValue.GetN());
break;
case Server::Model::AttributeValue::AttrType::STRING_LIST:
value.SetAttributeType(WebSocketAttrType::STRING_LIST);
value.SetSL(convertStringList(attributeValue));
break;
case Server::Model::AttributeValue::AttrType::STRING_DOUBLE_MAP:
value.SetAttributeType(WebSocketAttrType::STRING_DOUBLE_MAP);
value.SetSDM(convertStringDoubleMap(attributeValue));
break;
default:
value.SetAttributeType(WebSocketAttrType::NONE);
break;
}
result[attr.first] = value;
}
return result;
}
std::vector<std::string> StartMatchBackfillAdapter::convertStringList(const Server::Model::AttributeValue &attributeValue) {
std::vector<std::string> result;
#ifdef GAMELIFT_USE_STD
result = attributeValue.GetSL();
#else
int countOfStringList;
const Server::Model::AttributeValue::AttributeStringType *stringList = attributeValue.GetSL(countOfStringList);
for (int i = 0; i < countOfStringList; i++) {
const Server::Model::AttributeValue::AttributeStringType *stringListItemPointer = stringList + i;
std::string itemAsString = std::string(*stringListItemPointer);
result.push_back(itemAsString);
}
#endif
return result;
}
std::map<std::string, double> StartMatchBackfillAdapter::convertStringDoubleMap(const Server::Model::AttributeValue &attributeValue) {
std::map<std::string, double> result;
#ifdef GAMELIFT_USE_STD
result = attributeValue.GetSDM();
#else
int countOfStringMap;
const Server::Model::AttributeValue::KeyAndValue *stringAndDoubleMap = attributeValue.GetSDM(countOfStringMap);
for (int i = 0; i < countOfStringMap; i++) {
Server::Model::AttributeValue::KeyAndValue keyAndValue = *(stringAndDoubleMap + i);
std::string key = std::string(keyAndValue.GetKey());
result[key] = keyAndValue.GetValue();
}
#endif
return result;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,71 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/message/CreateGameSessionMessage.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool CreateGameSessionMessage::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_NAME, m_gameSessionName);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_DATA, m_gameSessionData);
JsonHelper::WriteNonEmptyString(writer, MATCHMAKER_DATA, m_matchmakerData);
JsonHelper::WriteNonEmptyString(writer, DNS_NAME, m_dnsName);
JsonHelper::WriteNonEmptyString(writer, IP_ADDRESS, m_ipAddress);
JsonHelper::WritePositiveInt(writer, MAXIMUM_PLAYER_SESSION_COUNT, m_maximumPlayerSessionCount);
JsonHelper::WritePositiveInt(writer, PORT, m_port);
writer->String(GAME_PROPERTIES);
writer->StartObject();
for (auto const &property : m_gameProperties) {
writer->String(property.first.c_str());
writer->String(property.second.c_str());
}
writer->EndObject();
return true;
}
bool CreateGameSessionMessage::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_gameSessionName = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_NAME);
m_gameSessionData = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_DATA);
m_matchmakerData = JsonHelper::SafelyDeserializeString(value, MATCHMAKER_DATA);
m_dnsName = JsonHelper::SafelyDeserializeString(value, DNS_NAME);
m_ipAddress = JsonHelper::SafelyDeserializeString(value, IP_ADDRESS);
m_maximumPlayerSessionCount = JsonHelper::SafelyDeserializeInt(value, MAXIMUM_PLAYER_SESSION_COUNT);
m_port = JsonHelper::SafelyDeserializeInt(value, PORT);
if (value.HasMember(GAME_PROPERTIES) && !value[GAME_PROPERTIES].IsNull()) {
for (auto itr = value[GAME_PROPERTIES].MemberBegin(); itr != value[GAME_PROPERTIES].MemberEnd(); ++itr) {
if (itr->name.IsString() && itr->value.IsString()) {
m_gameProperties[itr->name.GetString()] = itr->value.GetString();
}
}
}
return true;
}
std::ostream &operator<<(std::ostream &os, const CreateGameSessionMessage &createGameSessionMessage) {
const Message *message = &createGameSessionMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/message/RefreshConnectionMessage.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool RefreshConnectionMessage::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, REFRESH_CONNECTION_ENDPOINT, m_refreshConnectionEndpoint);
JsonHelper::WriteNonEmptyString(writer, AUTH_TOKEN, m_authToken);
return true;
}
bool RefreshConnectionMessage::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_refreshConnectionEndpoint = JsonHelper::SafelyDeserializeString(value, REFRESH_CONNECTION_ENDPOINT);
m_authToken = JsonHelper::SafelyDeserializeString(value, AUTH_TOKEN);
return true;
}
std::ostream &operator<<(std::ostream &os, const RefreshConnectionMessage &refreshConnectionMessage) {
const Message *message = &refreshConnectionMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/message/TerminateProcessMessage.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool TerminateProcessMessage::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WritePositiveInt64(writer, TERMINATION_TIME, m_terminationTime);
return true;
}
bool TerminateProcessMessage::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_terminationTime = JsonHelper::SafelyDeserializeInt64(value, TERMINATION_TIME);
return true;
}
std::ostream &operator<<(std::ostream &os, const TerminateProcessMessage &terminateProcessMessage) {
const Message *message = &terminateProcessMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,56 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/message/UpdateGameSessionMessage.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool UpdateGameSessionMessage::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
// Serialize game session object
writer->String(GAME_SESSION);
writer->StartObject();
m_gameSession.Serialize(writer);
writer->EndObject();
// Serialize update game session fields
JsonHelper::WriteNonEmptyString(writer, UPDATE_REASON, m_updateReason);
JsonHelper::WriteNonEmptyString(writer, BACKFILL_TICKET_ID, m_backfillTicketId);
return true;
}
bool UpdateGameSessionMessage::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
// Deserialize GameSession
WebSocketGameSession gameSession;
if (value.HasMember(GAME_SESSION) && !value[GAME_SESSION].IsNull()) {
gameSession.Deserialize(value[GAME_SESSION]);
}
m_gameSession = gameSession;
// Deserialize rest of fields
m_updateReason = JsonHelper::SafelyDeserializeString(value, UPDATE_REASON);
m_backfillTicketId = JsonHelper::SafelyDeserializeString(value, BACKFILL_TICKET_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const UpdateGameSessionMessage &updateGameSessionMessage) {
const Message *message = &updateGameSessionMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/AcceptPlayerSessionRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool AcceptPlayerSessionRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_ID, m_playerSessionId);
return true;
}
bool AcceptPlayerSessionRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_playerSessionId = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const AcceptPlayerSessionRequest &acceptPlayerSessionRequest) {
const Message *message = &acceptPlayerSessionRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/ActivateGameSessionRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
ActivateGameSessionRequest::ActivateGameSessionRequest() { SetAction(ACTIVATE_GAME_SESSION); }
ActivateGameSessionRequest::ActivateGameSessionRequest(std::string gameSessionId) : m_gameSessionId(gameSessionId) { SetAction(ACTIVATE_GAME_SESSION); }
bool ActivateGameSessionRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
return true;
}
bool ActivateGameSessionRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const ActivateGameSessionRequest &activateGameSessionRequest) {
const Message *message = &activateGameSessionRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,59 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/ActivateServerProcessRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
ActivateServerProcessRequest::ActivateServerProcessRequest() : m_port(-1) { SetAction(ACTIVATE_SERVER_PROCESS); }
ActivateServerProcessRequest::ActivateServerProcessRequest(std::string sdkVersion, std::string sdkLanguage,
std::string sdkToolName, std::string sdkToolVersion, int port,
const Aws::GameLift::Server::LogParameters &logParameters)
: m_sdkVersion(sdkVersion), m_sdkLanguage(sdkLanguage), m_sdkToolName(sdkToolName), m_sdkToolVersion(sdkToolVersion), m_port(port), m_logParameters(logParameters) {
SetAction(ACTIVATE_SERVER_PROCESS);
};
bool ActivateServerProcessRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, SDK_VERSION, m_sdkVersion);
JsonHelper::WriteNonEmptyString(writer, SDK_LANGUAGE, m_sdkLanguage);
JsonHelper::WriteNonEmptyString(writer, SDK_TOOL_NAME, m_sdkToolName);
JsonHelper::WriteNonEmptyString(writer, SDK_TOOL_VERSION, m_sdkToolVersion);
JsonHelper::WritePositiveInt(writer, PORT, m_port);
JsonHelper::WriteLogParameters(writer, LOG_PATHS, m_logParameters);
return true;
}
bool ActivateServerProcessRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_sdkVersion = JsonHelper::SafelyDeserializeString(value, SDK_VERSION);
m_sdkLanguage = JsonHelper::SafelyDeserializeString(value, SDK_LANGUAGE);
m_sdkToolName = JsonHelper::SafelyDeserializeString(value, SDK_TOOL_NAME);
m_sdkToolVersion = JsonHelper::SafelyDeserializeString(value, SDK_TOOL_VERSION);
m_port = JsonHelper::SafelyDeserializeInt(value, PORT);
m_logParameters = JsonHelper::SafelyDeserializeLogParameters(value, LOG_PATHS);
return true;
}
std::ostream &operator<<(std::ostream &os, const ActivateServerProcessRequest &activateServerProcessRequest) {
const Message *message = &activateServerProcessRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/HeartbeatServerProcessRequest.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool HeartbeatServerProcessRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
writer->String(HEALTH_STATUS);
writer->Bool(m_healthy);
return true;
}
bool HeartbeatServerProcessRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_healthy = value.HasMember(HEALTH_STATUS) && value[HEALTH_STATUS].IsBool() ? value[HEALTH_STATUS].GetBool() : false;
return true;
}
std::ostream &operator<<(std::ostream &os, const HeartbeatServerProcessRequest &heartbeatServerProcessRequest) {
const Message *message = &heartbeatServerProcessRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/RemovePlayerSessionRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool RemovePlayerSessionRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_ID, m_playerSessionId);
return true;
}
bool RemovePlayerSessionRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_playerSessionId = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const RemovePlayerSessionRequest &removePlayerSessionRequest) {
const Message *message = &removePlayerSessionRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,23 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/TerminateServerProcessRequest.h>
namespace Aws {
namespace GameLift {
namespace Internal {
TerminateServerProcessRequest::TerminateServerProcessRequest() { SetAction(TERMINATE_SERVER_PROCESS); }
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,42 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/UpdatePlayerSessionCreationPolicyRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool UpdatePlayerSessionCreationPolicyRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_POLICY, GetPlayerSessionCreationPolicyAsString());
return true;
}
bool UpdatePlayerSessionCreationPolicyRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
std::string policyAsString = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_POLICY);
SetPlayerSessionCreationPolicy(policyAsString);
return true;
}
std::ostream &operator<<(std::ostream &os, const UpdatePlayerSessionCreationPolicyRequest &updatePlayerSessionCreationPolicyRequest) {
const Message *message = &updatePlayerSessionCreationPolicyRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/WebSocketDescribePlayerSessionsRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketDescribePlayerSessionsRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ID, m_gameSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_ID, m_playerId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_ID, m_playerSessionId);
JsonHelper::WriteNonEmptyString(writer, PLAYER_SESSION_STATUS_FILTER, m_playerSessionStatusFilter);
JsonHelper::WriteNonEmptyString(writer, NEXT_TOKEN, m_nextToken);
JsonHelper::WritePositiveInt(writer, LIMIT, m_limit);
return true;
}
bool WebSocketDescribePlayerSessionsRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionId = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ID);
m_playerId = JsonHelper::SafelyDeserializeString(value, PLAYER_ID);
m_playerSessionId = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_ID);
m_playerSessionStatusFilter = JsonHelper::SafelyDeserializeString(value, PLAYER_SESSION_STATUS_FILTER);
m_nextToken = JsonHelper::SafelyDeserializeString(value, NEXT_TOKEN);
m_limit = JsonHelper::SafelyDeserializeInt(value, LIMIT);
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketDescribePlayerSessionsRequest &describePlayerSessionsRequest) {
const Message *message = &describePlayerSessionsRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,35 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/WebSocketGetComputeCertificateRequest.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketGetComputeCertificateRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
return true;
}
bool WebSocketGetComputeCertificateRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketGetComputeCertificateRequest &getComputeCertificateRequest) {
const Message *message = &getComputeCertificateRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/WebSocketGetFleetRoleCredentialsRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketGetFleetRoleCredentialsRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, ROLE_ARN, m_roleArn);
JsonHelper::WriteNonEmptyString(writer, ROLE_SESSION_NAME, m_roleSessionName);
return true;
}
bool WebSocketGetFleetRoleCredentialsRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_roleArn = JsonHelper::SafelyDeserializeString(value, ROLE_ARN);
m_roleSessionName = JsonHelper::SafelyDeserializeString(value, ROLE_SESSION_NAME);
return true;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,71 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/WebSocketStartMatchBackfillRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
WebSocketStartMatchBackfillRequest::WebSocketStartMatchBackfillRequest() { SetAction(ACTION); };
bool WebSocketStartMatchBackfillRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, TICKET_ID, m_ticketId);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ARN, m_gameSessionArn);
JsonHelper::WriteNonEmptyString(writer, MATCHMAKING_CONFIGURATION_ARN, m_matchmakingConfigurationArn);
writer->String(PLAYERS);
writer->StartArray();
for (const WebSocketPlayer &player : m_players) {
writer->StartObject();
player.Serialize(writer);
writer->EndObject();
}
writer->EndArray();
return true;
}
bool WebSocketStartMatchBackfillRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_ticketId = JsonHelper::SafelyDeserializeString(value, TICKET_ID);
m_gameSessionArn = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ARN);
m_matchmakingConfigurationArn = JsonHelper::SafelyDeserializeString(value, MATCHMAKING_CONFIGURATION_ARN);
m_players.clear();
if (value.HasMember(PLAYERS) && !value[PLAYERS].IsNull()) {
auto playerList = value[PLAYERS].GetArray();
for (rapidjson::SizeType i = 0; i < playerList.Size(); i++) {
auto &player = playerList[i];
if (!player.IsNull()) {
WebSocketPlayer webSocketPlayer;
webSocketPlayer.Deserialize(player);
m_players.push_back(webSocketPlayer);
}
}
}
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketStartMatchBackfillRequest &startMatchBackfillRequest) {
const Message *message = &startMatchBackfillRequest;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/request/WebSocketStopMatchBackfillRequest.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketStopMatchBackfillRequest::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, GAME_SESSION_ARN, m_gameSessionArn);
JsonHelper::WriteNonEmptyString(writer, MATCHMAKING_CONFIG_ARN, m_matchmakingConfigurationArn);
JsonHelper::WriteNonEmptyString(writer, TICKET_ID, m_ticketId);
return true;
}
bool WebSocketStopMatchBackfillRequest::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_gameSessionArn = JsonHelper::SafelyDeserializeString(value, GAME_SESSION_ARN);
m_matchmakingConfigurationArn = JsonHelper::SafelyDeserializeString(value, MATCHMAKING_CONFIG_ARN);
m_ticketId = JsonHelper::SafelyDeserializeString(value, TICKET_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketStopMatchBackfillRequest &stopMatchBackfillMessage) {
const Message *message = &stopMatchBackfillMessage;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,63 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/response/WebSocketDescribePlayerSessionsResponse.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketDescribePlayerSessionsResponse::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, NEXT_TOKEN, m_nextToken);
writer->String(PLAYER_SESSIONS);
writer->StartArray();
for (const WebSocketPlayerSession &playerSession : m_playerSessions) {
writer->StartObject();
playerSession.Serialize(writer);
writer->EndObject();
}
writer->EndArray();
return true;
}
bool WebSocketDescribePlayerSessionsResponse::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_nextToken = JsonHelper::SafelyDeserializeString(value, NEXT_TOKEN);
m_playerSessions.clear();
if (value.HasMember(PLAYER_SESSIONS) && !value[PLAYER_SESSIONS].IsNull()) {
auto playerSessions = value[PLAYER_SESSIONS].GetArray();
for (rapidjson::SizeType i = 0; i < playerSessions.Size(); i++) {
auto &playerSession = playerSessions[i];
if (!playerSession.IsNull()) {
WebSocketPlayerSession webSocketPlayerSession;
webSocketPlayerSession.Deserialize(playerSession);
m_playerSessions.push_back(webSocketPlayerSession);
}
}
}
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketDescribePlayerSessionsResponse &describePlayerSessionsResponse) {
const Message *message = &describePlayerSessionsResponse;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,44 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/response/WebSocketGetComputeCertificateResponse.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketGetComputeCertificateResponse::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, COMPUTE_NAME, m_computeName);
JsonHelper::WriteNonEmptyString(writer, CERTIFICATE_PATH, m_certificatePath);
return true;
}
bool WebSocketGetComputeCertificateResponse::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_computeName = JsonHelper::SafelyDeserializeString(value, COMPUTE_NAME);
m_certificatePath = JsonHelper::SafelyDeserializeString(value, CERTIFICATE_PATH);
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketGetComputeCertificateResponse &webSocketGetComputeCertificateResponse) {
const Message *message = &webSocketGetComputeCertificateResponse;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,46 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/response/WebSocketGetFleetRoleCredentialsResponse.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketGetFleetRoleCredentialsResponse::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, ASSUMED_ROLE_USER_ARN, m_assumedRoleUserArn);
JsonHelper::WriteNonEmptyString(writer, ASSUMED_ROLE_ID, m_assumedRoleId);
JsonHelper::WriteNonEmptyString(writer, ACCESS_KEY_ID, m_accessKeyId);
JsonHelper::WriteNonEmptyString(writer, SECRET_ACCESS_KEY, m_secretAccessKey);
JsonHelper::WriteNonEmptyString(writer, SESSION_TOKEN, m_sessionToken);
JsonHelper::WritePositiveInt64(writer, EXPIRATION, m_expiration);
return true;
}
bool WebSocketGetFleetRoleCredentialsResponse::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_assumedRoleUserArn = JsonHelper::SafelyDeserializeString(value, ASSUMED_ROLE_USER_ARN);
m_assumedRoleId = JsonHelper::SafelyDeserializeString(value, ASSUMED_ROLE_ID);
m_accessKeyId = JsonHelper::SafelyDeserializeString(value, ACCESS_KEY_ID);
m_secretAccessKey = JsonHelper::SafelyDeserializeString(value, SECRET_ACCESS_KEY);
m_sessionToken = JsonHelper::SafelyDeserializeString(value, SESSION_TOKEN);
m_expiration = JsonHelper::SafelyDeserializeInt64(value, EXPIRATION);
return true;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/model/response/WebSocketStartMatchBackfillResponse.h>
#include <aws/gamelift/internal/util/JsonHelper.h>
namespace Aws {
namespace GameLift {
namespace Internal {
bool WebSocketStartMatchBackfillResponse::Serialize(rapidjson::Writer<rapidjson::StringBuffer> *writer) const {
Message::Serialize(writer);
JsonHelper::WriteNonEmptyString(writer, TICKET_ID, m_ticketId);
return true;
}
bool WebSocketStartMatchBackfillResponse::Deserialize(const rapidjson::Value &value) {
Message::Deserialize(value);
m_ticketId = JsonHelper::SafelyDeserializeString(value, TICKET_ID);
return true;
}
std::ostream &operator<<(std::ostream &os, const WebSocketStartMatchBackfillResponse &startMatchBackfillResponse) {
const Message *message = &startMatchBackfillResponse;
os << message->Serialize();
return os;
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,83 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/GameLiftWebSocketClientManager.h>
#include <aws/gamelift/internal/GameLiftServerState.h>
#include <aws/gamelift/internal/model/response/WebSocketDescribePlayerSessionsResponse.h>
#include <aws/gamelift/internal/util/RandomStringGenerator.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome GameLiftWebSocketClientManager::Connect(std::string websocketUrl, const std::string &authToken, const std::string &processId,
const std::string &hostId, const std::string &fleetId, const std::map<std::string, std::string> &sigV4QueryParameters) {
spdlog::info("Connecting to GameLift WebSocket server. websocketUrl: {}, processId: {}, hostId: {}, fleetId: {}",
websocketUrl.c_str(), processId.c_str(), hostId.c_str(), fleetId.c_str());
// Due to the websocket library we're using, base URLs must end with a "/". Ensure that it is
// present.
if (!EndsWith(websocketUrl, REQUIRED_URL_ENDING)) {
websocketUrl = websocketUrl + REQUIRED_URL_ENDING;
}
// Build the WebSocket URI
std::string sdkVersion = Server::GetSdkVersion().GetResult();
std::string idempotencyToken = RandomStringGenerator::GenerateRandomAlphaNumericString(32);
Uri::UriBuilder uriBuilder = Uri::UriBuilder()
.WithBaseUri(websocketUrl)
.AddQueryParam(PID_KEY, processId)
.AddQueryParam(SDK_VERSION_KEY, sdkVersion)
.AddQueryParam(FLAVOR_KEY, GameLiftServerState::LANGUAGE)
.AddQueryParam(COMPUTE_ID_KEY, hostId)
.AddQueryParam(FLEET_ID_KEY, fleetId)
.AddQueryParam(IDEMPOTENCY_TOKEN_KEY, idempotencyToken);
if (!authToken.empty()) {
uriBuilder.AddQueryParam(AUTH_TOKEN_KEY, authToken);
} else if (!sigV4QueryParameters.empty()) {
for (auto sigV4QueryParameter: sigV4QueryParameters) {
uriBuilder.AddQueryParam(sigV4QueryParameter.first, sigV4QueryParameter.second);
}
}
Uri uri = uriBuilder.Build();
// delegate to the websocket client wrapper to connect
return m_webSocketClientWrapper->Connect(uri);
}
GenericOutcome GameLiftWebSocketClientManager::SendSocketMessage(Message &message) {
// Serialize the message
std::string jsonMessage = message.Serialize();
GenericOutcome outcome = m_webSocketClientWrapper->SendSocketMessage(message.GetRequestId(), jsonMessage);
return outcome;
}
void GameLiftWebSocketClientManager::Disconnect() { m_webSocketClientWrapper->Disconnect(); }
bool GameLiftWebSocketClientManager::EndsWith(const std::string &actualString, const std::string &ending) {
const int lengthDifference = (int)(actualString.length() - ending.length());
if (lengthDifference >= 0) {
return actualString.compare(lengthDifference, ending.length(), ending) == 0;
} else {
return false;
}
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,430 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/WebSocketppClientWrapper.h>
#include <aws/gamelift/internal/model/Message.h>
#include <aws/gamelift/internal/model/ResponseMessage.h>
#include <aws/gamelift/internal/retry/GeometricBackoffRetryStrategy.h>
#include <aws/gamelift/internal/retry/RetryingCallable.h>
#include <memory>
#include <websocketpp/error.hpp>
#include <spdlog/spdlog.h>
namespace Aws {
namespace GameLift {
namespace Internal {
WebSocketppClientWrapper::WebSocketppClientWrapper(std::shared_ptr<WebSocketppClientType> webSocketClient)
: m_webSocketClient(webSocketClient), m_connectionStateChanged(false) {
// configure logging. comment these out to get websocket logs on stdout for debugging
m_webSocketClient->clear_access_channels(websocketpp::log::alevel::all);
m_webSocketClient->clear_error_channels(websocketpp::log::elevel::all);
// initialize ASIO
m_webSocketClient->init_asio();
// start in perpetual mode (do not exit processing loop when there are no connections)
m_webSocketClient->start_perpetual();
// Kick off two threads that will own up to two parallel connections. These threads will live
// until the SDK is shutdown and alternate handling connections. If a connection fails to open,
// the thread will not hang. Instead, the thread will simply wait for another connection to
// appear in queue.
//
// Flow of logic in the two threads:
// --- SDK initialized ---
// socket_thread_1: waiting for connection...
// socket_thread_2: waiting for connection...
// --- Initial connection happens ---
// socket_thread_1: handling 1st connection
// socket_thread_2: waiting for connection...
// --- Connection refresh begins ---
// socket_thread_1: finish handling 1st connection messages
// socket_thread_2: handling 2nd connection
// --- Connection 1 closes ---
// socket_thread_1: waiting for connection...
// socket_thread_2: handling 2nd connection
// --- SDK shut down, and WebSocket client "->stop_perpetual()" is invoked ---
// socket_thread_1: No longer waits for a connection, thread ends
// socket_thread_2: Finishes handling 2nd connection, then thread ends
m_socket_thread_1 = std::unique_ptr<std::thread>(new std::thread([this] { m_webSocketClient->run(); }));
m_socket_thread_2 = std::unique_ptr<std::thread>(new std::thread([this] { m_webSocketClient->run(); }));
// Set callbacks
using std::placeholders::_1;
using std::placeholders::_2;
// Set timeout waiting for GameLift websocket server to respond on initial connection.
// See: https://github.com/zaphoyd/websocketpp/blob/master/websocketpp/connection.hpp#L501
m_webSocketClient->set_open_handshake_timeout(WEBSOCKET_OPEN_HANDSHAKE_TIMEOUT_MILLIS);
m_webSocketClient->set_tls_init_handler(std::bind(&WebSocketppClientWrapper::OnTlsInit, this, _1));
m_webSocketClient->set_open_handler(std::bind(&WebSocketppClientWrapper::OnConnected, this, _1));
m_webSocketClient->set_message_handler(std::bind(&WebSocketppClientWrapper::OnMessage, this, _1, _2));
m_webSocketClient->set_fail_handler(std::bind(&WebSocketppClientWrapper::OnError, this, _1));
m_webSocketClient->set_close_handler(std::bind(&WebSocketppClientWrapper::OnClose, this, _1));
m_webSocketClient->set_interrupt_handler(std::bind(&WebSocketppClientWrapper::OnInterrupt, this, _1));
}
WebSocketppClientWrapper::~WebSocketppClientWrapper() {
// stop perpetual mode, allowing the websocketClient to destroy itself
if (m_webSocketClient) {
m_webSocketClient->stop_perpetual();
}
spdlog::info("Destroying WebsocketPPClientWrapper");
// close connections and join the thread
if (m_connection && m_connection->get_state() == websocketpp::session::state::open) {
Disconnect();
}
if (m_socket_thread_1 && m_socket_thread_1->joinable()) {
m_socket_thread_1->join();
}
if (m_socket_thread_2 && m_socket_thread_2->joinable()) {
m_socket_thread_2->join();
}
}
GenericOutcome WebSocketppClientWrapper::Connect(const Uri &uri) {
spdlog::info("Opening Connection");
// Perform connection with retries.
// This attempts to start up a new websocket connection / thread
m_uri = uri;
websocketpp::lib::error_code errorCode;
GeometricBackoffRetryStrategy retryStrategy;
RetryingCallable callable = RetryingCallable::Builder()
.WithRetryStrategy(&retryStrategy)
.WithCallable([this, &uri, &errorCode] {
spdlog::info("Attempting to perform connection");
WebSocketppClientType::connection_ptr newConnection = PerformConnect(uri, errorCode);
if (newConnection && newConnection->get_state() == websocketpp::session::state::open) {
spdlog::info("Connection established, transitioning traffic");
// "Flip" traffic from our old websocket to our new websocket. Close the old one
// if necessary
WebSocketppClientType::connection_ptr oldConnection = m_connection;
m_connection = newConnection;
if (oldConnection && oldConnection->get_state() == websocketpp::session::state::open) {
spdlog::info("Closing previous connection");
websocketpp::lib::error_code closeErrorCode;
m_webSocketClient->close(oldConnection->get_handle(), websocketpp::close::status::going_away,
"Websocket client reconnecting", closeErrorCode);
if (errorCode.value()) {
spdlog::warn("Failed to close old websocket after a connection refresh, ignoring.");
}
}
return true;
} else {
spdlog::warn("Connection to Amazon GameLift Servers websocket server failed. Retrying connection if possible.");
return false;
}
})
.Build();
callable.call();
if (IsConnected()) {
spdlog::info("Connected to endpoint");
return GenericOutcome(nullptr);
} else {
spdlog::error("Connection to Amazon GameLift Servers websocket server failed. See error message in InitSDK() outcome for details.");
m_connection = nullptr;
switch (errorCode.value()) {
case websocketpp::error::server_only:
switch (m_fail_response_code) {
case websocketpp::http::status_code::value::forbidden:
return GenericOutcome(GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_FORBIDDEN);
default:
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE, errorCode.category().message(errorCode.value()).c_str(),
errorCode.message().c_str()));
}
case 11001: // Host not found
case websocketpp::error::invalid_uri:
return GenericOutcome(GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_INVALID_URL);
// case websocketpp::error::timeout:
case 0: // No Response after multiple retries, i.e. timeout
case websocketpp::error::open_handshake_timeout:
case websocketpp::error::close_handshake_timeout:
return GenericOutcome(GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_TIMEOUT);
case websocketpp::error::endpoint_not_secure:
case websocketpp::error::no_outgoing_buffers:
case websocketpp::error::no_incoming_buffers:
case websocketpp::error::invalid_state:
case websocketpp::error::bad_close_code:
case websocketpp::error::reserved_close_code:
case websocketpp::error::invalid_close_code:
case websocketpp::error::invalid_utf8:
case websocketpp::error::invalid_subprotocol:
case websocketpp::error::bad_connection:
case websocketpp::error::con_creation_failed:
case websocketpp::error::unrequested_subprotocol:
case websocketpp::error::client_only:
case websocketpp::error::http_connection_ended:
case websocketpp::error::invalid_port:
case websocketpp::error::async_accept_not_listening:
case websocketpp::error::upgrade_required:
case websocketpp::error::invalid_version:
case websocketpp::error::unsupported_version:
case websocketpp::error::http_parse_error:
case websocketpp::error::extension_neg_failed:
default:
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE, errorCode.category().message(errorCode.value()).c_str(),
errorCode.message().c_str()));
}
}
}
WebSocketppClientType::connection_ptr WebSocketppClientWrapper::PerformConnect(const Uri &uri, websocketpp::lib::error_code &errorCode) {
spdlog::info("Performing connection");
errorCode.clear();
// Create connection request
WebSocketppClientType::connection_ptr newConnection = m_webSocketClient->get_connection(uri.GetUriString(), errorCode);
if (errorCode.value()) {
spdlog::error("Failed to GetConnection. ERROR: {}", errorCode.message());
return newConnection;
} else {
spdlog::info("Connection request created successfully. Waiting for connection to establish...");
}
// Queue a new connection request (the socket thread will act on it and attempt to connect)
try {
m_webSocketClient->connect(newConnection);
}
catch (const std::exception& e) {
spdlog::error("Exception while trying to connect with the webSocketClient: {}", e.what());
}
spdlog::info("Connection request queued.");
// Wait for connection to succeed or fail (this makes connection synchronous)
{
std::unique_lock<std::mutex> lk(m_lock);
m_cond.wait(lk, [this] { return m_connectionStateChanged; });
spdlog::info("Connection state changed: {}", m_fail_error_code.message());
errorCode = m_fail_error_code;
// Reset
m_connectionStateChanged = false;
m_fail_error_code.clear();
}
if (errorCode.value()) {
spdlog::error("Connection failed with errorCode: {}", errorCode.message());
}
else {
spdlog::info("Connection established successfully.");
}
return newConnection;
}
GenericOutcome WebSocketppClientWrapper::SendSocketMessage(const std::string &requestId, const std::string &message) {
if (requestId.empty()) {
spdlog::error("Request does not have request ID, cannot process");
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::INTERNAL_SERVICE_EXCEPTION));
}
auto waitForReconnectRetryCount = 0;
while(!IsConnected()) {
// m_connection will be null if reconnect failed after max reties
if(m_connection == nullptr || ++waitForReconnectRetryCount >= WAIT_FOR_RECONNECT_MAX_RETRIES) {
spdlog::warn("WebSocket is not connected... WebSocket failed to send message due to an error.");
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_SEND_MESSAGE_FAILURE));
}
spdlog::warn("WebSocket is not connected... isConnected: {}", IsConnected());
std::this_thread::sleep_for(std::chrono::seconds(WAIT_FOR_RECONNECT_RETRY_DELAY_SECONDS));
}
std::future<GenericOutcome> responseFuture;
// Lock whenever we make use of 'm_requestIdToPromise' to avoid concurrent writes/reads
{
std::lock_guard<std::mutex> lock(m_requestToPromiseLock);
// This indicates we've already sent this message, and it's still in flight
if (m_requestIdToPromise.count(requestId) > 0) {
spdlog::error("Request {} already exists", requestId);
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::BAD_REQUEST_EXCEPTION));
}
std::promise<GenericOutcome> responsePromise;
responseFuture = responsePromise.get_future();
m_requestIdToPromise[requestId] = std::move(responsePromise);
}
GenericOutcome immediateResponse = SendSocketMessageAsync(message);
if (!immediateResponse.IsSuccess()) {
spdlog::error("Send Socket Message immediate response failed with error {}: {}",
immediateResponse.GetError().GetErrorName(), immediateResponse.GetError().GetErrorMessage());
std::lock_guard<std::mutex> lock(m_requestToPromiseLock);
m_requestIdToPromise.erase(requestId);
return immediateResponse;
}
std::future_status promiseStatus = responseFuture.wait_for(std::chrono::milliseconds(SERVICE_CALL_TIMEOUT_MILLIS));
if (promiseStatus == std::future_status::timeout) {
std::lock_guard<std::mutex> lock(m_requestToPromiseLock);
spdlog::error("Response not received within the time limit of {} ms for request {}", SERVICE_CALL_TIMEOUT_MILLIS, requestId);
spdlog::warn("isConnected: {}", IsConnected());
m_requestIdToPromise.erase(requestId);
// If a call times out, retry
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_RETRIABLE_SEND_MESSAGE_FAILURE));
}
return responseFuture.get();
}
GenericOutcome WebSocketppClientWrapper::SendSocketMessageAsync(const std::string &message) {
if (!m_connection) {
spdlog::error("Cannot send message: m_connection is null");
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_SEND_MESSAGE_FAILURE));
}
spdlog::info("Sending Socket Message, isConnected:{}", IsConnected());
websocketpp::lib::error_code errorCode;
m_webSocketClient->send(m_connection->get_handle(), message.c_str(), websocketpp::frame::opcode::text, errorCode);
if (errorCode.value()) {
spdlog::error("Error Sending Socket Message: {}", errorCode.value());
switch (errorCode.value()) {
case websocketpp::error::no_outgoing_buffers:
// If buffers are full, send will fail. Retryable since buffers can free up as messages
// send.
return GenericOutcome(GAMELIFT_ERROR_TYPE::WEBSOCKET_RETRIABLE_SEND_MESSAGE_FAILURE);
default:
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::WEBSOCKET_SEND_MESSAGE_FAILURE, errorCode.category().message(errorCode.value()).c_str(),
errorCode.message().c_str()));
}
}
return GenericOutcome(nullptr);
}
void WebSocketppClientWrapper::Disconnect() {
spdlog::info("Disconnecting WebSocket");
if (m_connection != nullptr) {
websocketpp::lib::error_code ec;
m_webSocketClient->close(m_connection->get_handle(), websocketpp::close::status::going_away, "Websocket client closing", ec);
if (ec) {
spdlog::error("Error initiating close: {}",ec.message());
}
m_connection = nullptr;
}
}
void WebSocketppClientWrapper::RegisterGameLiftCallback(const std::string &gameLiftEvent, const std::function<GenericOutcome(std::string)> &callback) {
spdlog::info("Registering GameLift CallBack for: {}", gameLiftEvent);
m_eventHandlers[gameLiftEvent] = callback;
}
bool WebSocketppClientWrapper::IsConnected() {
// m_connection is nullptr if 'm_webSocketClient->get_connection()' fails
return m_connection != nullptr && m_connection->get_state() == websocketpp::session::state::open;
}
void WebSocketppClientWrapper::OnConnected(websocketpp::connection_hdl connection) {
spdlog::info("Connected to WebSocket");
// aquire lock and set condition variables (let main thread know connection is successful)
{
std::lock_guard<std::mutex> lk(m_lock);
// set the state change variables and notify the thread that is connecting
m_connectionStateChanged = true;
}
m_cond.notify_one();
}
void WebSocketppClientWrapper::OnError(websocketpp::connection_hdl connection) {
auto con = m_webSocketClient->get_con_from_hdl(connection);
spdlog::error("Error Connecting to WebSocket");
// aquire lock and set condition variables (let main thread know an error has occurred)
{
std::lock_guard<std::mutex> lk(m_lock);
// set the state change variables and notify the thread that is connecting
m_connectionStateChanged = true;
m_fail_error_code = con->get_ec();
m_fail_response_code = con->get_response_code();
}
m_cond.notify_one();
}
void WebSocketppClientWrapper::OnMessage(websocketpp::connection_hdl connection, websocketpp::config::asio_client::message_type::ptr msg) {
std::string message = msg->get_payload();
spdlog::info("Received message from websocket endpoint");
ResponseMessage responseMessage;
Message &gameLiftMessage = responseMessage;
if (!gameLiftMessage.Deserialize(message)) {
spdlog::error("Error Deserializing Message");
return;
}
const std::string &action = responseMessage.GetAction();
spdlog::info("Deserialized Message has Action: {}", action);
const std::string &requestId = responseMessage.GetRequestId();
const int statusCode = responseMessage.GetStatusCode();
const std::string &errorMessage = responseMessage.GetErrorMessage();
// Default to a success response with no result pointer
GenericOutcome response(nullptr);
// Check if the response was an error. If so, update the response based on status code.
// RequestId will be empty when we get a message not associated with a request, in which case we
// don't expect a 200 status code either.
if (statusCode != OK_STATUS_CODE && !requestId.empty()) {
response = GenericOutcome(GameLiftError(statusCode, message.c_str()));
} else {
// If we got a success response, and we have a special event handler for this action, invoke
// it to get the real parsed result
if (m_eventHandlers.count(action)) {
spdlog::info("Executing Amazon GameLift Servers Event Handler for {}", action);
response = m_eventHandlers[action](message);
}
}
// Lock whenever we make use of 'm_requestIdToPromise' to avoid concurrent writes/reads
std::lock_guard<std::mutex> lock(m_requestToPromiseLock);
if (m_requestIdToPromise.count(requestId) > 0) {
m_requestIdToPromise[requestId].set_value(response);
m_requestIdToPromise.erase(requestId);
}
}
websocketpp::lib::shared_ptr<asio::ssl::context> WebSocketppClientWrapper::OnTlsInit(websocketpp::connection_hdl hdl) {
websocketpp::lib::shared_ptr<asio::ssl::context> contextPtr(new asio::ssl::context(asio::ssl::context::tlsv12));
return contextPtr;
}
void WebSocketppClientWrapper::OnClose(websocketpp::connection_hdl connection) {
auto connectionPointer = m_webSocketClient->get_con_from_hdl(connection);
auto localCloseCode = connectionPointer->get_local_close_code();
auto remoteCloseCode = connectionPointer->get_remote_close_code();
bool isNormalClosure = localCloseCode == websocketpp::close::status::normal
|| localCloseCode == websocketpp::close::status::going_away
|| remoteCloseCode == websocketpp::close::status::normal
|| remoteCloseCode == websocketpp::close::status::going_away;
spdlog::info("Connection to Amazon GameLift Servers websocket server lost, Local Close Code = {}, Remote Close Code = {}.",
websocketpp::close::status::get_string(localCloseCode).c_str(),
websocketpp::close::status::get_string(remoteCloseCode).c_str());
if(isNormalClosure) {
spdlog::info("Normal Connection Closure, skipping reconnect.");
return;
} else {
spdlog::info("Abnormal Connection Closure, reconnecting.");
WebSocketppClientWrapper::Connect(m_uri);
}
}
void WebSocketppClientWrapper::OnInterrupt(websocketpp::connection_hdl connection) {
auto connectionPointer = m_webSocketClient->get_con_from_hdl(connection);
auto remoteEndpoint = connectionPointer->get_remote_endpoint();
auto host = connectionPointer->get_host();
auto port = connectionPointer->get_port();
spdlog::warn("Interruption Happened");
spdlog::info("In OnInterrupt(), isConnected:{}, endpoint: {}, host: {}, port: {}", IsConnected(), remoteEndpoint, host, port);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,54 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/CreateGameSessionCallback.h>
#include <aws/gamelift/internal/model/message/CreateGameSessionMessage.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome CreateGameSessionCallback::OnStartGameSession(const std::string &data) {
spdlog::info("OnStartGameSession Received with raw data: {}", data);
CreateGameSessionMessage createGameSessionMessage;
Message &message = createGameSessionMessage;
message.Deserialize(data);
GameSession gameSession;
gameSession.WithGameSessionId(createGameSessionMessage.GetGameSessionId().c_str())
.WithName(createGameSessionMessage.GetGameSessionName().c_str())
.WithMaximumPlayerSessionCount(createGameSessionMessage.GetMaximumPlayerSessionCount())
.WithIpAddress(createGameSessionMessage.GetIpAddress().c_str())
.WithPort(createGameSessionMessage.GetPort())
.WithGameSessionData(createGameSessionMessage.GetGameSessionData().c_str())
.WithMatchmakerData(createGameSessionMessage.GetMatchmakerData().c_str())
.WithDnsName(createGameSessionMessage.GetDnsName().c_str());
std::map<std::string, std::string>::const_iterator mapIterator;
for (mapIterator = createGameSessionMessage.GetGameProperties().begin(); mapIterator != createGameSessionMessage.GetGameProperties().end(); mapIterator++) {
GameProperty gameProperty;
gameProperty.SetKey(mapIterator->first.c_str());
gameProperty.SetValue(mapIterator->second.c_str());
gameSession.AddGameProperty(gameProperty);
}
m_gameLiftMessageHandler->OnStartGameSession(gameSession);
return GenericOutcome(nullptr);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,32 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/DescribePlayerSessionsCallback.h>
#include <aws/gamelift/internal/model/response/WebSocketDescribePlayerSessionsResponse.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome DescribePlayerSessionsCallback::OnDescribePlayerSessions(const std::string &data) {
spdlog::info("OnDescribePlayerSessions Received with raw data: {}", data);
WebSocketDescribePlayerSessionsResponse *describePlayerSessionsResponse = new WebSocketDescribePlayerSessionsResponse();
Message *message = describePlayerSessionsResponse;
message->Deserialize(data);
return GenericOutcome(describePlayerSessionsResponse);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,32 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/GetComputeCertificateCallback.h>
#include <aws/gamelift/internal/model/response/WebSocketGetComputeCertificateResponse.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome GetComputeCertificateCallback::OnGetComputeCertificateCallback(const std::string &data) {
spdlog::info("OnGetComputeCertificate Received");
auto *response = new WebSocketGetComputeCertificateResponse();
Message *message = response;
message->Deserialize(data);
return GenericOutcome(response);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,32 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/GetFleetRoleCredentialsCallback.h>
#include <aws/gamelift/internal/model/response/WebSocketGetFleetRoleCredentialsResponse.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome GetFleetRoleCredentialsCallback::OnGetFleetRoleCredentials(const std::string &data) {
spdlog::info("OnGetFleetRoleCredentials Received");
auto *getFleetRoleCredentialsResponse = new WebSocketGetFleetRoleCredentialsResponse();
Message *message = getFleetRoleCredentialsResponse;
message->Deserialize(data);
return GenericOutcome(getFleetRoleCredentialsResponse);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,34 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/RefreshConnectionCallback.h>
#include <aws/gamelift/internal/model/message/RefreshConnectionMessage.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome RefreshConnectionCallback::OnRefreshConnection(const std::string &data) {
spdlog::info("OnRefreshConnection Received with raw data: {}", data);
RefreshConnectionMessage refreshConnectionMessage;
Message &message = refreshConnectionMessage;
message.Deserialize(data);
m_gameLiftMessageHandler->OnRefreshConnection(refreshConnectionMessage.GetRefreshConnectionEndpoint(), refreshConnectionMessage.GetAuthToken());
return GenericOutcome(nullptr);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,32 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/StartMatchBackfillCallback.h>
#include <aws/gamelift/internal/model/response/WebSocketStartMatchBackfillResponse.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome StartMatchBackfillCallback::OnStartMatchBackfill(const std::string &data) {
spdlog::info("OnStartMatchBackfill Received with raw data: {}", data);
WebSocketStartMatchBackfillResponse *startMatchBackfillResponse = new WebSocketStartMatchBackfillResponse();
Message *message = startMatchBackfillResponse;
message->Deserialize(data);
return GenericOutcome(startMatchBackfillResponse);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,37 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/TerminateProcessCallback.h>
#include <aws/gamelift/internal/model/message/TerminateProcessMessage.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome TerminateProcessCallback::OnTerminateProcess(const std::string &data) {
spdlog::info("OnTerminateProcess Received with raw data: {}", data);
TerminateProcessMessage terminateProcessMessage;
Message &message = terminateProcessMessage;
message.Deserialize(data);
long terminationTime = terminateProcessMessage.GetTerminationTime();
m_gameLiftMessageHandler->OnTerminateProcess(terminationTime);
return GenericOutcome(nullptr);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,59 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/network/callback/UpdateGameSessionCallback.h>
#include <aws/gamelift/internal/model/message/UpdateGameSessionMessage.h>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift;
namespace Aws {
namespace GameLift {
namespace Internal {
GenericOutcome UpdateGameSessionCallback::OnUpdateGameSession(const std::string &data) {
spdlog::info("OnUpdateGameSession Received with raw data: {}", data);
UpdateGameSessionMessage updateGameSessionMessage;
Message &message = updateGameSessionMessage;
message.Deserialize(data);
GameSession gameSession;
WebSocketGameSession webSocketGameSession = updateGameSessionMessage.GetGameSession();
gameSession.WithGameSessionId(webSocketGameSession.GetGameSessionId().c_str())
.WithName(webSocketGameSession.GetName().c_str())
.WithFleetId(webSocketGameSession.GetFleetId().c_str())
.WithMaximumPlayerSessionCount(webSocketGameSession.GetMaximumPlayerSessionCount())
.WithIpAddress(webSocketGameSession.GetIpAddress().c_str())
.WithPort(webSocketGameSession.GetPort())
.WithGameSessionData(webSocketGameSession.GetGameSessionData().c_str())
.WithMatchmakerData(webSocketGameSession.GetMatchmakerData().c_str())
.WithDnsName(webSocketGameSession.GetDnsName().c_str());
std::map<std::string, std::string>::const_iterator mapIterator;
for (mapIterator = webSocketGameSession.GetGameProperties().begin(); mapIterator != webSocketGameSession.GetGameProperties().end(); mapIterator++) {
GameProperty gameProperty;
gameProperty.SetKey(mapIterator->first.c_str());
gameProperty.SetValue(mapIterator->second.c_str());
gameSession.AddGameProperty(gameProperty);
}
UpdateGameSession updateGameSession(gameSession, UpdateReasonMapper::GetUpdateReasonForName(updateGameSessionMessage.GetUpdateReason().c_str()),
updateGameSessionMessage.GetBackfillTicketId().c_str());
m_gameLiftMessageHandler->OnUpdateGameSession(updateGameSession);
return GenericOutcome(nullptr);
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/retry/GeometricBackoffRetryStrategy.h>
#include <thread>
#include <spdlog/spdlog.h>
namespace Aws {
namespace GameLift {
namespace Internal {
void GeometricBackoffRetryStrategy::apply(const std::function<bool(void)> &callable) {
int retryIntervalSeconds = m_initialRetryIntervalSeconds;
for (int i = 0; i < m_maxRetries; ++i) {
bool success = callable();
if (success) {
break;
} else {
spdlog::warn("Connection Failed. Retrying in {} seconds...", retryIntervalSeconds);
std::this_thread::sleep_for(std::chrono::seconds(retryIntervalSeconds));
retryIntervalSeconds *= m_retryFactor;
retryIntervalSeconds = retryIntervalSeconds > m_maxRetryIntervalSeconds ? m_maxRetryIntervalSeconds : retryIntervalSeconds;
}
}
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,42 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/retry/JitteredGeometricBackoffRetryStrategy.h>
#include <random>
#include <thread>
#include <spdlog/spdlog.h>
namespace Aws {
namespace GameLift {
namespace Internal {
void JitteredGeometricBackoffRetryStrategy::apply(const std::function<bool(void)> &callable) {
int retryIntervalMs = m_initialRetryIntervalMs;
std::random_device rd;
std::mt19937 randGenerator(rd());
for (int i = 0; i < m_maxRetries; ++i) {
bool success = callable();
if (success) {
break;
} else {
std::uniform_int_distribution<> intervalRange(m_minRetryDelayMs, retryIntervalMs);
int currentInterval = intervalRange(randGenerator);
spdlog::warn("Sending Message Failed. Retrying in {} milliseconds...", currentInterval);
std::this_thread::sleep_for(std::chrono::milliseconds(currentInterval));
retryIntervalMs *= m_retryFactor;
}
}
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,38 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/retry/RetryingCallable.h>
#include <thread>
namespace Aws {
namespace GameLift {
namespace Internal {
RetryingCallable::Builder &RetryingCallable::Builder::WithCallable(const std::function<bool(void)> &callable) {
m_callable = callable;
return *this;
}
RetryingCallable::Builder &RetryingCallable::Builder::WithRetryStrategy(RetryStrategy *retryStrategy) {
m_retryStrategy = retryStrategy;
return *this;
}
RetryingCallable RetryingCallable::Builder::Build() const { return RetryingCallable(*m_retryStrategy, m_callable); }
RetryingCallable::RetryingCallable(RetryStrategy &retryStrategy, std::function<bool(void)> callable) : m_retryStrategy(retryStrategy), m_callable(callable) {}
void RetryingCallable::call() { m_retryStrategy.apply(m_callable); }
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,186 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/security/AwsSigV4Utility.h>
#include <aws/gamelift/internal/util/UriEncoder.h>
#include <openssl/opensslv.h>
#include <openssl/evp.h>
#include <openssl/sha.h>
#include <openssl/hmac.h>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <algorithm>
#include <vector>
using namespace Aws::GameLift::Internal;
Aws::GameLift::Outcome<std::map<std::string, std::string>, std::string> AwsSigV4Utility::GenerateSigV4QueryParameters(const SigV4Parameters &parameters) {
try {
ValidateParameters(parameters);
} catch (std::invalid_argument const &ex) {
return std::string(ex.what());
}
char dateBuffer[16];
char dateTimeBuffer[32];
strftime(dateBuffer, sizeof(dateBuffer), DateFormat, &parameters.RequestTime);
strftime(dateTimeBuffer, sizeof(dateTimeBuffer), DateTimeFormat, &parameters.RequestTime);
const std::string formattedRequestDate(dateBuffer);
const std::string formattedRequestDateTime(dateTimeBuffer);
const std::string canonicalRequest = ToSortedEncodedQueryString(parameters.QueryParams);
const std::string hashedCanonicalRequest = ComputeSha256Hash(canonicalRequest);
const std::string scope = formattedRequestDate + "/" + parameters.AwsRegion + "/" + ServiceName + "/" + TerminationString;
const std::string stringToSign = std::string(Algorithm) + "\n" + formattedRequestDateTime + "\n" + scope + "\n" + hashedCanonicalRequest;
const std::string credential = parameters.Credentials.AccessKey + "/" + scope;
const std::string signature = GenerateSignature(
parameters.AwsRegion,
parameters.Credentials.SecretKey,
formattedRequestDate,
ServiceName,
stringToSign);
return GenerateSigV4QueryParameters(
credential,
formattedRequestDateTime,
parameters.Credentials.SessionToken,
signature);
}
void AwsSigV4Utility::ValidateParameters(const SigV4Parameters &parameters) {
if (parameters.AwsRegion.empty()) {
throw std::invalid_argument("AwsRegion is required");
}
if (parameters.Credentials.AccessKey.empty()) {
throw std::invalid_argument("AccessKey is required");
}
if (parameters.Credentials.SecretKey.empty()) {
throw std::invalid_argument("SecretKey is required");
}
if (parameters.QueryParams.empty()) {
throw std::invalid_argument("QueryParams is required");
}
if (parameters.RequestTime.tm_year == 0) {
throw std::invalid_argument("RequestTime is required");
}
}
std::string AwsSigV4Utility::GenerateSignature(
const std::string &region,
const std::string &secretKey,
const std::string &formattedRequestDateTime,
const std::string &serviceName,
const std::string &stringToSign) {
std::vector<uint8_t> encodedKeySecret = std::vector<uint8_t>(SignatureSecretKeyPrefix, SignatureSecretKeyPrefix +
strlen(SignatureSecretKeyPrefix));
encodedKeySecret.insert(encodedKeySecret.end(), secretKey.begin(), secretKey.end());
auto hashDate = ComputeHmacSha256(encodedKeySecret, formattedRequestDateTime);
auto hashRegion = ComputeHmacSha256(hashDate, region);
auto hashService = ComputeHmacSha256(hashRegion, serviceName);
auto signingKey = ComputeHmacSha256(hashService, TerminationString);
return ToHex(ComputeHmacSha256(signingKey, stringToSign));
}
std::map<std::string, std::string> AwsSigV4Utility::GenerateSigV4QueryParameters(
const std::string &credential,
const std::string &formattedRequestDateTime,
const std::string &sessionToken,
const std::string &signature) {
std::map<std::string, std::string> sigV4QueryParameters;
sigV4QueryParameters[AuthorizationKey] = AuthorizationValue;
sigV4QueryParameters[AmzAlgorithmKey] = Algorithm;
sigV4QueryParameters[AmzCredentialKey] = UriEncoder::UriEncode(credential);
sigV4QueryParameters[AmzDateKey] = formattedRequestDateTime;
sigV4QueryParameters[AmzSignatureKey] = UriEncoder::UriEncode(signature);
if (!sessionToken.empty()) {
sigV4QueryParameters[AmzSecurityTokenHeadersKey] = UriEncoder::UriEncode(sessionToken);
}
return sigV4QueryParameters;
}
std::string AwsSigV4Utility::ToSortedEncodedQueryString(const std::map<std::string, std::string> &queryParameters) {
std::vector<std::pair<std::string, std::string> > sortedParams(queryParameters.begin(), queryParameters.end());
std::sort(sortedParams.begin(), sortedParams.end());
std::ostringstream stringBuffer;
for (auto sortedParam = sortedParams.begin(); sortedParam != sortedParams.end(); ++sortedParam) {
if (sortedParam != sortedParams.begin()) {
stringBuffer << "&";
}
stringBuffer << UriEncoder::UriEncode(sortedParam->first) << "=" << UriEncoder::UriEncode(sortedParam->second);
}
return stringBuffer.str();
}
// Refer to documentation in AwsSigV4Utility.h
std::string AwsSigV4Utility::ComputeSha256Hash(const std::string &data) {
// Because the following methods do not throw exceptions, they are not being surrounded by try-catch or use RAII for cleaning memory.
unsigned char hash[SHA256_DIGEST_LENGTH];
SHA256_CTX sha256;
SHA256_Init(&sha256);
SHA256_Update(&sha256, data.c_str(), data.size());
SHA256_Final(hash, &sha256);
const std::vector<uint8_t> sha256Hash = std::vector<uint8_t>(hash, hash + SHA256_DIGEST_LENGTH);
return ToHex(sha256Hash);
}
// Refer to documentation in AwsSigV4Utility.h
std::vector<uint8_t> AwsSigV4Utility::ComputeHmacSha256(const std::vector<uint8_t> &key, const std::string &data) {
// Because the following methods do not throw exceptions, they are not being surrounded by try-catch or use RAII for cleaning memory.
unsigned char hash[EVP_MAX_MD_SIZE];
unsigned int len = 0;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L // OpenSSL 1.1.0 or newer
HMAC_CTX *ctx = HMAC_CTX_new();
HMAC_Init_ex(ctx, key.data(), key.size(), EVP_sha256(), nullptr);
HMAC_Update(ctx, reinterpret_cast<const unsigned char *>(data.c_str()), data.size());
HMAC_Final(ctx, hash, &len);
HMAC_CTX_free(ctx);
#else // Older versions of OpenSSL
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, key.data(), key.size(), EVP_sha256(), nullptr);
HMAC_Update(&ctx, reinterpret_cast<const unsigned char *>(data.c_str()), data.size());
HMAC_Final(&ctx, hash, &len);
HMAC_CTX_cleanup(&ctx);
#endif
return std::vector<uint8_t>(hash, hash + len);
}
std::string AwsSigV4Utility::ToHex(const std::vector<uint8_t> &hashBytes) {
std::ostringstream stringBuffer;
for (auto b: hashBytes) {
stringBuffer << std::hex << std::setw(2) << std::setfill('0') << (int) b;
}
return stringBuffer.str();
}

View File

@@ -0,0 +1,61 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/security/ContainerCredentialsFetcher.h>
#include <stdexcept>
#include <cstdlib>
#include "rapidjson/document.h"
using namespace Aws::GameLift::Internal;
ContainerCredentialsFetcher::ContainerCredentialsFetcher(HttpClient &httpClient)
: httpClient(httpClient) {}
Aws::GameLift::Outcome<AwsCredentials, std::string> ContainerCredentialsFetcher::FetchContainerCredentials() {
const char *credentialsRelativeUri = std::getenv(EnvironmentVariableContainerCredentialsRelativeUri.c_str());
if (!credentialsRelativeUri) {
return "The environment variable " + EnvironmentVariableContainerCredentialsRelativeUri + " is not set.";
}
std::string relativeUri = credentialsRelativeUri;
HttpResponse response = httpClient.SendGetRequest(ContainerCredentialProviderUrl + relativeUri);
if (!response.IsSuccessfulStatusCode()) {
return std::string(
"Failed to get Container Credentials from Container Credential Provider. HTTP Response Status Code is " +
std::to_string(response.statusCode));
}
rapidjson::Document document;
if (document.Parse(response.body.c_str()).HasParseError()) {
return std::string("Error parsing Container Credential Provider JSON response");
}
if (!document.HasMember("AccessKeyId") || !document["AccessKeyId"].IsString()) {
return std::string("AccessKeyId is not found in Container Credential Provider response");
}
if (!document.HasMember("SecretAccessKey") || !document["SecretAccessKey"].IsString()) {
return std::string("SecretAccessKey is not found in Container Credential Provider response");
}
if (!document.HasMember("Token") || !document["Token"].IsString()) {
return std::string("Token is not found in Container Credential Provider response");
}
AwsCredentials awsCredentials(
document["AccessKeyId"].GetString(),
document["SecretAccessKey"].GetString(),
document["Token"].GetString());
return awsCredentials;
}

View File

@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/security/ContainerMetadataFetcher.h>
#include <stdexcept>
#include <cstdlib>
#include "rapidjson/document.h"
using namespace Aws::GameLift::Internal;
ContainerMetadataFetcher::ContainerMetadataFetcher(HttpClient &httpClient)
: httpClient(httpClient) {}
Aws::GameLift::Outcome<ContainerTaskMetadata, std::string> ContainerMetadataFetcher::FetchContainerTaskMetadata() {
const char *containerMetadataUri = std::getenv(EnvironmentVariableContainerMetadataUri.c_str());
if (!containerMetadataUri) {
return "The environment variable " + EnvironmentVariableContainerMetadataUri + " is not set.";
}
std::string baseUrl = containerMetadataUri;
HttpResponse response = httpClient.SendGetRequest(baseUrl + "/" + TaskMetadataRelativePath);
if(!response.IsSuccessfulStatusCode()) {
return std::string(
"Failed to get Container Task Metadata from Container Metadata Service. HTTP Response Status Code is " +
std::to_string(response.statusCode));
}
rapidjson::Document document;
if (document.Parse(response.body.c_str()).HasParseError()) {
return std::string("Error parsing Container Metadata Service JSON response");
}
if (!document.HasMember("TaskARN") || !document["TaskARN"].IsString()) {
return std::string("TaskArn is not found in Container Metadata Service response");
}
std::string taskArn = document["TaskARN"].GetString();
if (taskArn.empty()) {
return std::string("Invalid TaskARN, value is empty");
}
if (taskArn.find('/') == std::string::npos) {
return std::string("Failed to extract Task ID from container TaskArn with value " + taskArn);
}
std::string taskId = taskArn.substr(taskArn.find_last_of('/') + 1);
return ContainerTaskMetadata(taskId);
}

View File

@@ -0,0 +1,47 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/GuidGenerator.h>
#include <iostream>
#include <string>
#include <random>
#include <sstream>
#include <iomanip>
using namespace Aws::GameLift::Internal;
std::string GuidGenerator::GenerateGuid() {
std::random_device rd;
std::uniform_int_distribution<int> dist(0, 15);
std::uniform_int_distribution<int> dist2(8, 11);
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < 8; ++i) ss << dist(rd);
ss << "-";
for (int i = 0; i < 4; ++i) ss << dist(rd);
ss << "-";
ss << "4";
for (int i = 0; i < 3; ++i) ss << dist(rd);
ss << "-";
ss << dist2(rd);
for (int i = 0; i < 3; ++i) ss << dist(rd);
ss << "-";
for (int i = 0; i < 12; ++i) ss << dist(rd);
return ss.str();
}

View File

@@ -0,0 +1,195 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/HttpClient.h>
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
using ssize_t = SSIZE_T;
#else
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <cstring>
#endif
#include <stdexcept>
#include <spdlog/spdlog.h>
using namespace Aws::GameLift::Internal;
bool HttpResponse::IsSuccessfulStatusCode() {
return statusCode >= 200 && statusCode <= 299;
}
HttpResponse HttpClient::SendGetRequest(const std::string &url) {
const std::tuple<std::string, int, std::string> hostAndPortAndPath = GetHostAndPortAndPath(url);
const std::string host = std::get<0>(hostAndPortAndPath);
const int port = std::get<1>(hostAndPortAndPath);
const std::string path = std::get<2>(hostAndPortAndPath);
const std::string request = "GET " + path + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n";
int sock = -1;
#ifdef _WIN32
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
throw std::runtime_error("WSAStartup failed, error number: " + std::to_string(WSAGetLastError()));
}
#endif
try {
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
#ifdef _WIN32
throw std::runtime_error("Socket creation failed, error number: " + std::to_string(WSAGetLastError()));
#else
throw std::runtime_error("Socket creation failed, error number: " + std::string(strerror(errno)));
#endif
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
#ifdef _WIN32
std::wstring wide_host = std::wstring(host.begin(), host.end());
if (InetPtonW(AF_INET, wide_host.c_str(), &server_addr.sin_addr) <= 0) {
throw std::runtime_error("Invalid address or address not supported, error number: " + std::to_string(WSAGetLastError()));
}
#else
if (inet_pton(AF_INET, host.c_str(), &server_addr.sin_addr) <= 0) {
throw std::runtime_error("Invalid address or address not supported, error number: " + std::string(strerror(errno)));
}
#endif
if (connect(sock, (struct sockaddr *) &server_addr, sizeof(server_addr)) < 0) {
#ifdef _WIN32
throw std::runtime_error("Connection failed, error number: " + std::to_string(WSAGetLastError()));
#else
throw std::runtime_error("Connection failed, error number: " + std::string(strerror(errno)));
#endif
}
ssize_t sent = send(sock, request.c_str(), request.length(), 0);
if (sent < 0) {
#ifdef _WIN32
throw std::runtime_error("Send failed, error number: " + std::to_string(WSAGetLastError()));
#else
throw std::runtime_error("Send failed, error number: " + std::string(strerror(errno)));
#endif
} else if (sent != (ssize_t) request.length()) {
throw std::runtime_error("Send incomplete, only " + std::to_string(sent) + " bytes sent.");
}
std::string fullResponse;
char buffer[1024] = {0};
ssize_t bytesReceived;
while ((bytesReceived = recv(sock, buffer, sizeof(buffer) - 1, 0)) > 0) {
fullResponse.append(buffer, bytesReceived);
}
if (bytesReceived < 0) {
#ifdef _WIN32
throw std::runtime_error("Receive failed, error number: " + std::to_string(WSAGetLastError()));
#else
throw std::runtime_error("Receive failed, error number: " + std::string(strerror(errno)));
#endif
}
#ifdef _WIN32
if (closesocket(sock) < 0) {
spdlog::warn("Socket close failed, error number: {}", WSAGetLastError());
}
WSACleanup();
#else
if (close(sock) < 0) {
spdlog::warn("Socket close failed, error number: {}", errno);
}
#endif
sock = -1;
HttpResponse httpResponse = ParseHttpResponse(fullResponse);
return httpResponse;
} catch (const std::runtime_error& e) {
if (sock >= 0) {
#ifdef _WIN32
closesocket(sock);
WSACleanup();
#else
close(sock);
#endif
}
throw e;
}
}
std::tuple<std::string, int, std::string> HttpClient::GetHostAndPortAndPath(const std::string &url) {
std::string host;
std::string path;
int port = 80;
std::size_t protocolPos = url.find("://");
if (protocolPos == std::string::npos) {
throw std::runtime_error("Invalid URL: Missing protocol");
}
std::size_t hostStart = protocolPos + 3;
if (hostStart >= url.size()) {
throw std::runtime_error("Invalid URL: Host is missing");
}
std::size_t pathPos = url.find('/', hostStart);
std::size_t portPos = url.find(':', hostStart);
if (portPos != std::string::npos && (pathPos == std::string::npos || portPos < pathPos)) {
host = url.substr(hostStart, portPos - hostStart);
std::size_t portEnd = (pathPos == std::string::npos) ? url.size() : pathPos;
port = std::stoi(url.substr(portPos + 1, portEnd - portPos - 1));
} else {
if (pathPos == std::string::npos) {
host = url.substr(hostStart);
path = "/";
} else {
host = url.substr(hostStart, pathPos - hostStart);
}
}
if (path.empty()) {
if (pathPos != std::string::npos) {
path = url.substr(pathPos);
} else {
path = "/";
}
}
return std::make_tuple(host, port, path);
}
HttpResponse HttpClient::ParseHttpResponse(const std::string &response) {
HttpResponse httpResponse;
std::size_t statusCodeStart = response.find("HTTP/1.1 ") + 9;
std::size_t statusCodeEnd = response.find(" ", statusCodeStart);
if (statusCodeStart != std::string::npos && statusCodeEnd != std::string::npos) {
httpResponse.statusCode = std::stoi(response.substr(statusCodeStart, statusCodeEnd - statusCodeStart));
}
std::size_t bodyStart = response.find("\r\n\r\n");
if (bodyStart != std::string::npos) {
httpResponse.body = response.substr(bodyStart + 4);
}
if (response.find("Transfer-Encoding: chunked") != std::string::npos
&& response.find("Content-Type: application/json") != std::string::npos) {
int jsonStart = httpResponse.body.find("{");
int jsonEnd = httpResponse.body.find_last_of("}");
if (jsonStart != std::string::npos && jsonEnd != std::string::npos) {
httpResponse.body = httpResponse.body.substr(jsonStart, jsonEnd - jsonStart + 2);
}
}
return httpResponse;
}

View File

@@ -0,0 +1,107 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/JsonHelper.h>
using namespace Aws::GameLift::Internal;
std::string JsonHelper::SafelyDeserializeString(const rapidjson::Value &value, const char *key) {
return value.HasMember(key) && value[key].IsString() ? value[key].GetString() : "";
}
void JsonHelper::WriteNonEmptyString(rapidjson::Writer<rapidjson::StringBuffer> *writer, const char *key, const std::string &value) {
if (!value.empty()) {
writer->String(key);
writer->String(value.c_str());
}
}
int JsonHelper::SafelyDeserializeInt(const rapidjson::Value &value, const char *key) {
return value.HasMember(key) && value[key].IsInt() ? value[key].GetInt() : -1;
}
void JsonHelper::WritePositiveInt(rapidjson::Writer<rapidjson::StringBuffer> *writer, const char *key, int value) {
if (value > 0) {
writer->String(key);
writer->Int(value);
}
}
int64_t JsonHelper::SafelyDeserializeInt64(const rapidjson::Value &value, const char *key) {
return value.HasMember(key) && value[key].IsInt64() ? value[key].GetInt64() : -1;
}
void JsonHelper::WritePositiveInt64(rapidjson::Writer<rapidjson::StringBuffer> *writer, const char *key, int64_t value) {
if (value > 0) {
writer->String(key);
writer->Int64(value);
}
}
Aws::GameLift::Server::LogParameters JsonHelper::SafelyDeserializeLogParameters(const rapidjson::Value &value, const char *key) {
if (!value.HasMember(key) || !value[key].IsArray() || value[key].Size() == 0) {
return Aws::GameLift::Server::LogParameters();
}
const rapidjson::SizeType numLogPaths = value[key].Size();
#ifdef GAMELIFT_USE_STD
std::vector<std::string> logPaths = std::vector<std::string>();
#else
char **logPaths = new char *[numLogPaths];
#endif
for (rapidjson::SizeType i = 0; i < numLogPaths; i++) {
if (value[key][i].IsString()) {
#ifdef GAMELIFT_USE_STD
logPaths.push_back(value[key][i].GetString());
#else
logPaths[i] = new char[MAX_PATH_LENGTH];
#ifdef WIN32
strcpy_s(logPaths[i], MAX_PATH_LENGTH, value[key][i].GetString());
#else
strncpy(logPaths[i], value[key][i].GetString(), MAX_PATH_LENGTH);
#endif
#endif
}
}
#ifdef GAMELIFT_USE_STD
return Aws::GameLift::Server::LogParameters(logPaths);
#else
Aws::GameLift::Server::LogParameters toReturn(logPaths, numLogPaths);
for (rapidjson::SizeType i = 0; i < numLogPaths; i++) {
delete[] logPaths[i];
}
delete[] logPaths;
return toReturn;
#endif
}
void JsonHelper::WriteLogParameters(rapidjson::Writer<rapidjson::StringBuffer> *writer, const char *key, const Aws::GameLift::Server::LogParameters &value) {
if (value.getLogPathCount() == 0) {
return;
}
writer->String(key);
writer->StartArray();
for (size_t i = 0; i < value.getLogPathCount(); i++) {
const char *logPath = value.getLogPath(i);
// If logPath is not empty, write it.
if (logPath && logPath[0]) {
writer->String(value.getLogPath(i));
}
}
writer->EndArray();
}

View File

@@ -0,0 +1,52 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/LoggerHelper.h>
#include <spdlog/spdlog.h>
#include <spdlog/sinks/stdout_color_sinks.h>
#include <spdlog/sinks/rotating_file_sink.h>
using namespace Aws::GameLift::Internal;
#ifdef GAMELIFT_USE_STD
void LoggerHelper::InitializeLogger(const std::string& process_Id) {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
std::string serverSdkLog = "logs/gamelift-server-sdk-";
serverSdkLog.append(process_Id).append(".log");
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(serverSdkLog, 10485760, 5);
console_sink->set_pattern("%^[%Y-%m-%d %H:%M:%S] [%l] %v%$");
file_sink->set_pattern("[%Y-%m-%d %H:%M:%S] [%l] %v");
spdlog::logger logger("multi_sink", { console_sink, file_sink });
logger.set_level(spdlog::level::info);
logger.flush_on(spdlog::level::info);
spdlog::set_default_logger(std::make_shared<spdlog::logger>(logger));
}
#else
void LoggerHelper::InitializeLogger(const char* process_Id) {
auto console_sink = std::make_shared<spdlog::sinks::stdout_color_sink_mt>();
std::string serverSdkLog = "logs/gamelift-server-sdk-";
serverSdkLog.append(process_Id).append(".log");
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(serverSdkLog, 10485760, 5);
console_sink->set_pattern("%^[%Y-%m-%d %H:%M:%S] [%l] %v%$");
file_sink->set_pattern("[%Y-%m-%d %H:%M:%S] [%l] %v");
spdlog::logger logger("multi_sink", { console_sink, file_sink });
logger.set_level(spdlog::level::info);
logger.flush_on(spdlog::level::info);
spdlog::set_default_logger(std::make_shared<spdlog::logger>(logger));
}
#endif

View File

@@ -0,0 +1,40 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/RandomStringGenerator.h>
#include <random>
#include <sstream>
namespace Aws {
namespace GameLift {
namespace Internal {
std::string RandomStringGenerator::GenerateRandomAlphaNumericString(const int stringLength) {
std::stringstream ss;
static const char alphaNumChars[] = "0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz";
static thread_local std::mt19937 randomNumberGenerator(std::random_device{}());
// Distribution has an inclusive upper bound. "alphaNumChars" will end in a null terminator, so
// we use "sizeof() - 2" to avoid out of bounds errors, and also to avoid including the null
// terminator.
std::uniform_int_distribution<int> distribution(0, sizeof(alphaNumChars) - 2);
for (int i = 0; i < stringLength; i++) {
ss << alphaNumChars[distribution(randomNumberGenerator)];
}
return ss.str();
}
} // namespace Internal
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,31 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/internal/util/UriEncoder.h>
#include <sstream>
#include <iomanip>
using namespace Aws::GameLift::Internal;
std::string UriEncoder::UriEncode(const std::string &value) {
std::ostringstream escaped;
escaped.fill('0');
escaped << std::hex << std::uppercase;
for (char c: value) {
if (isalnum(static_cast<unsigned char>(c)) || c == '-' || c == '_' || c == '.' || c == '~') {
escaped << c;
} else {
escaped << '%' << std::setw(2) << static_cast<int>(static_cast<unsigned char>(c));
}
}
return escaped.str();
}

View File

@@ -0,0 +1,102 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates
* or its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root
* of this distribution (the "License"). All use of this software is governed by
* the License, or, if provided, by the license below or the license
* accompanying this file. Do not remove or modify any license notices. This
* file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/metrics/Combiner.h>
#include <cassert>
void Combiner::Add(MetricMessage message) {
if (message.IsGauge()) {
// We have to do a bit more work for gauges to convert GaugeAdd to GaugeSet
UpdateGauge(message);
} else {
auto it = m_combinedMessages.find(message.Metric);
if (it == std::end(m_combinedMessages)) {
m_combinedMessages.emplace(message.Metric, message);
return;
}
assert(message.IsCounter() || message.IsTimer());
if (message.IsCounter()) {
UpdateCounter(it->second, message);
} else if (message.IsTimer()) {
UpdateTimer(it->second, message);
}
}
}
void Combiner::UpdateGauge(const MetricMessage &message) {
assert(message.Type == MetricMessageType::GaugeSet ||
message.Type == MetricMessageType::GaugeAdd);
if (message.Type == MetricMessageType::GaugeSet) {
// If setting - we just use the new value
m_combinedMessages[message.Metric] = message;
m_gaugeHistory[message.Metric] = message;
} else if (message.Type == MetricMessageType::GaugeAdd) {
// If adding - we get historic value (if available) and add to it
// if there's no historic value, we just add to 0
double currentValue = 0;
auto it = m_gaugeHistory.find(message.Metric);
if (it != std::end(m_gaugeHistory)) {
currentValue = it->second.SubmitDouble.Value;
}
currentValue += message.SubmitDouble.Value;
auto newMessage = MetricMessage::GaugeSet(*message.Metric, currentValue);
m_combinedMessages[message.Metric] = newMessage;
m_gaugeHistory[message.Metric] = newMessage;
}
}
void Combiner::UpdateCounter(MetricMessage &current,
const MetricMessage &newMessage) {
assert(newMessage.Type == MetricMessageType::CounterAdd);
// Just sum the values.
current.SubmitDouble.Value += newMessage.SubmitDouble.Value;
}
void Combiner::UpdateTimer(MetricMessage &current,
const MetricMessage &newMessage) {
assert(newMessage.Type == MetricMessageType::TimerSet);
// Grab or init sample count
auto sampleCountIt = m_timerSampleCount.find(current.Metric);
if (sampleCountIt != std::end(m_timerSampleCount)) {
++(sampleCountIt->second);
} else {
// This is the second sample being added, hence we initialize it to 2.
auto pair = m_timerSampleCount.emplace(current.Metric, 2);
const bool insertSuccess = pair.second;
assert(insertSuccess);
sampleCountIt = pair.first;
}
// Welford's algorithm
// numerically stable mean
//
// Knuth - TACOP Vol 2 pg. 216
//
// https://nullbuffer.com/articles/welford_algorithm.html
const double update =
(newMessage.SubmitDouble.Value - current.SubmitDouble.Value) /
sampleCountIt->second;
current.SubmitDouble.Value += update;
}
void Combiner::Clear() {
m_combinedMessages.clear();
m_timerSampleCount.clear();
}

View File

@@ -0,0 +1,145 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/metrics/CrashReporterClient.h>
#include <aws/gamelift/internal/retry/RetryingCallable.h>
#include <aws/gamelift/internal/retry/JitteredGeometricBackoffRetryStrategy.h>
#include <spdlog/spdlog.h>
#include <stdexcept>
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
namespace Aws {
namespace GameLift {
namespace Metrics {
CrashReporterClient::CrashReporterClient(const std::string& host, int port)
: httpClient(std::make_shared<Aws::GameLift::Internal::HttpClient>()) {
baseUrl = "http://" + host + ":" + std::to_string(port) + "/";
}
CrashReporterClient::CrashReporterClient(std::shared_ptr<Aws::GameLift::Internal::HttpClient> httpClient, const std::string &host, int port)
: httpClient(std::move(httpClient)) {
baseUrl = "http://" + host + ":" + std::to_string(port) + "/";
}
bool CrashReporterClient::isRetryableError(const std::string& errorMessage) const {
return errorMessage.find("Connection refused") != std::string::npos ||
errorMessage.find("Connection failed") != std::string::npos;
}
void CrashReporterClient::RegisterProcessWithRetries() {
#ifdef _WIN32
int processPid = static_cast<int>(GetCurrentProcessId());
#else
int processPid = static_cast<int>(getpid());
#endif
std::string requestUri = baseUrl + RegisterProcessUrlPath + "?" +
ProcessPidParameterName + "=" + std::to_string(processPid);
spdlog::info("Registering process with {} {} in OTEL Collector Crash Reporter", ProcessPidParameterName, processPid);
// 5 retries, 1s base delay with jitter (default)
// Total max wait time: ~1s + 2s + 4s + 8s + 16s = ~31s
Aws::GameLift::Internal::JitteredGeometricBackoffRetryStrategy retryStrategy;
auto callable = [this, &requestUri, processPid]() -> bool {
try {
auto response = httpClient->SendGetRequest(requestUri);
if (response.IsSuccessfulStatusCode()) {
spdlog::info("Successfully registered {} {} to OTEL Collector Crash Reporter", ProcessPidParameterName, processPid);
return true;
} else {
spdlog::error("Failed to register {} {} to OTEL Collector Crash Reporter, Http response: {} - {}",
ProcessPidParameterName, processPid, response.statusCode, response.body);
return true; // Don't retry on HTTP errors (4xx, 5xx)
}
} catch (const std::exception& e) {
std::string errorMsg = e.what();
if (isRetryableError(errorMsg)) {
spdlog::warn("Failed to register {} {} to OTEL Collector Crash Reporter due to connection error: {}",
ProcessPidParameterName, processPid, e.what());
return false; // Retry on connection errors
} else {
spdlog::error("Failed to register {} {} to OTEL Collector Crash Reporter due to error: {}",
ProcessPidParameterName, processPid, e.what());
return true; // Don't retry on other errors
}
}
};
Aws::GameLift::Internal::RetryingCallable::Builder()
.WithRetryStrategy(&retryStrategy)
.WithCallable(callable)
.Build()
.call();
}
void CrashReporterClient::RegisterProcess() {
RegisterProcessWithRetries();
}
void CrashReporterClient::TagGameSession(const std::string& sessionId) {
#ifdef _WIN32
int processPid = static_cast<int>(GetCurrentProcessId());
#else
int processPid = static_cast<int>(getpid());
#endif
std::string requestUri = baseUrl + UpdateProcessUrlPath + "?" +
ProcessPidParameterName + "=" + std::to_string(processPid) + "&" +
SessionIdParameterName + "=" + sessionId;
try {
spdlog::info("Adding {} tag {} to process with {} {} to the OTEL Collector Crash Reporter",
SessionIdParameterName, sessionId, ProcessPidParameterName, processPid);
auto response = httpClient->SendGetRequest(requestUri);
if (!response.IsSuccessfulStatusCode()) {
spdlog::error("Failed to add {} tag {} to process with {} {} in the OTEL Collector Crash Reporter, Http response: {} - {}",
SessionIdParameterName, sessionId, ProcessPidParameterName, processPid,
response.statusCode, response.body);
}
} catch (const std::exception& e) {
spdlog::error("Failed to add {} tag {} to process with {} {} in the OTEL Collector Crash Reporter due to error: {}",
SessionIdParameterName, sessionId, ProcessPidParameterName, processPid, e.what());
}
}
void CrashReporterClient::DeregisterProcess() {
#ifdef _WIN32
int processPid = static_cast<int>(GetCurrentProcessId());
#else
int processPid = static_cast<int>(getpid());
#endif
std::string requestUri = baseUrl + DeregisterProcessUrlPath + "?" +
ProcessPidParameterName + "=" + std::to_string(processPid);
try {
spdlog::info("Unregistering process with {} {} in OTEL Collector Crash Reporter",
ProcessPidParameterName, processPid);
auto response = httpClient->SendGetRequest(requestUri);
if (!response.IsSuccessfulStatusCode()) {
spdlog::error("Failed to deregister {} {} in the OTEL Collector Crash Reporter, Http response: {} - {}",
ProcessPidParameterName, processPid, response.statusCode, response.body);
}
} catch (const std::exception& e) {
spdlog::error("Failed to deregister {} {} in the OTEL Collector Crash Reporter due to error: {}",
ProcessPidParameterName, processPid, e.what());
}
}
} // namespace Metrics
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,25 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates
* or its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root
* of this distribution (the "License"). All use of this software is governed by
* the License, or, if provided, by the license below or the license
* accompanying this file. Do not remove or modify any license notices. This
* file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/metrics/DerivedMetric.h>
namespace Aws {
namespace GameLift {
namespace Metrics {
IDerivedMetric::~IDerivedMetric() {}
IDerivedMetricVisitor::~IDerivedMetricVisitor() {}
IDerivedMetricCollection::~IDerivedMetricCollection() {}
} // namespace Metrics
} // namespace GameLift
} // namespace Aws

View File

@@ -0,0 +1,33 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates
* or its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root
* of this distribution (the "License"). All use of this software is governed by
* the License, or, if provided, by the license below or the license
* accompanying this file. Do not remove or modify any license notices. This
* file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF
* ANY KIND, either express or implied.
*
*/
#include <aws/gamelift/metrics/DynamicMetric.h>
#ifndef GAMELIFT_USE_STD
#include <cstring>
namespace Aws {
namespace GameLift {
namespace Metrics {
void DynamicMetric::SetKey(const char *newKey) {
#ifdef _WIN32
strncpy_s(m_key, DynamicMetric::MAXIMUM_KEY_LENGTH, newKey,
DynamicMetric::MAXIMUM_KEY_LENGTH);
#else
strncpy(m_key, newKey, DynamicMetric::MAXIMUM_KEY_LENGTH);
#endif // _WIN32
}
} // namespace Metrics
} // namespace GameLift
} // namespace Aws
#endif // !GAMELIFT_USE_STD

Some files were not shown because too many files have changed in this diff Show More