Initial Commit - Lesson 31 (Commit #1)
This commit is contained in:
@@ -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",
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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 "MemoryStats.h"
|
||||
|
||||
#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);
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
#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;
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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{};
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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;
|
||||
};
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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));
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 ¶meters) {
|
||||
|
||||
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, ¶meters.RequestTime);
|
||||
strftime(dateTimeBuffer, sizeof(dateTimeBuffer), DateTimeFormat, ¶meters.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 ¶meters) {
|
||||
|
||||
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 ®ion,
|
||||
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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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 ¤t,
|
||||
const MetricMessage &newMessage) {
|
||||
assert(newMessage.Type == MetricMessageType::CounterAdd);
|
||||
|
||||
// Just sum the values.
|
||||
current.SubmitDouble.Value += newMessage.SubmitDouble.Value;
|
||||
}
|
||||
|
||||
void Combiner::UpdateTimer(MetricMessage ¤t,
|
||||
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();
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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/GlobalMetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/IMetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/MetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/LoggerMacros.h>
|
||||
#include <aws/gamelift/metrics/CrashReporterClient.h>
|
||||
#include <aws/gamelift/metrics/StatsDClient.h>
|
||||
#include <aws/gamelift/server/model/GameSession.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
#ifdef __linux__
|
||||
#include <unistd.h>
|
||||
#elif defined(_WIN32) || defined(_WIN64)
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
GAMELIFT_METRICS_DEFINE_GAUGE(ServerUpGauge);
|
||||
|
||||
namespace {
|
||||
std::unique_ptr<::Aws::GameLift::Metrics::IMetricsProcessor>
|
||||
GlobalProcessor(nullptr);
|
||||
std::shared_ptr<::Aws::GameLift::Metrics::StatsDClient>
|
||||
GlobalStatsDClient(nullptr);
|
||||
std::shared_ptr<::Aws::GameLift::Metrics::CrashReporterClient>
|
||||
GlobalCrashReporter(nullptr);
|
||||
|
||||
void InitializeCrashReporter(const MetricsSettings &settings) {
|
||||
std::string crashReporterHost;
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
crashReporterHost = settings.CrashReporterHost;
|
||||
#else
|
||||
crashReporterHost = (settings.CrashReporterHost != nullptr) ? std::string(settings.CrashReporterHost) : "";
|
||||
#endif
|
||||
// Skip crash reporter initialization if host is empty
|
||||
if (crashReporterHost.empty()) {
|
||||
GAMELIFT_METRICS_LOG_INFO("Crash reporter disabled - host not set");
|
||||
return;
|
||||
}
|
||||
int crashReporterPort = settings.CrashReporterPort;
|
||||
GlobalCrashReporter = std::make_shared<CrashReporterClient>(crashReporterHost, crashReporterPort);
|
||||
GlobalCrashReporter->RegisterProcess();
|
||||
}
|
||||
|
||||
void InitializeStatsDClient(const MetricsSettings &settings) {
|
||||
std::string statsdHost;
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
statsdHost = settings.StatsDClientHost;
|
||||
#else
|
||||
statsdHost = (settings.StatsDClientHost != nullptr) ? std::string(settings.StatsDClientHost) : "";
|
||||
#endif
|
||||
// Skip crash reporter initialization if host is empty
|
||||
if (statsdHost.empty()) {
|
||||
GAMELIFT_METRICS_LOG_INFO("StatsDClient disabled - host not set");
|
||||
return;
|
||||
}
|
||||
int statsdPort = settings.StatsDClientPort;
|
||||
GlobalStatsDClient = std::make_shared<StatsDClient>(statsdHost.c_str(), statsdPort);
|
||||
GAMELIFT_METRICS_LOG_INFO("Created StatsD client for {}:{}", statsdHost, statsdPort);
|
||||
}
|
||||
|
||||
void InitializeDefaultGlobalTags() {
|
||||
if (GlobalProcessor) {
|
||||
// Check if GAMELIFT_SDK_PROCESS_ID environment variable is set
|
||||
const char *processId = std::getenv(ENV_VAR_PROCESS_ID);
|
||||
if (processId != nullptr && processId[0] != '\0') {
|
||||
GlobalProcessor->SetGlobalTag("gamelift_process_id", processId);
|
||||
|
||||
GAMELIFT_METRICS_LOG_INFO("Set global tag gamelift_process_id: {}",
|
||||
processId);
|
||||
}
|
||||
|
||||
// Set the OS process ID (Linux and Windows).
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
std::string pidStr = std::to_string(pid);
|
||||
#else
|
||||
pid_t pid = getpid();
|
||||
std::string pidStr = std::to_string(pid);
|
||||
#endif
|
||||
GlobalProcessor->SetGlobalTag("process_pid", pidStr.c_str());
|
||||
GAMELIFT_METRICS_LOG_INFO("Set global tag process_pid: {}", pidStr);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
|
||||
void MetricsInitialize(const MetricsSettings &settings) {
|
||||
GAMELIFT_METRICS_LOG_INFO("Initializing GameLift Servers Metrics");
|
||||
|
||||
assert(!GlobalProcessor);
|
||||
InitializeCrashReporter(settings);
|
||||
InitializeStatsDClient(settings);
|
||||
|
||||
// Create settings with StatsD callback only if no callback is already set
|
||||
MetricsSettings settingsWithCallbackOverride = settings;
|
||||
if (!settings.SendPacketCallback) {
|
||||
settingsWithCallbackOverride.SendPacketCallback = [](const char* data, int size) {
|
||||
if (GlobalStatsDClient) {
|
||||
GlobalStatsDClient->Send(data, size);
|
||||
} else {
|
||||
GAMELIFT_METRICS_LOG_ERROR("StatsDClient is not initialized. Cannot send metrics data.");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
GlobalProcessor.reset(new MetricsProcessor(settingsWithCallbackOverride));
|
||||
InitializeDefaultGlobalTags();
|
||||
|
||||
GAMELIFT_METRICS_LOG_INFO(
|
||||
"GameLift Servers Metrics initialized successfully");
|
||||
}
|
||||
|
||||
void MetricsTerminate() {
|
||||
GAMELIFT_METRICS_SET(ServerUpGauge, 0);
|
||||
|
||||
// Process the final metrics before shutting down
|
||||
if (GlobalProcessor) {
|
||||
GlobalProcessor->ProcessMetricsNow();
|
||||
}
|
||||
|
||||
if (GlobalCrashReporter) {
|
||||
GlobalCrashReporter->DeregisterProcess();
|
||||
GlobalCrashReporter.reset();
|
||||
}
|
||||
|
||||
if (GlobalStatsDClient) {
|
||||
GlobalStatsDClient.reset();
|
||||
}
|
||||
|
||||
GlobalProcessor.reset();
|
||||
}
|
||||
|
||||
void MetricsProcess() {
|
||||
assert(GlobalProcessor);
|
||||
if (GlobalProcessor) {
|
||||
GlobalProcessor->ProcessMetrics();
|
||||
}
|
||||
}
|
||||
|
||||
void OnGameSessionStarted(
|
||||
const Aws::GameLift::Server::Model::GameSession &session) {
|
||||
assert(GlobalProcessor);
|
||||
if (GlobalProcessor) {
|
||||
GlobalProcessor->OnStartGameSession(session);
|
||||
}
|
||||
if (GlobalCrashReporter) {
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
GlobalCrashReporter->TagGameSession(session.GetGameSessionId());
|
||||
#else
|
||||
GlobalCrashReporter->TagGameSession(std::string(session.GetGameSessionId()));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
|
||||
::Aws::GameLift::Metrics::IMetricsProcessor *GameLiftMetricsGlobalProcessor() {
|
||||
return GlobalProcessor.get();
|
||||
}
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
#include <aws/gamelift/metrics/HighResolutionClock.h>
|
||||
|
||||
#ifndef GAMELIFT_USE_STD
|
||||
#include <aws/gamelift/metrics/InternalTypes.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
/**
|
||||
* We hide the internal chrono use and report a time as int64 nanoseconds
|
||||
* publicly.
|
||||
*
|
||||
* Then convert back to chrono internally.
|
||||
*/
|
||||
|
||||
namespace {
|
||||
using Nanoseconds =
|
||||
std::chrono::duration<Aws::GameLift::Metrics::Int64, std::nano>;
|
||||
}
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
namespace Internal {
|
||||
Int64 HighResolutionClock::Now() {
|
||||
const auto now = std::chrono::high_resolution_clock::now();
|
||||
return std::chrono::time_point_cast<Nanoseconds>(now)
|
||||
.time_since_epoch()
|
||||
.count();
|
||||
}
|
||||
|
||||
double HighResolutionClock::ToMilliseconds(Int64 duration) {
|
||||
using Milliseconds = std::chrono::duration<double, std::milli>;
|
||||
return std::chrono::duration_cast<Milliseconds>(Nanoseconds(duration))
|
||||
.count();
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
|
||||
#endif // !GAMELIFT_USE_STD
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
#include <aws/gamelift/metrics/IMetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/DynamicTag.h>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
|
||||
IMetricsEnqueuer::~IMetricsEnqueuer() {}
|
||||
|
||||
IMetricsProcessor::~IMetricsProcessor() {}
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
MetricMessage MetricMessage::TagSet(IMetric &metric, std::string key,
|
||||
std::string value) {
|
||||
DynamicTag *tag = new DynamicTag(std::move(key), std::move(value));
|
||||
return MetricMessage(MetricMessageType::TagSet, &metric, MetricSetTag(tag));
|
||||
}
|
||||
|
||||
MetricMessage MetricMessage::TagRemove(Aws::GameLift::Metrics::IMetric &metric,
|
||||
std::string key) {
|
||||
DynamicTag *tag = new DynamicTag(std::move(key), "");
|
||||
return MetricMessage(MetricMessageType::TagRemove, &metric,
|
||||
MetricSetTag(tag));
|
||||
}
|
||||
#else
|
||||
MetricMessage MetricMessage::TagSet(IMetric &metric, const char *key,
|
||||
const char *value) {
|
||||
DynamicTag *tag = new DynamicTag(key, value);
|
||||
return MetricMessage(MetricMessageType::TagSet, &metric, MetricSetTag(tag));
|
||||
}
|
||||
|
||||
MetricMessage MetricMessage::TagRemove(IMetric &metric, const char *key) {
|
||||
DynamicTag *tag = new DynamicTag(key, "");
|
||||
return MetricMessage(MetricMessageType::TagRemove, &metric,
|
||||
MetricSetTag(tag));
|
||||
}
|
||||
#endif
|
||||
|
||||
bool operator==(const MetricSetTag &a, const MetricSetTag &b) {
|
||||
return a.Ptr->Key == b.Ptr->Key && a.Ptr->Value == b.Ptr->Value;
|
||||
}
|
||||
|
||||
void CopyTagMessage(const MetricMessage &original, IMetric &destMetric,
|
||||
IMetricsEnqueuer &enqueuer) {
|
||||
switch (original.Type) {
|
||||
case MetricMessageType::TagSet:
|
||||
enqueuer.Enqueue(MetricMessage::TagSet(destMetric,
|
||||
original.SetTag.Ptr->Key.c_str(),
|
||||
original.SetTag.Ptr->Value.c_str()));
|
||||
break;
|
||||
case MetricMessageType::TagRemove:
|
||||
enqueuer.Enqueue(
|
||||
MetricMessage::TagRemove(destMetric, original.SetTag.Ptr->Key.c_str()));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -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 <aws/gamelift/metrics/InternalTypes.h>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
IMetric::~IMetric() {}
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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/KeySuffix.h>
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
void KeySuffix::Apply(const IMetric &original, DynamicMetric &target) {
|
||||
target.SetKey(std::string(original.GetKey()) + m_suffix);
|
||||
}
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
#else
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
KeySuffix::KeySuffix() {
|
||||
std::fill(std::begin(m_suffix), std::end(m_suffix), '\0');
|
||||
}
|
||||
|
||||
KeySuffix::KeySuffix(const char *newSuffix) {
|
||||
#ifdef _WIN32
|
||||
strncpy_s(m_suffix, KeySuffix::MAXIMUM_SUFFIX_LENGTH, newSuffix,
|
||||
KeySuffix::MAXIMUM_SUFFIX_LENGTH);
|
||||
#else
|
||||
strncpy(m_suffix, newSuffix, KeySuffix::MAXIMUM_SUFFIX_LENGTH);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
void KeySuffix::SetSuffix(const char *newSuffix) {
|
||||
#ifdef _WIN32
|
||||
strncpy_s(m_suffix, KeySuffix::MAXIMUM_SUFFIX_LENGTH, newSuffix,
|
||||
KeySuffix::MAXIMUM_SUFFIX_LENGTH);
|
||||
#else
|
||||
strncpy(m_suffix, newSuffix, KeySuffix::MAXIMUM_SUFFIX_LENGTH);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
void KeySuffix::Apply(const IMetric &original, DynamicMetric &target) {
|
||||
std::string key = original.GetKey();
|
||||
key += m_suffix;
|
||||
target.SetKey(key.c_str());
|
||||
}
|
||||
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
|
||||
#endif // GAMELIFT_USE_STD
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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/MetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/DerivedMetric.h>
|
||||
#include <aws/gamelift/metrics/GaugeMacros.h>
|
||||
#include <iterator>
|
||||
#include <unordered_set>
|
||||
|
||||
void MetricsProcessor::ProcessMetrics() {
|
||||
const auto now = ClockT::now();
|
||||
if (now < m_nextCaptureTime) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The server_up metric needs to be set on each flush period, as an untouched
|
||||
// metric will automatically expire in many metrics backends (e.g. Prometheus)
|
||||
GAMELIFT_METRICS_SET(ServerUpGauge, 1);
|
||||
|
||||
ProcessMetricsNow();
|
||||
}
|
||||
|
||||
void MetricsProcessor::ProcessMetricsNow() {
|
||||
if (m_preProcessCallback) {
|
||||
m_preProcessCallback();
|
||||
}
|
||||
|
||||
const auto messageCount = m_messageQueueMPSC.size_approx();
|
||||
m_messageQueueMPSC.try_dequeue_bulk(std::back_inserter(m_processQueue),
|
||||
messageCount);
|
||||
|
||||
m_combinedMetrics.Clear();
|
||||
ProcessMessages(m_processQueue);
|
||||
m_processQueue.clear();
|
||||
m_enqueuer.Clear();
|
||||
|
||||
m_nextCaptureTime = ClockT::now() + m_captureInterval;
|
||||
}
|
||||
|
||||
namespace {
|
||||
void UpdateDerivedMetrics(std::vector<MetricMessage> &messages,
|
||||
IMetricsEnqueuer &enqueuer) {
|
||||
for (auto &message : messages) {
|
||||
struct HandleMessageVisitor final
|
||||
: public Aws::GameLift::Metrics::IDerivedMetricVisitor {
|
||||
MetricMessage &m_message;
|
||||
IMetricsEnqueuer &m_enqueuer;
|
||||
|
||||
explicit HandleMessageVisitor(MetricMessage &message,
|
||||
IMetricsEnqueuer &enqueuer) noexcept
|
||||
: m_message(message), m_enqueuer(enqueuer) {}
|
||||
|
||||
virtual void VisitDerivedMetric(
|
||||
Aws::GameLift::Metrics::IDerivedMetric &metric) override {
|
||||
metric.HandleMessage(m_message, m_enqueuer);
|
||||
}
|
||||
};
|
||||
|
||||
HandleMessageVisitor visitor(message, enqueuer);
|
||||
message.Metric->GetDerivedMetrics().Visit(visitor);
|
||||
}
|
||||
}
|
||||
|
||||
void SubmitDerivedMetrics(std::vector<MetricMessage> &messages,
|
||||
IMetricsEnqueuer &enqueuer) {
|
||||
std::unordered_set<const Aws::GameLift::Metrics::IMetric *> submittedMetrics;
|
||||
|
||||
for (auto &message : messages) {
|
||||
const bool derivativeMetricsSubmitted =
|
||||
submittedMetrics.find(message.Metric) != std::end(submittedMetrics);
|
||||
if (derivativeMetricsSubmitted) {
|
||||
continue;
|
||||
}
|
||||
|
||||
submittedMetrics.emplace(message.Metric);
|
||||
|
||||
class EmitMessageVisitor final
|
||||
: public Aws::GameLift::Metrics::IDerivedMetricVisitor {
|
||||
public:
|
||||
EmitMessageVisitor(const Aws::GameLift::Metrics::IMetric *originalMetric,
|
||||
IMetricsEnqueuer &enqueuer) noexcept
|
||||
: m_originalMetric(originalMetric), m_enqueuer(enqueuer) {}
|
||||
|
||||
virtual void VisitDerivedMetric(
|
||||
Aws::GameLift::Metrics::IDerivedMetric &metric) override {
|
||||
metric.EmitMetrics(m_originalMetric, m_enqueuer);
|
||||
}
|
||||
|
||||
private:
|
||||
const Aws::GameLift::Metrics::IMetric *m_originalMetric;
|
||||
IMetricsEnqueuer &m_enqueuer;
|
||||
};
|
||||
|
||||
EmitMessageVisitor visitor(message.Metric, enqueuer);
|
||||
message.Metric->GetDerivedMetrics().Visit(visitor);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void MetricsProcessor::ProcessMessages(std::vector<MetricMessage> &messages) {
|
||||
// Compute derived metrics and appends their messages to the end
|
||||
UpdateDerivedMetrics(messages, m_enqueuer);
|
||||
SubmitDerivedMetrics(messages, m_enqueuer);
|
||||
std::copy(std::begin(m_enqueuer.m_messages), std::end(m_enqueuer.m_messages),
|
||||
std::back_inserter(messages));
|
||||
|
||||
// Combine all the metrics
|
||||
for (auto &message : messages) {
|
||||
if (message.IsTag()) {
|
||||
m_metricTags.Handle(message);
|
||||
} else {
|
||||
m_combinedMetrics.Add(message);
|
||||
}
|
||||
}
|
||||
|
||||
if (m_combinedMetrics.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build & send packets
|
||||
for (const auto &message : m_combinedMetrics) {
|
||||
m_packet.Append(message, m_globalTags, m_metricTags.GetTags(message.Metric),
|
||||
m_sendPacket);
|
||||
}
|
||||
m_packet.Flush(m_sendPacket);
|
||||
}
|
||||
|
||||
void MetricsProcessor::OnStartGameSession(
|
||||
const Aws::GameLift::Server::Model::GameSession &session) {
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
const char *sessionId = session.GetGameSessionId().c_str();
|
||||
#else
|
||||
const char *sessionId = session.GetGameSessionId();
|
||||
#endif
|
||||
|
||||
if (sessionId != nullptr && sessionId[0] != '\0') {
|
||||
SetGlobalTag("session_id", sessionId);
|
||||
}
|
||||
}
|
||||
@@ -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/MetricsUtils.h>
|
||||
#include <aws/gamelift/metrics/GlobalMetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/MetricsSettings.h>
|
||||
#include <aws/gamelift/common/GameLiftErrors.h>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
using namespace Aws::GameLift::Server;
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
|
||||
MetricsParameters CreateMetricsParametersFromEnvironmentOrDefault() {
|
||||
// Start with default values
|
||||
const char* statsdHost = DEFAULT_STATSD_HOST;
|
||||
int statsdPort = DEFAULT_STATSD_PORT;
|
||||
const char* crashReporterHost = DEFAULT_CRASH_REPORTER_HOST;
|
||||
int crashReporterPort = DEFAULT_CRASH_REPORTER_PORT;
|
||||
int flushIntervalMs = DEFAULT_FLUSH_INTERVAL_MS;
|
||||
int maxPacketSize = DEFAULT_MAX_PACKET_SIZE;
|
||||
|
||||
// Check environment variables and override defaults
|
||||
const char* envStatsdHost = std::getenv(ENV_VAR_STATSD_HOST);
|
||||
if (envStatsdHost && envStatsdHost[0] != '\0') {
|
||||
statsdHost = envStatsdHost;
|
||||
spdlog::info("Env override for statsdHost: {}", statsdHost);
|
||||
}
|
||||
|
||||
const char* envStatsdPort = std::getenv(ENV_VAR_STATSD_PORT);
|
||||
if (envStatsdPort && envStatsdPort[0] != '\0') {
|
||||
statsdPort = std::atoi(envStatsdPort);
|
||||
spdlog::info("Env override for statsdPort: {}", statsdPort);
|
||||
}
|
||||
|
||||
const char* envCrashReporterHost = std::getenv(ENV_VAR_CRASH_REPORTER_HOST);
|
||||
if (envCrashReporterHost && envCrashReporterHost[0] != '\0') {
|
||||
crashReporterHost = envCrashReporterHost;
|
||||
spdlog::info("Env override for crashReporterHost: {}", crashReporterHost);
|
||||
}
|
||||
|
||||
const char* envCrashReporterPort = std::getenv(ENV_VAR_CRASH_REPORTER_PORT);
|
||||
if (envCrashReporterPort && envCrashReporterPort[0] != '\0') {
|
||||
crashReporterPort = std::atoi(envCrashReporterPort);
|
||||
spdlog::info("Env override for crashReporterPort: {}", crashReporterPort);
|
||||
}
|
||||
|
||||
const char* envFlushInterval = std::getenv(ENV_VAR_FLUSH_INTERVAL_MS);
|
||||
if (envFlushInterval && envFlushInterval[0] != '\0') {
|
||||
flushIntervalMs = std::atoi(envFlushInterval);
|
||||
spdlog::info("Env override for flushIntervalMs: {}", flushIntervalMs);
|
||||
}
|
||||
|
||||
const char* envMaxPacketSize = std::getenv(ENV_VAR_MAX_PACKET_SIZE);
|
||||
if (envMaxPacketSize && envMaxPacketSize[0] != '\0') {
|
||||
maxPacketSize = std::atoi(envMaxPacketSize);
|
||||
spdlog::info("Env override for maxPacketSize: {}", maxPacketSize);
|
||||
}
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
return MetricsParameters(std::string(statsdHost), statsdPort, std::string(crashReporterHost), crashReporterPort, flushIntervalMs, maxPacketSize);
|
||||
#else
|
||||
return MetricsParameters(statsdHost, statsdPort, crashReporterHost, crashReporterPort, flushIntervalMs, maxPacketSize);
|
||||
#endif
|
||||
}
|
||||
|
||||
MetricsSettings FromMetricsParameters(const Aws::GameLift::Server::MetricsParameters ¶ms) {
|
||||
MetricsSettings settings;
|
||||
settings.StatsDClientHost = params.GetStatsDHost();
|
||||
settings.StatsDClientPort = params.GetStatsDPort();
|
||||
settings.CrashReporterHost = params.GetCrashReporterHost();
|
||||
settings.CrashReporterPort = params.GetCrashReporterPort();
|
||||
settings.MaxPacketSizeBytes = params.GetMaxPacketSize();
|
||||
settings.CaptureIntervalSec = params.GetFlushIntervalMs() / 1000.0f;
|
||||
return settings;
|
||||
}
|
||||
|
||||
Aws::GameLift::GenericOutcome ValidateMetricsParameters(const Aws::GameLift::Server::MetricsParameters ¶ms) {
|
||||
// Validate StatsD host
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
if (params.GetStatsDHost().empty()) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "StatsDHost cannot be empty"));
|
||||
}
|
||||
#else
|
||||
const char* statsdHost = params.GetStatsDHost();
|
||||
if (statsdHost == nullptr || statsdHost[0] == '\0') {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "StatsDHost cannot be empty"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Validate StatsD port
|
||||
int statsdPort = params.GetStatsDPort();
|
||||
if (statsdPort < PORT_MIN || statsdPort > PORT_MAX) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "StatsDPort must be between 1 and 65535"));
|
||||
}
|
||||
|
||||
// Validate CrashReporter host
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
if (params.GetCrashReporterHost().empty()) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "CrashReporterHost cannot be empty"));
|
||||
}
|
||||
#else
|
||||
const char* crashReporterHost = params.GetCrashReporterHost();
|
||||
if (crashReporterHost == nullptr || crashReporterHost[0] == '\0') {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "CrashReporterHost cannot be empty"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Validate CrashReporter port
|
||||
int crashReporterPort = params.GetCrashReporterPort();
|
||||
if (crashReporterPort < PORT_MIN || crashReporterPort > PORT_MAX) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "CrashReporterPort must be between 1 and 65535"));
|
||||
}
|
||||
|
||||
// Validate FlushIntervalMs
|
||||
int flushIntervalMs = params.GetFlushIntervalMs();
|
||||
if (flushIntervalMs < 0) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "FlushIntervalMs must be non-negative"));
|
||||
}
|
||||
|
||||
// Validate MaxPacketSize
|
||||
int maxPacketSize = params.GetMaxPacketSize();
|
||||
if (maxPacketSize < 0) {
|
||||
return Aws::GameLift::GenericOutcome(Aws::GameLift::GameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION, "MaxPacketSize must be non-negative"));
|
||||
}
|
||||
|
||||
return Aws::GameLift::GenericOutcome(nullptr);
|
||||
}
|
||||
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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/PacketBuilder.h>
|
||||
#include <aws/gamelift/metrics/Samplers.h>
|
||||
#include <aws/gamelift/metrics/LoggerMacros.h>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
namespace {
|
||||
static constexpr int NullTerminator = 1;
|
||||
}
|
||||
|
||||
PacketBuilder::PacketBuilder(size_t packetSize, int floatPrecision)
|
||||
: m_packetSize(packetSize), m_floatPrecision(floatPrecision) {
|
||||
m_formatBuffer << std::setprecision(floatPrecision)
|
||||
<< std::setiosflags(std::ios_base::fixed);
|
||||
}
|
||||
|
||||
void PacketBuilder::Append(
|
||||
const MetricMessage &message, const TagMap &globalTags,
|
||||
const TagMap &metricTags,
|
||||
Aws::GameLift::Metrics::MetricsSettings::SendPacketFunc sendPacketFunc) {
|
||||
const auto startPosition = m_formatBuffer.tellp();
|
||||
AppendToStream(message, m_floatPrecision, globalTags, metricTags,
|
||||
m_formatBuffer);
|
||||
const auto endPosition = m_formatBuffer.tellp();
|
||||
|
||||
const size_t messageLength = endPosition - startPosition;
|
||||
if (messageLength > GetPacketSize() - NullTerminator) {
|
||||
// If there's no way a message can fit the packet size, we drop it and log
|
||||
// an error.
|
||||
|
||||
try {
|
||||
// Use a simple message that doesn't reference message.Metric
|
||||
// which could be null in tests
|
||||
GAMELIFT_METRICS_LOG_WARN(
|
||||
"Message length ({}) exceeds packet size ({}), message has "
|
||||
"been dropped.",
|
||||
messageLength, GetPacketSize() - NullTerminator);
|
||||
} catch (...) {
|
||||
// Silently continue if logging fails - don't break tests
|
||||
}
|
||||
|
||||
// Reset the stream to the start position so we can continue appending
|
||||
m_formatBuffer.seekp(startPosition);
|
||||
return;
|
||||
}
|
||||
|
||||
const size_t formatBufferLength = endPosition;
|
||||
if (formatBufferLength > GetPacketSize() - NullTerminator) {
|
||||
// Likely case:
|
||||
// this message caused us to exceed packet size
|
||||
//
|
||||
// 1. Seek back to the end of the previous message (cut the new message
|
||||
// out of the stream).
|
||||
// 2. Flush (sending packet).
|
||||
// 3. Re-append the message to the (now) empty stream.
|
||||
m_formatBuffer.seekp(startPosition);
|
||||
Flush(sendPacketFunc);
|
||||
AppendToStream(message, m_floatPrecision, globalTags, metricTags,
|
||||
m_formatBuffer);
|
||||
} else if (formatBufferLength == GetPacketSize() - NullTerminator) {
|
||||
// Unlikely case:
|
||||
// we hit the packet size exactly
|
||||
// so we can just flush
|
||||
Flush(sendPacketFunc);
|
||||
}
|
||||
}
|
||||
|
||||
void PacketBuilder::Flush(
|
||||
Aws::GameLift::Metrics::MetricsSettings::SendPacketFunc sendPacketFunc) {
|
||||
m_sendBuffer = m_formatBuffer.str();
|
||||
m_sendBuffer.resize(m_formatBuffer.tellp());
|
||||
|
||||
sendPacketFunc(m_sendBuffer.c_str(),
|
||||
static_cast<int>(m_sendBuffer.size() + NullTerminator));
|
||||
|
||||
m_formatBuffer.seekp(0);
|
||||
}
|
||||
|
||||
namespace {
|
||||
void WriteTags(const PacketBuilder::TagMap &tags, std::ostream &stream) {
|
||||
if (tags.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::begin(tags);
|
||||
stream << it->first << ':' << it->second;
|
||||
for (++it; it != std::end(tags); ++it) {
|
||||
stream << ',' << it->first << ':' << it->second;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteTags(const PacketBuilder::TagMap &globalTags,
|
||||
const PacketBuilder::TagMap &metricTags, std::ostream &stream) {
|
||||
if (globalTags.size() > 0 || metricTags.size() > 0) {
|
||||
stream << "|#";
|
||||
WriteTags(globalTags, stream);
|
||||
if (globalTags.size() > 0 && metricTags.size() > 0) {
|
||||
stream << ',';
|
||||
}
|
||||
WriteTags(metricTags, stream);
|
||||
}
|
||||
}
|
||||
|
||||
void WriteValue(double value, int floatPrecision, std::ostream &stream) {
|
||||
const auto valueAsInteger = static_cast<int64_t>(value);
|
||||
const double fractionalPart = value - valueAsInteger;
|
||||
|
||||
/*
|
||||
* We check if the fractional part of our value is 0 when rounded for display.
|
||||
*
|
||||
* We configured ostream to round to a specific float precision earlier.
|
||||
* Ie with a precision = 2, 1.425 becomes 1.43
|
||||
*
|
||||
* Due to floating point imprecision, we may, at some point, end up with a
|
||||
* value like 1.0000002. When rounded this ends up as 1.00 (with precision = 2
|
||||
* as before) and we'd prefer to print it as an integer.
|
||||
*
|
||||
* The check is simple: we multiply the fraction by 10^precision and see if
|
||||
* when rounded the value equals to 0.
|
||||
*
|
||||
* 0.425 * 10^2 = 42.5 ~= 43 => not zero so we print 1.425 as a real
|
||||
* 0.0000002 * 10^2 = 0.00002 ~= 0 => zero so we can print 1.0000002 as an
|
||||
* integer
|
||||
*
|
||||
* This also takes care of integer valued doubles in general. (Fractional part
|
||||
* is already zero in that case.)
|
||||
*/
|
||||
const double thousandths = std::pow(10, floatPrecision);
|
||||
const bool hasFractionalPart = std::round(fractionalPart * thousandths) != 0;
|
||||
|
||||
if (hasFractionalPart) {
|
||||
stream << value;
|
||||
} else {
|
||||
stream << valueAsInteger;
|
||||
}
|
||||
}
|
||||
|
||||
void WriteSampleRate(const MetricMessage &message, std::ostream &stream) {
|
||||
// Get the sample rate from the sampler
|
||||
if (message.Metric) {
|
||||
Aws::GameLift::Metrics::ISampler &sampler = message.Metric->GetSampler();
|
||||
float rate = sampler.GetSampleRate();
|
||||
|
||||
// Only add sample rate if it's less than 1.0 (1.0 is implicit/default in
|
||||
// StatsD). Packets with a 0.0 sample rate are not sent.
|
||||
if (rate < 1.0f) {
|
||||
// Format using a separate stringstream with default formatting
|
||||
std::ostringstream rateStream;
|
||||
rateStream << rate;
|
||||
|
||||
stream << "|@" << rateStream.str();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WriteMessage(const MetricMessage &message, int floatPrecision,
|
||||
std::ostream &stream) {
|
||||
static constexpr auto showPositiveSign = std::ios_base::showpos;
|
||||
|
||||
stream << message.Metric->GetKey() << ':';
|
||||
|
||||
if (message.Type == MetricMessageType::GaugeSet) {
|
||||
WriteValue(message.SubmitDouble.Value, floatPrecision, stream);
|
||||
stream << "|g";
|
||||
} else if (message.Type == MetricMessageType::GaugeAdd) {
|
||||
stream << std::setiosflags(showPositiveSign);
|
||||
WriteValue(message.SubmitDouble.Value, floatPrecision, stream);
|
||||
stream << "|g" << std::resetiosflags(showPositiveSign);
|
||||
} else if (message.Type == MetricMessageType::CounterAdd) {
|
||||
WriteValue(message.SubmitDouble.Value, floatPrecision, stream);
|
||||
stream << "|c" << std::resetiosflags(showPositiveSign);
|
||||
} else if (message.Type == MetricMessageType::TimerSet) {
|
||||
WriteValue(message.SubmitDouble.Value, floatPrecision, stream);
|
||||
stream << "|ms";
|
||||
}
|
||||
|
||||
// Add sample rate if using SampleFraction
|
||||
WriteSampleRate(message, stream);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void AppendToStream(const MetricMessage &message, int floatPrecision,
|
||||
const PacketBuilder::TagMap &globalTags,
|
||||
const PacketBuilder::TagMap &metricTags,
|
||||
std::ostream &stream) {
|
||||
if (message.Type == MetricMessageType::GaugeSet &&
|
||||
message.SubmitDouble.Value < 0) {
|
||||
/*
|
||||
* There's an intentional amgibuity in `gaugor:-10|g`
|
||||
|
||||
* It means 'subtract 10 from gaugor'. So the only way to set a
|
||||
* gauge to a negative value is by setting it to zero first and
|
||||
* subtracting:
|
||||
* gaugor:0|g
|
||||
* gaugor:-10|g
|
||||
*
|
||||
* See:
|
||||
https://github.com/statsd/statsd/blob/master/docs/metric_types.md#gauges
|
||||
*/
|
||||
WriteMessage(MetricMessage::GaugeSet(*message.Metric, 0), floatPrecision,
|
||||
stream);
|
||||
WriteTags(globalTags, metricTags, stream);
|
||||
stream << '\n';
|
||||
WriteMessage(
|
||||
MetricMessage::GaugeAdd(*message.Metric, message.SubmitDouble.Value),
|
||||
floatPrecision, stream);
|
||||
WriteTags(globalTags, metricTags, stream);
|
||||
stream << '\n';
|
||||
} else if (message.IsCounter() && message.SubmitDouble.Value <= 0) {
|
||||
// Skip non-positive or negative counters
|
||||
} else {
|
||||
WriteMessage(message, floatPrecision, stream);
|
||||
WriteTags(globalTags, metricTags, stream);
|
||||
stream << '\n';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* 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/Percentiles.h>
|
||||
|
||||
#include <aws/gamelift/metrics/LoggerMacros.h>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <iomanip>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
namespace {
|
||||
struct PercentileMetric {
|
||||
double m_percentile;
|
||||
DynamicMetric m_metric;
|
||||
bool m_metricInitialized = false;
|
||||
|
||||
explicit PercentileMetric(double percentile) : m_percentile(percentile) {}
|
||||
|
||||
double GetPercentile() const { return m_percentile; }
|
||||
void SetPercentile(double percentile) { m_percentile = percentile; }
|
||||
PercentileMetric &WithPercentile(double percentile) {
|
||||
SetPercentile(percentile);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* INTERNAL: concrete percentile metric implementation
|
||||
*/
|
||||
class PercentilesImpl : public IDerivedMetric {
|
||||
public:
|
||||
template <class It> PercentilesImpl(It begin, It end) {
|
||||
std::transform(begin, end, std::back_inserter(m_percentiles),
|
||||
[](double value) { return PercentileMetric(value); });
|
||||
}
|
||||
|
||||
virtual void HandleMessage(MetricMessage &message,
|
||||
IMetricsEnqueuer &submitter) override {
|
||||
switch (message.Type) {
|
||||
case MetricMessageType::GaugeAdd:
|
||||
m_currentValue += message.SubmitDouble.Value;
|
||||
AppendValue(m_currentValue);
|
||||
break;
|
||||
case MetricMessageType::GaugeSet:
|
||||
case MetricMessageType::TimerSet:
|
||||
m_currentValue = message.SubmitDouble.Value;
|
||||
AppendValue(m_currentValue);
|
||||
break;
|
||||
case MetricMessageType::TagSet:
|
||||
case MetricMessageType::TagRemove:
|
||||
for (auto &percentile : m_percentiles) {
|
||||
CopyTagMessage(message, percentile.m_metric, submitter);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void EmitMetrics(const IMetric *originalMetric,
|
||||
IMetricsEnqueuer &submitter) override {
|
||||
if (m_numSeenSinceLastEmitCall == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_numSeenSinceLastEmitCall = 0;
|
||||
std::sort(std::begin(m_values), std::end(m_values));
|
||||
for (auto &percentile : m_percentiles) {
|
||||
EmitPercentile(originalMetric, percentile, submitter);
|
||||
}
|
||||
m_values.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
void AppendValue(double newCurrentValue) {
|
||||
m_values.emplace_back(newCurrentValue);
|
||||
m_numSeenSinceLastEmitCall++;
|
||||
}
|
||||
|
||||
void EmitPercentile(const IMetric *originalMetric,
|
||||
PercentileMetric &percentile,
|
||||
IMetricsEnqueuer &submitter) {
|
||||
const double value = ComputePercentile(percentile.GetPercentile());
|
||||
|
||||
if (!percentile.m_metricInitialized) {
|
||||
percentile.m_metric.SetMetricType(originalMetric->GetMetricType());
|
||||
|
||||
std::stringstream stream;
|
||||
stream << originalMetric->GetKey() << ".p" << std::setw(2)
|
||||
<< std::setfill('0')
|
||||
<< static_cast<int>(percentile.GetPercentile() * 100.0);
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
percentile.m_metric.SetKey(stream.str());
|
||||
#else
|
||||
percentile.m_metric.SetKey(stream.str().c_str());
|
||||
#endif
|
||||
percentile.m_metricInitialized = true;
|
||||
}
|
||||
|
||||
switch (percentile.m_metric.GetMetricType()) {
|
||||
case MetricType::Gauge:
|
||||
submitter.Enqueue(MetricMessage::GaugeSet(percentile.m_metric, value));
|
||||
break;
|
||||
case MetricType::Timer:
|
||||
submitter.Enqueue(MetricMessage::TimerSet(percentile.m_metric, value));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double ComputePercentile(double percentile) const {
|
||||
const double startIndexFloat = percentile * (m_values.size() - 1);
|
||||
const size_t startIndex = static_cast<size_t>(startIndexFloat);
|
||||
const double fractionalPart = startIndexFloat - startIndex;
|
||||
|
||||
const bool isBetweenValues = fractionalPart != 0;
|
||||
if (isBetweenValues) {
|
||||
const double start = m_values[startIndex];
|
||||
const double end = m_values[startIndex + 1];
|
||||
return start + fractionalPart * (end - start);
|
||||
} else {
|
||||
return m_values[startIndex];
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<PercentileMetric> m_percentiles;
|
||||
|
||||
size_t m_numSeenSinceLastEmitCall = 0;
|
||||
double m_currentValue = 0;
|
||||
std::vector<double> m_values;
|
||||
};
|
||||
|
||||
/**
|
||||
* INTERNAL: validate percentiles and report errors / warnings for debug builds
|
||||
*
|
||||
* @param begin The begin iterator of percentile collection
|
||||
* @param end The past-the-end iterator of percentile collection
|
||||
*/
|
||||
template <class InputIt>
|
||||
inline void ValidatePercentiles(InputIt begin, InputIt end) {
|
||||
if (begin == end) {
|
||||
GAMELIFT_METRICS_LOG_CRITICAL("Percentile list is empty.");
|
||||
}
|
||||
|
||||
for (auto it = begin + 1; it != end; ++it) {
|
||||
if (*(it - 1) == *it) {
|
||||
GAMELIFT_METRICS_LOG_CRITICAL("Duplicate percentiles detected.", *it);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
const auto &value = *it;
|
||||
if (value < 0 || value > 1) {
|
||||
GAMELIFT_METRICS_LOG_CRITICAL("Percentiles must be in the [0, 1] range.",
|
||||
value);
|
||||
}
|
||||
|
||||
const auto percentileFloat = value * 100;
|
||||
const auto percentileInteger = static_cast<int>(percentileFloat);
|
||||
const double fractionalPart = percentileFloat - percentileInteger;
|
||||
const double absDistance = 0.0001;
|
||||
if (std::abs(fractionalPart) >= absDistance) {
|
||||
// Warn about the user entering too many digits past decimal point.
|
||||
// Diff might be a tiny value due to float rounding, so we check against
|
||||
// distance to ignore it.
|
||||
GAMELIFT_METRICS_LOG_WARN(
|
||||
"Percentile {} ({}) has too many digits past the decimal "
|
||||
"point. It will be truncated to {}",
|
||||
percentileFloat, value, percentileInteger);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
namespace Internal {
|
||||
PercentilesWrapper PercentilesWrapper::Create(double *begin, double *end) {
|
||||
std::sort(begin, end); // sort percentiles (mostly for validation but might
|
||||
// as well keep them in this order)
|
||||
|
||||
#ifndef NDEBUG
|
||||
ValidatePercentiles(begin, end);
|
||||
#endif
|
||||
|
||||
return PercentilesWrapper(new PercentilesImpl(begin, end));
|
||||
}
|
||||
} // namespace Internal
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
#include <aws/gamelift/metrics/Samplers.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
namespace Internal {
|
||||
/**
|
||||
* Basic wrapper around seed_seq so we don't have to leak it in the header
|
||||
*/
|
||||
struct SeedState {
|
||||
std::seed_seq m_seed;
|
||||
// std::seed_seq has internal state that is updated when we first initialize
|
||||
// the sampler per-thread
|
||||
std::mutex m_mutex;
|
||||
|
||||
explicit SeedState(Int64 seed) : m_seed{seed} {}
|
||||
};
|
||||
} // namespace Internal
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Per thread sampler with own RNG.
|
||||
*
|
||||
* We use this to avoid synchronization in multithreaded scenarios.
|
||||
* This way we only have to lock when first initializing the thread.
|
||||
*/
|
||||
class PerThreadSampler {
|
||||
public:
|
||||
explicit PerThreadSampler(Internal::SeedState &state) noexcept
|
||||
: m_distribution(0.0, 1.0) {
|
||||
const std::lock_guard<std::mutex> guard(state.m_mutex);
|
||||
if (state.m_seed.size() > 0) {
|
||||
m_engine = std::mt19937(state.m_seed);
|
||||
}
|
||||
}
|
||||
|
||||
bool ShouldTakeSample(float fraction) {
|
||||
const float randomValue = m_distribution(m_engine);
|
||||
return randomValue <= fraction;
|
||||
}
|
||||
|
||||
private:
|
||||
std::uniform_real_distribution<float> m_distribution;
|
||||
std::mt19937 m_engine;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
ISampler::~ISampler() {}
|
||||
|
||||
SampleFraction::SampleFraction(float fractionToSample, Int64 seed)
|
||||
: m_fractionToSample(fractionToSample),
|
||||
m_seed(new Internal::SeedState(seed)) {}
|
||||
|
||||
SampleFraction::~SampleFraction() { delete m_seed; }
|
||||
|
||||
bool SampleFraction::ShouldTakeSample() {
|
||||
// We use per-thread RNG to avoid synchronization.
|
||||
static thread_local PerThreadSampler sampler(*m_seed);
|
||||
return sampler.ShouldTakeSample(m_fractionToSample);
|
||||
}
|
||||
|
||||
Int64 SampleFraction::DefaultSeed() {
|
||||
using Nanoseconds = std::chrono::duration<Int64, std::nano>;
|
||||
return std::chrono::duration_cast<Nanoseconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -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/metrics/StatsDClient.h>
|
||||
#include <aws/gamelift/metrics/LoggerMacros.h>
|
||||
|
||||
using namespace Aws::GameLift::Metrics;
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
StatsDClient::StatsDClient(const std::string& host, int port)
|
||||
#else
|
||||
StatsDClient::StatsDClient(const char* host, int port)
|
||||
#endif
|
||||
: m_socket(m_io_service)
|
||||
, m_endpoint(asio::ip::address::from_string(host), port) {
|
||||
|
||||
try {
|
||||
m_socket.open(asio::ip::udp::v4());
|
||||
} catch (const std::exception& e) {
|
||||
GAMELIFT_METRICS_LOG_ERROR("Failed to open StatsD socket: {}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void StatsDClient::Send(const char* data, int size) {
|
||||
try {
|
||||
m_socket.send_to(asio::buffer(data, size), m_endpoint);
|
||||
} catch (const std::exception& e) {
|
||||
GAMELIFT_METRICS_LOG_ERROR("Failed to send StatsD packet: {}", e.what());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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/Tags.h>
|
||||
#include <aws/gamelift/metrics/DynamicTag.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
||||
void Tags::Handle(MetricMessage &message) {
|
||||
assert(message.Type == MetricMessageType::TagSet ||
|
||||
message.Type == MetricMessageType::TagRemove);
|
||||
|
||||
if (message.Type == MetricMessageType::TagSet) {
|
||||
HandleSet(message.Metric, message.SetTag);
|
||||
} else if (message.Type == MetricMessageType::TagRemove) {
|
||||
HandleRemove(message.Metric, message.SetTag);
|
||||
}
|
||||
}
|
||||
|
||||
void Tags::HandleSet(const IMetric *metric, MetricSetTag &message) {
|
||||
// Create tag map for current metric if not exist
|
||||
auto it = m_tags.find(metric);
|
||||
if (it == std::end(m_tags)) {
|
||||
it = m_tags.emplace(metric, std::unordered_map<std::string, std::string>())
|
||||
.first;
|
||||
}
|
||||
assert(it != std::end(m_tags));
|
||||
auto &metricTags = it->second;
|
||||
|
||||
auto tagIt = metricTags.find(message.Ptr->Key);
|
||||
if (tagIt != std::end(metricTags)) {
|
||||
// Swap-in the new value to avoid copy
|
||||
// Old value gets deleted below.
|
||||
using std::swap;
|
||||
swap(tagIt->second, message.Ptr->Value);
|
||||
} else {
|
||||
// Move key and value into dictionary to avoid copy. (We delete empty shells
|
||||
// below.)
|
||||
metricTags.emplace(std::move(message.Ptr->Key),
|
||||
std::move(message.Ptr->Value));
|
||||
}
|
||||
|
||||
delete message.Ptr;
|
||||
message.Ptr = nullptr;
|
||||
}
|
||||
|
||||
void Tags::HandleRemove(const IMetric *metric, MetricSetTag &message) {
|
||||
auto it = m_tags.find(metric);
|
||||
if (it != std::end(m_tags)) {
|
||||
it->second.erase(message.Ptr->Key);
|
||||
}
|
||||
delete message.Ptr;
|
||||
message.Ptr = nullptr;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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/TypeTraits.h>
|
||||
|
||||
#ifndef GAMELIFT_USE_STD
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Metrics {
|
||||
namespace Internal {
|
||||
const bool TrueType::value;
|
||||
const bool FalseType::value;
|
||||
} // namespace Internal
|
||||
} // namespace Metrics
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
#endif // !GAMELIFT_USE_STD
|
||||
@@ -0,0 +1,443 @@
|
||||
/*
|
||||
* 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/server/GameLiftServerAPI.h>
|
||||
#include <aws/gamelift/internal/GameLiftServerState.h>
|
||||
#include <aws/gamelift/internal/network/IWebSocketClientWrapper.h>
|
||||
#include <aws/gamelift/internal/network/WebSocketppClientWrapper.h>
|
||||
#include <aws/gamelift/server/ProcessParameters.h>
|
||||
#include <aws/gamelift/server/MetricsParameters.h>
|
||||
#include <aws/gamelift/metrics/GlobalMetricsProcessor.h>
|
||||
#include <aws/gamelift/metrics/MetricsSettings.h>
|
||||
#include <aws/gamelift/metrics/MetricsUtils.h>
|
||||
|
||||
#include <aws/gamelift/internal/util/LoggerHelper.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
using namespace Aws::GameLift;
|
||||
|
||||
static const std::string sdkVersion = "5.4.0";
|
||||
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
Aws::GameLift::AwsStringOutcome Server::GetSdkVersion() { return AwsStringOutcome(sdkVersion); }
|
||||
|
||||
Server::InitSDKOutcome Server::InitSDK() { return InitSDK(Aws::GameLift::Server::Model::ServerParameters()); }
|
||||
|
||||
Server::InitSDKOutcome Server::InitSDK(const Aws::GameLift::Server::Model::ServerParameters &serverParameters) {
|
||||
Internal::LoggerHelper::InitializeLogger(serverParameters.GetProcessId());
|
||||
spdlog::info("Initializing GameLift SDK");
|
||||
// Initialize the WebSocketWrapper
|
||||
std::shared_ptr<Internal::IWebSocketClientWrapper> webSocketClientWrapper;
|
||||
std::shared_ptr<Internal::WebSocketppClientType> wsClientPointer = std::make_shared<Internal::WebSocketppClientType>();
|
||||
webSocketClientWrapper = std::make_shared<Internal::WebSocketppClientWrapper>(wsClientPointer);
|
||||
|
||||
InitSDKOutcome initOutcome = InitSDKOutcome(Internal::GameLiftServerState::CreateInstance(webSocketClientWrapper));
|
||||
if (initOutcome.IsSuccess()) {
|
||||
spdlog::info("Created Instance");
|
||||
GenericOutcome networkingOutcome = initOutcome.GetResult()->InitializeNetworking(serverParameters);
|
||||
if (!networkingOutcome.IsSuccess()) {
|
||||
spdlog::error("Networking outcome failure when init SDK");
|
||||
return InitSDKOutcome(networkingOutcome.GetError());
|
||||
}
|
||||
spdlog::info("Networking outcome success. Init SDK success");
|
||||
|
||||
// Set global processor if available
|
||||
Aws::GameLift::Metrics::IMetricsProcessor* globalProcessor = GameLiftMetricsGlobalProcessor();
|
||||
if (globalProcessor != nullptr) {
|
||||
initOutcome.GetResult()->SetGlobalProcessor(globalProcessor);
|
||||
}
|
||||
}
|
||||
return initOutcome;
|
||||
}
|
||||
|
||||
GenericOutcome Server::ProcessReady(const Aws::GameLift::Server::ProcessParameters &processParameters) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->ProcessReady(processParameters);
|
||||
}
|
||||
|
||||
GenericOutcome Server::ProcessEnding() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->ProcessEnding();
|
||||
}
|
||||
|
||||
GenericOutcome Server::ActivateGameSession() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return serverState->ActivateGameSession();
|
||||
}
|
||||
|
||||
StartMatchBackfillOutcome Server::StartMatchBackfill(const Aws::GameLift::Server::Model::StartMatchBackfillRequest &request) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return StartMatchBackfillOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->StartMatchBackfill(request);
|
||||
}
|
||||
|
||||
GenericOutcome Server::StopMatchBackfill(const Aws::GameLift::Server::Model::StopMatchBackfillRequest &request) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->StopMatchBackfill(request);
|
||||
}
|
||||
|
||||
GenericOutcome Server::UpdatePlayerSessionCreationPolicy(Aws::GameLift::Server::Model::PlayerSessionCreationPolicy newPlayerSessionPolicy) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return serverState->UpdatePlayerSessionCreationPolicy(newPlayerSessionPolicy);
|
||||
}
|
||||
|
||||
Aws::GameLift::AwsStringOutcome Server::GetGameSessionId() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return AwsStringOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return AwsStringOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return AwsStringOutcome(serverState->GetGameSessionId());
|
||||
}
|
||||
|
||||
Aws::GameLift::AwsLongOutcome Server::GetTerminationTime() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return AwsLongOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return AwsLongOutcome(serverState->GetTerminationTime());
|
||||
}
|
||||
|
||||
GenericOutcome Server::AcceptPlayerSession(const std::string &playerSessionId) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return serverState->AcceptPlayerSession(playerSessionId);
|
||||
}
|
||||
|
||||
GenericOutcome Server::RemovePlayerSession(const std::string &playerSessionId) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return serverState->RemovePlayerSession(playerSessionId);
|
||||
}
|
||||
|
||||
#else
|
||||
Aws::GameLift::AwsStringOutcome Server::GetSdkVersion() { return AwsStringOutcome(sdkVersion.c_str()); }
|
||||
|
||||
GenericOutcome Server::InitSDK() { return InitSDK(Aws::GameLift::Server::Model::ServerParameters()); }
|
||||
|
||||
GenericOutcome Server::InitSDK(const Aws::GameLift::Server::Model::ServerParameters &serverParameters) {
|
||||
Internal::LoggerHelper::InitializeLogger(serverParameters.GetProcessId());
|
||||
spdlog::info("Initializing server SDK");
|
||||
// Initialize the WebSocketWrapper
|
||||
Internal::InitSDKOutcome initOutcome =
|
||||
Internal::InitSDKOutcome(Internal::GameLiftServerState::CreateInstance<Internal::WebSocketppClientWrapper, Internal::WebSocketppClientType>());
|
||||
if (initOutcome.IsSuccess()) {
|
||||
spdlog::info("Created Instance");
|
||||
GenericOutcome networkingOutcome = initOutcome.GetResult()->InitializeNetworking(serverParameters);
|
||||
if (!networkingOutcome.IsSuccess()) {
|
||||
spdlog::error("Networking outcome failure when init SDK");
|
||||
return GenericOutcome(networkingOutcome.GetError());
|
||||
}
|
||||
spdlog::info("Networking outcome success. Init SDK success");
|
||||
|
||||
// Set global processor if available
|
||||
Aws::GameLift::Metrics::IMetricsProcessor* globalProcessor = GameLiftMetricsGlobalProcessor();
|
||||
if (globalProcessor != nullptr) {
|
||||
initOutcome.GetResult()->SetGlobalProcessor(globalProcessor);
|
||||
}
|
||||
}
|
||||
return GenericOutcome(nullptr);
|
||||
}
|
||||
|
||||
GenericOutcome Server::ProcessReady(const Aws::GameLift::Server::ProcessParameters &processParameters) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->ProcessReady(processParameters);
|
||||
}
|
||||
|
||||
GenericOutcome Server::ProcessEnding() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->ProcessEnding();
|
||||
}
|
||||
|
||||
GenericOutcome Server::ActivateGameSession() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return serverState->ActivateGameSession();
|
||||
}
|
||||
|
||||
StartMatchBackfillOutcome Server::StartMatchBackfill(const Aws::GameLift::Server::Model::StartMatchBackfillRequest &request) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return StartMatchBackfillOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->StartMatchBackfill(request);
|
||||
}
|
||||
|
||||
GenericOutcome Server::StopMatchBackfill(const Aws::GameLift::Server::Model::StopMatchBackfillRequest &request) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
return serverState->StopMatchBackfill(request);
|
||||
}
|
||||
|
||||
GenericOutcome Server::UpdatePlayerSessionCreationPolicy(Aws::GameLift::Server::Model::PlayerSessionCreationPolicy newPlayerSessionPolicy) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return serverState->UpdatePlayerSessionCreationPolicy(newPlayerSessionPolicy);
|
||||
}
|
||||
|
||||
Aws::GameLift::AwsStringOutcome Server::GetGameSessionId() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return AwsStringOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return AwsStringOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return AwsStringOutcome(serverState->GetGameSessionId());
|
||||
}
|
||||
|
||||
Aws::GameLift::AwsLongOutcome Server::GetTerminationTime() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return AwsLongOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
return AwsLongOutcome(serverState->GetTerminationTime());
|
||||
}
|
||||
|
||||
GenericOutcome Server::AcceptPlayerSession(const char *playerSessionId) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return serverState->AcceptPlayerSession(playerSessionId);
|
||||
}
|
||||
|
||||
GenericOutcome Server::RemovePlayerSession(const char *playerSessionId) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GenericOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return GenericOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return serverState->RemovePlayerSession(playerSessionId);
|
||||
}
|
||||
#endif
|
||||
|
||||
DescribePlayerSessionsOutcome Server::DescribePlayerSessions(const Aws::GameLift::Server::Model::DescribePlayerSessionsRequest &describePlayerSessionsRequest) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return DescribePlayerSessionsOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
|
||||
if (!serverState->IsProcessReady()) {
|
||||
return DescribePlayerSessionsOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY));
|
||||
}
|
||||
|
||||
return serverState->DescribePlayerSessions(describePlayerSessionsRequest);
|
||||
}
|
||||
|
||||
GenericOutcome Server::Destroy() {
|
||||
Aws::GameLift::Metrics::MetricsTerminate();
|
||||
spdlog::info("Metrics terminated");
|
||||
return Internal::GameLiftCommonState::DestroyInstance();
|
||||
}
|
||||
|
||||
GetComputeCertificateOutcome Server::GetComputeCertificate() {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GetComputeCertificateOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
Internal::GameLiftServerState *serverState = static_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
if (serverState != NULL) {
|
||||
return serverState->GetComputeCertificate();
|
||||
}
|
||||
|
||||
return GetComputeCertificateOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::NOT_INITIALIZED));
|
||||
}
|
||||
|
||||
GetFleetRoleCredentialsOutcome Server::GetFleetRoleCredentials(const Aws::GameLift::Server::Model::GetFleetRoleCredentialsRequest &request) {
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
|
||||
if (!giOutcome.IsSuccess()) {
|
||||
return GetFleetRoleCredentialsOutcome(giOutcome.GetError());
|
||||
}
|
||||
|
||||
auto *serverState = dynamic_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
if (serverState != nullptr) {
|
||||
return serverState->GetFleetRoleCredentials(request);
|
||||
}
|
||||
|
||||
return GetFleetRoleCredentialsOutcome(GameLiftError(GAMELIFT_ERROR_TYPE::NOT_INITIALIZED));
|
||||
}
|
||||
|
||||
GenericOutcome Server::InitMetrics() {
|
||||
return InitMetrics(Aws::GameLift::Metrics::CreateMetricsParametersFromEnvironmentOrDefault());
|
||||
}
|
||||
|
||||
GenericOutcome Server::InitMetrics(const Aws::GameLift::Server::MetricsParameters &metricsParameters) {
|
||||
// Validate parameters
|
||||
GenericOutcome validationOutcome = Aws::GameLift::Metrics::ValidateMetricsParameters(metricsParameters);
|
||||
if (!validationOutcome.IsSuccess()) {
|
||||
return validationOutcome;
|
||||
}
|
||||
|
||||
// Map MetricsParameters to MetricsSettings
|
||||
Aws::GameLift::Metrics::MetricsSettings settings = Aws::GameLift::Metrics::FromMetricsParameters(metricsParameters);
|
||||
Aws::GameLift::Metrics::MetricsInitialize(settings);
|
||||
|
||||
// Now that metrics are initialized, set the global processor in the server state
|
||||
Internal::GetInstanceOutcome giOutcome = Internal::GameLiftCommonState::GetInstance(Internal::GAMELIFT_INTERNAL_STATE_TYPE::SERVER);
|
||||
if (giOutcome.IsSuccess()) {
|
||||
auto *serverState = dynamic_cast<Internal::GameLiftServerState *>(giOutcome.GetResult());
|
||||
if (serverState != nullptr) {
|
||||
Aws::GameLift::Metrics::IMetricsProcessor* globalProcessor = GameLiftMetricsGlobalProcessor();
|
||||
if (globalProcessor != nullptr) {
|
||||
serverState->SetGlobalProcessor(globalProcessor);
|
||||
}
|
||||
// Check if there's an active game session
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
std::string gameSessionId = serverState->GetGameSessionId();
|
||||
if (!gameSessionId.empty()) {
|
||||
Aws::GameLift::Server::Model::GameSession gameSession;
|
||||
gameSession.SetGameSessionId(gameSessionId);
|
||||
Aws::GameLift::Metrics::OnGameSessionStarted(gameSession);
|
||||
}
|
||||
#else
|
||||
const char* gameSessionId = serverState->GetGameSessionId();
|
||||
if (gameSessionId != nullptr && gameSessionId[0] != '\0') {
|
||||
Aws::GameLift::Server::Model::GameSession gameSession;
|
||||
gameSession.SetGameSessionId(gameSessionId);
|
||||
Aws::GameLift::Metrics::OnGameSessionStarted(gameSession);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return GenericOutcome(nullptr);
|
||||
}
|
||||
@@ -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/server/LogParameters.h>
|
||||
|
||||
#ifndef GAMELIFT_USE_STD
|
||||
#include "string.h"
|
||||
#endif
|
||||
|
||||
#ifndef GAMELIFT_USE_STD
|
||||
Aws::GameLift::Server::LogParameters::LogParameters(const char *const *logPaths, int count) {
|
||||
m_count = (count < MAX_LOG_PATHS) ? count : MAX_LOG_PATHS;
|
||||
for (int i = 0; i < m_count; ++i) {
|
||||
|
||||
#ifdef WIN32
|
||||
strcpy_s(m_logPaths[i], MAX_PATH_LENGTH, logPaths[i]);
|
||||
#else
|
||||
strncpy(m_logPaths[i], logPaths[i], MAX_PATH_LENGTH);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
Aws::GameLift::Server::LogParameters::LogParameters(const LogParameters &o) {
|
||||
int count = o.getLogPathCount();
|
||||
m_count = (count < MAX_LOG_PATHS) ? count : MAX_LOG_PATHS;
|
||||
for (int i = 0; i < m_count; ++i) {
|
||||
#ifdef WIN32
|
||||
strcpy_s(m_logPaths[i], MAX_PATH_LENGTH, o.getLogPath(i));
|
||||
#else
|
||||
strncpy(m_logPaths[i], o.getLogPath(i), MAX_PATH_LENGTH);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 "Modules/ModuleManager.h"
|
||||
#include "Delegates/DelegateCombinations.h"
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/AllowWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
#include "aws/gamelift/common/Outcome.h"
|
||||
#include "aws/gamelift/server/GameLiftServerAPI.h"
|
||||
#include "GameLiftServerSDKModels.h"
|
||||
#include <map>
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#include "Windows/HideWindowsPlatformTypes.h"
|
||||
#endif
|
||||
|
||||
DECLARE_DELEGATE_OneParam(FOnStartGameSession, Aws::GameLift::Server::Model::GameSession);
|
||||
DECLARE_DELEGATE_OneParam(FOnUpdateGameSession, Aws::GameLift::Server::Model::UpdateGameSession);
|
||||
DECLARE_DELEGATE_RetVal(bool, FOnHealthCheck);
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FProcessParameters {
|
||||
FOnStartGameSession OnStartGameSession;
|
||||
FOnUpdateGameSession OnUpdateGameSession;
|
||||
FOnHealthCheck OnHealthCheck;
|
||||
FSimpleDelegate OnTerminate;
|
||||
int port = -1;
|
||||
TArray<FString> logParameters;
|
||||
|
||||
void OnTerminateFunction() {
|
||||
this->OnTerminate.ExecuteIfBound();
|
||||
}
|
||||
|
||||
bool OnHealthCheckFunction() {
|
||||
if (this->OnHealthCheck.IsBound()){
|
||||
return this->OnHealthCheck.Execute();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void OnActivateFunction(Aws::GameLift::Server::Model::GameSession gameSession) {
|
||||
this->OnStartGameSession.ExecuteIfBound(gameSession);
|
||||
}
|
||||
|
||||
void OnUpdateFunction(Aws::GameLift::Server::Model::UpdateGameSession updateGameSession) {
|
||||
this->OnUpdateGameSession.ExecuteIfBound(updateGameSession);
|
||||
}
|
||||
};
|
||||
|
||||
enum class FAttributeType : uint8
|
||||
{
|
||||
NONE,
|
||||
STRING,
|
||||
DOUBLE,
|
||||
STRING_LIST,
|
||||
STRING_DOUBLE_MAP
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FAttributeValue {
|
||||
FString m_S;
|
||||
double m_N;
|
||||
TArray<FString> m_SL;
|
||||
TMap<FString, double> m_SDM;
|
||||
FAttributeType m_type;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FPlayer {
|
||||
FString m_playerId;
|
||||
FString m_team;
|
||||
TMap<FString, FAttributeValue> m_playerAttributes;
|
||||
TMap<FString, int32> m_latencyInMs;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FStartMatchBackfillRequest {
|
||||
FString m_ticketId;
|
||||
FString m_gameSessionArn;
|
||||
FString m_matchmakingConfigurationArn;
|
||||
TArray<FPlayer> m_players;
|
||||
|
||||
FStartMatchBackfillRequest(const FString& ticketId, const FString& gameSessionArn, const FString& matchmakingConfigurationArn, const TArray<FPlayer>& players) :
|
||||
m_ticketId(ticketId),
|
||||
m_gameSessionArn(gameSessionArn),
|
||||
m_matchmakingConfigurationArn(matchmakingConfigurationArn),
|
||||
m_players(players)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FStopMatchBackfillRequest {
|
||||
FString m_ticketId;
|
||||
FString m_gameSessionArn;
|
||||
FString m_matchmakingConfigurationArn;
|
||||
|
||||
FStopMatchBackfillRequest(const FString& ticketId, const FString& gameSessionArn, const FString& matchmakingConfigurationArn) :
|
||||
m_ticketId(ticketId),
|
||||
m_gameSessionArn(gameSessionArn),
|
||||
m_matchmakingConfigurationArn(matchmakingConfigurationArn)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class GAMELIFTSERVERSDK_API FGameLiftServerSDKModule : public IModuleInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/** IModuleInterface implementation */
|
||||
virtual void StartupModule() override;
|
||||
virtual void ShutdownModule() override;
|
||||
|
||||
virtual FGameLiftStringOutcome GetSdkVersion();
|
||||
|
||||
// Needs the standalone server to be running locally. If not, this will block at load time.
|
||||
virtual FGameLiftGenericOutcome InitSDK();
|
||||
virtual FGameLiftGenericOutcome InitSDK(const FServerParameters &serverParameters);
|
||||
|
||||
virtual FGameLiftGenericOutcome InitMetrics();
|
||||
virtual FGameLiftGenericOutcome InitMetrics(const FMetricsParameters &metricsParameters);
|
||||
|
||||
//virtual TGameLiftGenericOutcome ProcessReady(Aws::GameLift::Server::ProcessParameters &processParameters);
|
||||
virtual FGameLiftGenericOutcome ProcessReady(FProcessParameters &processParameters);
|
||||
|
||||
virtual FGameLiftGenericOutcome ProcessEnding();
|
||||
virtual FGameLiftGenericOutcome ActivateGameSession();
|
||||
virtual FGameLiftGenericOutcome AcceptPlayerSession(const FString& playerSessionId);
|
||||
virtual FGameLiftGenericOutcome RemovePlayerSession(const FString& playerSessionId);
|
||||
virtual FGameLiftGenericOutcome Destroy();
|
||||
virtual FGameLiftDescribePlayerSessionsOutcome DescribePlayerSessions(const FGameLiftDescribePlayerSessionsRequest& describePlayerSessionsRequest);
|
||||
|
||||
virtual FGameLiftGenericOutcome UpdatePlayerSessionCreationPolicy(EPlayerSessionCreationPolicy policy);
|
||||
virtual FGameLiftStringOutcome GetGameSessionId();
|
||||
virtual FGameLiftLongOutcome GetTerminationTime();
|
||||
|
||||
virtual FGameLiftStringOutcome StartMatchBackfill(const FStartMatchBackfillRequest& request);
|
||||
virtual FGameLiftGenericOutcome StopMatchBackfill(const FStopMatchBackfillRequest& request);
|
||||
|
||||
virtual FGameLiftGetComputeCertificateOutcome GetComputeCertificate();
|
||||
virtual FGameLiftGetFleetRoleCredentialsOutcome GetFleetRoleCredentials(const FGameLiftGetFleetRoleCredentialsRequest& request);
|
||||
|
||||
private:
|
||||
/** Handle to the dll we will load */
|
||||
static void* GameLiftServerSDKLibraryHandle;
|
||||
static bool LoadDependency(const FString& Dir, const FString& Name, void*& Handle);
|
||||
static void FreeDependency(void*& Handle);
|
||||
};
|
||||
@@ -0,0 +1,280 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
enum class GAMELIFTSERVERSDK_API EPlayerSessionCreationPolicy
|
||||
{
|
||||
NOT_SET,
|
||||
ACCEPT_ALL,
|
||||
DENY_ALL
|
||||
};
|
||||
|
||||
inline GAMELIFTSERVERSDK_API EPlayerSessionCreationPolicy GetPlayerSessionCreationPolicyForName(FString& name)
|
||||
{
|
||||
if (name == "ACCEPT_ALL") {
|
||||
return EPlayerSessionCreationPolicy::ACCEPT_ALL;
|
||||
}
|
||||
if (name == "DENY_ALL") {
|
||||
return EPlayerSessionCreationPolicy::DENY_ALL;
|
||||
}
|
||||
return EPlayerSessionCreationPolicy::NOT_SET;
|
||||
}
|
||||
|
||||
inline GAMELIFTSERVERSDK_API FString GetNameForPlayerSessionCreationPolicy(EPlayerSessionCreationPolicy value)
|
||||
{
|
||||
switch (value) {
|
||||
case EPlayerSessionCreationPolicy::ACCEPT_ALL:
|
||||
return FString("ACCEPT_ALL");
|
||||
case EPlayerSessionCreationPolicy::DENY_ALL:
|
||||
return FString("DENY_ALL");
|
||||
default:
|
||||
return FString("NOT_SET");
|
||||
}
|
||||
}
|
||||
|
||||
enum class GAMELIFTSERVERSDK_API EPlayerSessionStatus
|
||||
{
|
||||
NOT_SET,
|
||||
RESERVED,
|
||||
ACTIVE,
|
||||
COMPLETED,
|
||||
TIMEDOUT
|
||||
};
|
||||
|
||||
inline GAMELIFTSERVERSDK_API EPlayerSessionStatus GetPlayerSessionStatusForName(FString& name)
|
||||
{
|
||||
if (name == "RESERVED") {
|
||||
return EPlayerSessionStatus::RESERVED;
|
||||
}
|
||||
if (name == "ACTIVE") {
|
||||
return EPlayerSessionStatus::ACTIVE;
|
||||
}
|
||||
if (name == "COMPLETED") {
|
||||
return EPlayerSessionStatus::COMPLETED;
|
||||
}
|
||||
if (name == "TIMEDOUT") {
|
||||
return EPlayerSessionStatus::TIMEDOUT;
|
||||
}
|
||||
return EPlayerSessionStatus::NOT_SET;
|
||||
}
|
||||
|
||||
inline GAMELIFTSERVERSDK_API FString GetNameForPlayerSessionStatus(EPlayerSessionStatus value)
|
||||
{
|
||||
switch (value) {
|
||||
case EPlayerSessionStatus::RESERVED:
|
||||
return FString("RESERVED");
|
||||
case EPlayerSessionStatus::ACTIVE:
|
||||
return FString("ACTIVE");
|
||||
case EPlayerSessionStatus::COMPLETED:
|
||||
return FString("COMPLETED");
|
||||
case EPlayerSessionStatus::TIMEDOUT:
|
||||
return FString("TIMEDOUT");
|
||||
default:
|
||||
return FString("NOT_SET");
|
||||
}
|
||||
}
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FServerParameters
|
||||
{
|
||||
FString m_webSocketUrl;
|
||||
FString m_fleetId;
|
||||
FString m_processId;
|
||||
FString m_hostId;
|
||||
FString m_authToken;
|
||||
FString m_awsRegion;
|
||||
FString m_accessKey;
|
||||
FString m_secretKey;
|
||||
FString m_sessionToken;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FMetricsParameters
|
||||
{
|
||||
FString m_statsDHost;
|
||||
int32 m_statsDPort = 0;
|
||||
FString m_crashReporterHost;
|
||||
int32 m_crashReporterPort = 0;
|
||||
int32 m_flushIntervalMs = 0;
|
||||
int32 m_maxPacketSize = 0;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftPlayerSession
|
||||
{
|
||||
FString m_playerSessionId;
|
||||
FString m_playerId;
|
||||
FString m_gameSessionId;
|
||||
FString m_fleetId;
|
||||
long m_creationTime = 0;
|
||||
long m_terminationTime = 0;
|
||||
EPlayerSessionStatus m_status = EPlayerSessionStatus::NOT_SET;
|
||||
FString m_ipAddress;
|
||||
int m_port = 0;
|
||||
FString m_playerData;
|
||||
FString m_dnsName;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftDescribePlayerSessionsResult
|
||||
{
|
||||
TArray<FGameLiftPlayerSession> m_playerSessions;
|
||||
FString m_nextToken;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftDescribePlayerSessionsRequest
|
||||
{
|
||||
FString m_gameSessionId;
|
||||
FString m_playerId;
|
||||
FString m_playerSessionId;
|
||||
FString m_playerSessionStatusFilter;
|
||||
int m_limit = 0;
|
||||
FString m_nextToken;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftGetComputeCertificateResult
|
||||
{
|
||||
FString m_certificate_path;
|
||||
FString m_computeName;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftGetFleetRoleCredentialsResult
|
||||
{
|
||||
FString m_assumedUserRoleArn;
|
||||
FString m_assumedRoleId;
|
||||
FString m_accessKeyId;
|
||||
FString m_secretAccessKey;
|
||||
FString m_sessionToken;
|
||||
FDateTime m_expiration;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftGetFleetRoleCredentialsRequest
|
||||
{
|
||||
FString m_roleArn;
|
||||
FString m_roleSessionName;
|
||||
};
|
||||
|
||||
struct GAMELIFTSERVERSDK_API FGameLiftError {
|
||||
Aws::GameLift::GAMELIFT_ERROR_TYPE m_errorType;
|
||||
FString m_errorName;
|
||||
FString m_errorMessage;
|
||||
|
||||
FGameLiftError(){}
|
||||
FGameLiftError(Aws::GameLift::GAMELIFT_ERROR_TYPE type, FString name, FString message) :
|
||||
m_errorType(type),
|
||||
m_errorName(name),
|
||||
m_errorMessage(message)
|
||||
{}
|
||||
|
||||
FGameLiftError(Aws::GameLift::GameLiftError error)
|
||||
{
|
||||
m_errorMessage = FString(error.GetErrorMessage());
|
||||
m_errorName = FString(error.GetErrorName());
|
||||
m_errorType = error.GetErrorType();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename R, typename E>
|
||||
class GAMELIFTSERVERSDK_API TGameLiftOutcome
|
||||
{
|
||||
public:
|
||||
|
||||
TGameLiftOutcome() : success(false)
|
||||
{
|
||||
} // Default constructor
|
||||
TGameLiftOutcome(const R& r) : result(r), success(true)
|
||||
{
|
||||
} // Result copy constructor
|
||||
TGameLiftOutcome(const E& e) : error(e), success(false)
|
||||
{
|
||||
} // Error copy constructor
|
||||
TGameLiftOutcome(R&& r) : result(std::forward<R>(r)), success(true)
|
||||
{
|
||||
} // Result move constructor
|
||||
TGameLiftOutcome(E&& e) : error(std::forward<E>(e)), success(false)
|
||||
{
|
||||
} // Error move constructor
|
||||
TGameLiftOutcome(const TGameLiftOutcome& o) :
|
||||
result(o.result),
|
||||
error(o.error),
|
||||
success(o.success)
|
||||
{
|
||||
}
|
||||
|
||||
TGameLiftOutcome& operator=(const TGameLiftOutcome& o)
|
||||
{
|
||||
if (this != &o)
|
||||
{
|
||||
result = o.result;
|
||||
error = o.error;
|
||||
success = o.success;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TGameLiftOutcome(TGameLiftOutcome&& o) : // Required to force Move Constructor
|
||||
result(std::move(o.result)),
|
||||
error(std::move(o.error)),
|
||||
success(o.success)
|
||||
{
|
||||
}
|
||||
|
||||
TGameLiftOutcome& operator=(TGameLiftOutcome&& o)
|
||||
{
|
||||
if (this != &o)
|
||||
{
|
||||
result = std::move(o.result);
|
||||
error = std::move(o.error);
|
||||
success = o.success;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline const R& GetResult() const
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
inline R& GetResult()
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* casts the underlying result to an r-value so that caller can't take ownership of underlying resources.
|
||||
* this is necessary when streams are involved.
|
||||
*/
|
||||
inline R&& GetResultWithOwnership()
|
||||
{
|
||||
return std::move(result);
|
||||
}
|
||||
|
||||
inline const E& GetError() const
|
||||
{
|
||||
return error;
|
||||
}
|
||||
|
||||
inline bool IsSuccess() const
|
||||
{
|
||||
return this->success;
|
||||
}
|
||||
|
||||
private:
|
||||
R result;
|
||||
E error;
|
||||
bool success;
|
||||
};
|
||||
|
||||
typedef TGameLiftOutcome<void*, FGameLiftError> FGameLiftGenericOutcome;
|
||||
typedef TGameLiftOutcome<FString, FGameLiftError> FGameLiftStringOutcome;
|
||||
typedef TGameLiftOutcome<long, FGameLiftError> FGameLiftLongOutcome;
|
||||
typedef TGameLiftOutcome<FGameLiftDescribePlayerSessionsResult, FGameLiftError> FGameLiftDescribePlayerSessionsOutcome;
|
||||
typedef TGameLiftOutcome<FGameLiftGetComputeCertificateResult, FGameLiftError> FGameLiftGetComputeCertificateOutcome;
|
||||
typedef TGameLiftOutcome<FGameLiftGetFleetRoleCredentialsResult, FGameLiftError> FGameLiftGetFleetRoleCredentialsOutcome;
|
||||
@@ -0,0 +1,363 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#if defined(_MSC_VER) && !defined(GAMELIFT_USE_STD)
|
||||
#pragma warning(push) // Save warning settings.
|
||||
#pragma warning(disable : 4996) // Disable deprecated warning for strncpy
|
||||
#endif
|
||||
|
||||
#include <aws/gamelift/common/GameLift_EXPORTS.h>
|
||||
#ifndef GAMELIFT_USE_STD
|
||||
#include "string.h"
|
||||
#endif
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
enum class AWS_GAMELIFT_API GAMELIFT_ERROR_TYPE {
|
||||
ALREADY_INITIALIZED, // The server or client has already been initialized with
|
||||
// Initialize().
|
||||
FLEET_MISMATCH, // The target fleet does not match the fleet of a gameSession or playerSession.
|
||||
GAMELIFT_CLIENT_NOT_INITIALIZED, // The client has not been initialized.
|
||||
GAMELIFT_SERVER_NOT_INITIALIZED, // The server SDK has not been initialized.
|
||||
GAME_SESSION_ENDED_FAILED, // The server SDK could not contact the service to report
|
||||
// the game session ended.
|
||||
GAME_SESSION_NOT_READY, // The game session was not activated.
|
||||
GAME_SESSION_READY_FAILED, // The server SDK could not contact the service to report
|
||||
// the game session is ready.
|
||||
GAME_SESSION_ID_NOT_SET, // No game sessions are bound to this process.
|
||||
INITIALIZATION_MISMATCH, // A client method was called after Server::Initialize(), or vice
|
||||
// versa.
|
||||
NOT_INITIALIZED, // The server or client has not been initialized with Initialize().
|
||||
NO_TARGET_ALIASID_SET, // A target aliasId has not been set.
|
||||
NO_TARGET_FLEET_SET, // A target fleet has not been set.
|
||||
PROCESS_ENDING_FAILED, // The server SDK could not contact the service to report the
|
||||
// process is ending.
|
||||
PROCESS_NOT_ACTIVE, // The server process is not yet active, not bound to a GameSession, and
|
||||
// cannot accept or process PlayerSessions.
|
||||
PROCESS_NOT_READY, // The server process is not yet ready to be activated.
|
||||
PROCESS_READY_FAILED, // The server SDK could not contact the service to report the
|
||||
// process is ready.
|
||||
SDK_VERSION_DETECTION_FAILED, // SDK version detection failed.
|
||||
SERVICE_CALL_FAILED, // A call to an AWS service has failed.
|
||||
STX_CALL_FAILED, // A call to the XStx server backend component has failed.
|
||||
STX_INITIALIZATION_FAILED, // The XStx server backend component has failed to initialize.
|
||||
UNEXPECTED_PLAYER_SESSION, // An unregistered player session was encountered by the server.
|
||||
BAD_REQUEST_EXCEPTION, // Generic error when client creates a bad request.
|
||||
UNAUTHORIZED_EXCEPTION, // Client not authorized to access a required resource due to missing or invalid auth.
|
||||
FORBIDDEN_EXCEPTION, // Client requesting to use resources/operations they aren't allow to access.
|
||||
NOT_FOUND_EXCEPTION, // Request needs a backend resource that the client failed to install.
|
||||
CONFLICT_EXCEPTION, // Client request error caused by stale data.
|
||||
TOO_MANY_REQUESTS_EXCEPTION, // Client called request too often and is being throttled.
|
||||
INTERNAL_SERVICE_EXCEPTION, // Generic error when Amazon GameLift Servers WebSocket fails to process a request.
|
||||
WEBSOCKET_CONNECT_FAILURE, // Failure to connect to the Amazon GameLift Servers WebSocket
|
||||
WEBSOCKET_CONNECT_FAILURE_FORBIDDEN, // Access denied, e.g. auth token has expired
|
||||
WEBSOCKET_CONNECT_FAILURE_INVALID_URL, // End point URL is invalid
|
||||
WEBSOCKET_CONNECT_FAILURE_TIMEOUT, // Timeout
|
||||
WEBSOCKET_RETRIABLE_SEND_MESSAGE_FAILURE, // Retriable failure to send message to the Amazon GameLift Servers
|
||||
// Service WebSocket
|
||||
WEBSOCKET_SEND_MESSAGE_FAILURE, // Failure to send message to the Amazon GameLift Servers WebSocket
|
||||
VALIDATION_EXCEPTION // Client-side error when invalid parameters are passed.
|
||||
};
|
||||
|
||||
class AWS_GAMELIFT_API GameLiftError {
|
||||
#ifdef GAMELIFT_USE_STD
|
||||
public:
|
||||
GAMELIFT_ERROR_TYPE GetErrorType() const { return m_errorType; }
|
||||
|
||||
const std::string &GetErrorName() const { return m_errorName; }
|
||||
void SetErrorName(const std::string &errorName) { m_errorName = errorName; }
|
||||
|
||||
const std::string &GetErrorMessage() const { return m_errorMessage; }
|
||||
void SetErrorMessage(const std::string &errorMessage) { m_errorMessage = errorMessage; }
|
||||
|
||||
GameLiftError() : m_errorType(){};
|
||||
|
||||
~GameLiftError(){};
|
||||
|
||||
GameLiftError(const int statusCode, const std::string &message) : GameLiftError(GetErrorTypeForStatusCode(statusCode), message){};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType)
|
||||
: m_errorType(errorType), m_errorName(Aws::GameLift::GameLiftError::GetDefaultNameForErrorType(errorType)),
|
||||
m_errorMessage(Aws::GameLift::GameLiftError::GetDefaultMessageForErrorType(errorType)){};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType, const std::string &errorName, const std::string &message)
|
||||
: m_errorType(errorType), m_errorName(errorName), m_errorMessage(message){};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType, const std::string &message)
|
||||
: m_errorType(errorType), m_errorName(Aws::GameLift::GameLiftError::GetDefaultNameForErrorType(errorType)), m_errorMessage(message){};
|
||||
|
||||
GameLiftError(const GameLiftError &rhs) : m_errorType(rhs.GetErrorType()), m_errorName(rhs.GetErrorName()), m_errorMessage(rhs.GetErrorMessage()){};
|
||||
|
||||
bool operator==(const GameLiftError other) const {
|
||||
return other.GetErrorType() == GetErrorType() && other.GetErrorName() == GetErrorName() && other.GetErrorMessage() == GetErrorMessage();
|
||||
}
|
||||
|
||||
private:
|
||||
GAMELIFT_ERROR_TYPE m_errorType;
|
||||
std::string m_errorName;
|
||||
std::string m_errorMessage;
|
||||
#else
|
||||
public:
|
||||
const GAMELIFT_ERROR_TYPE GetErrorType() const { return m_errorType; }
|
||||
|
||||
const char *GetErrorName() const { return m_errorName; }
|
||||
void SetErrorName(const char *errorName) {
|
||||
strncpy(m_errorName, errorName, sizeof(m_errorName));
|
||||
m_errorName[sizeof(m_errorName) - 1] = 0;
|
||||
}
|
||||
|
||||
const char *GetErrorMessage() const { return m_errorMessage; }
|
||||
void SetErrorMessage(const char *errorMessage) {
|
||||
strncpy(m_errorMessage, errorMessage, sizeof(m_errorMessage));
|
||||
m_errorMessage[sizeof(m_errorMessage) - 1] = 0;
|
||||
}
|
||||
|
||||
GameLiftError() {
|
||||
memset(m_errorName, 0, sizeof(m_errorName));
|
||||
memset(m_errorMessage, 0, sizeof(m_errorMessage));
|
||||
};
|
||||
|
||||
~GameLiftError(){};
|
||||
|
||||
GameLiftError(const int statusCode, const char *message) : GameLiftError(GetErrorTypeForStatusCode(statusCode), message){};
|
||||
|
||||
void Init(GAMELIFT_ERROR_TYPE errorType, const char *errorName, const char *message) {
|
||||
m_errorType = errorType;
|
||||
SetErrorName(errorName);
|
||||
SetErrorMessage(message);
|
||||
};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType) {
|
||||
Init(errorType, Aws::GameLift::GameLiftError::GetDefaultNameForErrorType(errorType).c_str(),
|
||||
Aws::GameLift::GameLiftError::GetDefaultMessageForErrorType(errorType).c_str());
|
||||
};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType, const char *errorName, const char *message) : m_errorType(errorType) {
|
||||
this->SetErrorName(errorName);
|
||||
this->SetErrorMessage(message);
|
||||
};
|
||||
|
||||
GameLiftError(GAMELIFT_ERROR_TYPE errorType, const char *message) {
|
||||
Init(errorType, Aws::GameLift::GameLiftError::GetDefaultNameForErrorType(errorType).c_str(), message);
|
||||
};
|
||||
|
||||
GameLiftError(const GameLiftError &rhs) { Init(rhs.GetErrorType(), rhs.GetErrorName(), rhs.GetErrorMessage()); };
|
||||
|
||||
bool operator==(const GameLiftError other) const {
|
||||
return other.GetErrorType() == GetErrorType() && strcmp(other.GetErrorName(), GetErrorName()) == 0 &&
|
||||
strcmp(other.GetErrorMessage(), GetErrorMessage()) == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
GAMELIFT_ERROR_TYPE m_errorType;
|
||||
char m_errorName[256];
|
||||
char m_errorMessage[1024];
|
||||
#endif
|
||||
static GAMELIFT_ERROR_TYPE GetErrorTypeForStatusCode(const int statusCode) {
|
||||
if (statusCode >= 400 && statusCode < 500) {
|
||||
// Catch valid 4xx (client errors) status codes returned by websocket lambda
|
||||
// All other 4xx codes fallback to "bad request exception"
|
||||
switch(statusCode) {
|
||||
case 400:
|
||||
return GAMELIFT_ERROR_TYPE::BAD_REQUEST_EXCEPTION;
|
||||
case 401:
|
||||
return GAMELIFT_ERROR_TYPE::UNAUTHORIZED_EXCEPTION;
|
||||
case 403:
|
||||
return GAMELIFT_ERROR_TYPE::FORBIDDEN_EXCEPTION;
|
||||
case 404:
|
||||
return GAMELIFT_ERROR_TYPE::NOT_FOUND_EXCEPTION;
|
||||
case 409:
|
||||
return GAMELIFT_ERROR_TYPE::CONFLICT_EXCEPTION;
|
||||
case 429:
|
||||
return GAMELIFT_ERROR_TYPE::TOO_MANY_REQUESTS_EXCEPTION;
|
||||
}
|
||||
|
||||
return GAMELIFT_ERROR_TYPE::BAD_REQUEST_EXCEPTION;
|
||||
} else {
|
||||
// The websocket can return other error types, in this case classify it as an internal
|
||||
// service exception
|
||||
return GAMELIFT_ERROR_TYPE::INTERNAL_SERVICE_EXCEPTION;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetDefaultNameForErrorType(GAMELIFT_ERROR_TYPE errorType) {
|
||||
switch (errorType) {
|
||||
case GAMELIFT_ERROR_TYPE::ALREADY_INITIALIZED:
|
||||
return "Already Initialized";
|
||||
case GAMELIFT_ERROR_TYPE::FLEET_MISMATCH:
|
||||
return "Fleet mismatch.";
|
||||
case GAMELIFT_ERROR_TYPE::GAMELIFT_CLIENT_NOT_INITIALIZED:
|
||||
return "Amazon GameLift Servers client not initialized.";
|
||||
case GAMELIFT_ERROR_TYPE::GAMELIFT_SERVER_NOT_INITIALIZED:
|
||||
return "Server SDK not initialized.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_ENDED_FAILED:
|
||||
return "Game session failed.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_NOT_READY:
|
||||
return "Game session not activated.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_READY_FAILED:
|
||||
return "Game session failed.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_ID_NOT_SET:
|
||||
return "GameSession id is not set.";
|
||||
case GAMELIFT_ERROR_TYPE::INITIALIZATION_MISMATCH:
|
||||
return "Initialization mismatch.";
|
||||
case GAMELIFT_ERROR_TYPE::NOT_INITIALIZED:
|
||||
return "Not Initialized";
|
||||
case GAMELIFT_ERROR_TYPE::NO_TARGET_ALIASID_SET:
|
||||
return "No target aliasId set.";
|
||||
case GAMELIFT_ERROR_TYPE::NO_TARGET_FLEET_SET:
|
||||
return "No target fleet set.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_ENDING_FAILED:
|
||||
return "Process ending failed.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_NOT_ACTIVE:
|
||||
return "Process not activated.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY:
|
||||
return "Process not ready.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_READY_FAILED:
|
||||
return "Process ready failed.";
|
||||
case GAMELIFT_ERROR_TYPE::SDK_VERSION_DETECTION_FAILED:
|
||||
return "Could not detect SDK version.";
|
||||
case GAMELIFT_ERROR_TYPE::SERVICE_CALL_FAILED:
|
||||
return "Service call failed.";
|
||||
case GAMELIFT_ERROR_TYPE::STX_CALL_FAILED:
|
||||
return "STX call failed.";
|
||||
case GAMELIFT_ERROR_TYPE::STX_INITIALIZATION_FAILED:
|
||||
return "STX Initialization Failed.";
|
||||
case GAMELIFT_ERROR_TYPE::UNEXPECTED_PLAYER_SESSION:
|
||||
return "Unexpected player session.";
|
||||
case GAMELIFT_ERROR_TYPE::BAD_REQUEST_EXCEPTION:
|
||||
return "Bad request exception.";
|
||||
case GAMELIFT_ERROR_TYPE::UNAUTHORIZED_EXCEPTION:
|
||||
return "Unauthorized exception.";
|
||||
case GAMELIFT_ERROR_TYPE::FORBIDDEN_EXCEPTION:
|
||||
return "Forbidden exception.";
|
||||
case GAMELIFT_ERROR_TYPE::NOT_FOUND_EXCEPTION:
|
||||
return "Not found exception.";
|
||||
case GAMELIFT_ERROR_TYPE::CONFLICT_EXCEPTION:
|
||||
return "Conflict exception.";
|
||||
case GAMELIFT_ERROR_TYPE::TOO_MANY_REQUESTS_EXCEPTION:
|
||||
return "Throttling exception.";
|
||||
case GAMELIFT_ERROR_TYPE::INTERNAL_SERVICE_EXCEPTION:
|
||||
return "Internal service exception.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE:
|
||||
return "WebSocket Connection Failed.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_FORBIDDEN:
|
||||
return "WebSocket Connection Denied.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_INVALID_URL:
|
||||
return "WebSocket Connection has invalid URL.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_TIMEOUT:
|
||||
return "WebSocket Connection has timed out.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_SEND_MESSAGE_FAILURE:
|
||||
return "WebSocket Send Message Failed.";
|
||||
case GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION:
|
||||
return "Validation exception.";
|
||||
default:
|
||||
return "Unknown Error";
|
||||
}
|
||||
}
|
||||
|
||||
static std::string GetDefaultMessageForErrorType(GAMELIFT_ERROR_TYPE errorType) {
|
||||
switch (errorType) {
|
||||
case GAMELIFT_ERROR_TYPE::ALREADY_INITIALIZED:
|
||||
return "Server SDK has already been initialized. You must call Destroy() before "
|
||||
"reinitializing the client or server.";
|
||||
case GAMELIFT_ERROR_TYPE::FLEET_MISMATCH:
|
||||
return "The Target fleet does not match the request fleet. Make sure GameSessions and "
|
||||
"PlayerSessions belong to your target fleet.";
|
||||
case GAMELIFT_ERROR_TYPE::GAMELIFT_CLIENT_NOT_INITIALIZED:
|
||||
return "The Amazon GameLift Servers client has not been initialized. Please call SetTargetFleet or "
|
||||
"SetTArgetAliasId.";
|
||||
case GAMELIFT_ERROR_TYPE::GAMELIFT_SERVER_NOT_INITIALIZED:
|
||||
return "The server SDK has not been initialized. Please call InitSDK.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_ENDED_FAILED:
|
||||
return "The GameSessionEnded invocation failed.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_NOT_READY:
|
||||
return "The Game session associated with this server was not activated.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_READY_FAILED:
|
||||
return "The GameSessionReady invocation failed.";
|
||||
case GAMELIFT_ERROR_TYPE::GAME_SESSION_ID_NOT_SET:
|
||||
return "No game sessions are bound to this process.";
|
||||
case GAMELIFT_ERROR_TYPE::INITIALIZATION_MISMATCH:
|
||||
return "The current call does not match the initialization state. Client calls require "
|
||||
"a call to Client::Initialize(), and Server calls require Server::Initialize(). "
|
||||
"Only one may be active at a time.";
|
||||
case GAMELIFT_ERROR_TYPE::NOT_INITIALIZED:
|
||||
return "Server SDK has not been initialized! You must call Client::Initialize() or "
|
||||
"Server::InitSDK() before making Amazon GameLift Servers calls.";
|
||||
case GAMELIFT_ERROR_TYPE::NO_TARGET_ALIASID_SET:
|
||||
return "The aliasId has not been set. Clients should call SetTargetAliasId() before "
|
||||
"making calls that require an alias.";
|
||||
case GAMELIFT_ERROR_TYPE::NO_TARGET_FLEET_SET:
|
||||
return "The target fleet has not been set. Clients should call SetTargetFleet() before "
|
||||
"making calls that require a fleet.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_ENDING_FAILED:
|
||||
return "ProcessEnding call to Amazon GameLift Servers failed.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_NOT_ACTIVE:
|
||||
return "The process has not yet been activated.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_NOT_READY:
|
||||
return "The process has not yet been activated by calling ProcessReady(). Processes in "
|
||||
"standby cannot receive StartGameSession callbacks.";
|
||||
case GAMELIFT_ERROR_TYPE::PROCESS_READY_FAILED:
|
||||
return "ProcessReady call to Amazon GameLift Servers failed.";
|
||||
case GAMELIFT_ERROR_TYPE::SDK_VERSION_DETECTION_FAILED:
|
||||
return "Could not detect SDK version.";
|
||||
case GAMELIFT_ERROR_TYPE::SERVICE_CALL_FAILED:
|
||||
return "An AWS service call has failed. See the root cause error for more information.";
|
||||
case GAMELIFT_ERROR_TYPE::STX_CALL_FAILED:
|
||||
return "An internal call to the STX server backend component has failed.";
|
||||
case GAMELIFT_ERROR_TYPE::STX_INITIALIZATION_FAILED:
|
||||
return "The STX server backend component has failed to initialize.";
|
||||
case GAMELIFT_ERROR_TYPE::UNEXPECTED_PLAYER_SESSION:
|
||||
return "The player session was not expected by the server. Clients wishing to connect "
|
||||
"to a server must obtain a PlayerSessionID from Amazon GameLift Servers by creating a player "
|
||||
"session on the desired server's game instance.";
|
||||
case GAMELIFT_ERROR_TYPE::BAD_REQUEST_EXCEPTION:
|
||||
return "Bad request exception.";
|
||||
case GAMELIFT_ERROR_TYPE::UNAUTHORIZED_EXCEPTION:
|
||||
return "User provided invalid or missing authorization to access a resource/operation.";
|
||||
case GAMELIFT_ERROR_TYPE::FORBIDDEN_EXCEPTION:
|
||||
return "User is attempting to access resources/operations that they are not allowed to access.";
|
||||
case GAMELIFT_ERROR_TYPE::NOT_FOUND_EXCEPTION:
|
||||
return "A necessary resource was missing when attempting to process the request.";
|
||||
case GAMELIFT_ERROR_TYPE::CONFLICT_EXCEPTION:
|
||||
return "Request conflicts with the current state of the target resource.";
|
||||
case GAMELIFT_ERROR_TYPE::TOO_MANY_REQUESTS_EXCEPTION:
|
||||
return "Too many requests; please increase throttle limit if needed.";
|
||||
case GAMELIFT_ERROR_TYPE::INTERNAL_SERVICE_EXCEPTION:
|
||||
return "Internal service exception.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE:
|
||||
return "Connection to the Amazon GameLift Servers WebSocket has failed";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_FORBIDDEN:
|
||||
return "Handshake with Amazon GameLift Servers WebSocket failed. Please verify that values of ServerParameters "
|
||||
"in InitSDK() are correct. For example, process ID needs to be unique between executions, and "
|
||||
"the authentication token needs to be correct and unexpired.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_INVALID_URL:
|
||||
return "Connection to Amazon GameLift Servers WebSocket failed due to invalid websocket URL. Please verify that "
|
||||
"websocketUrl in InitSDK() is correct and matches the GameLiftServiceSdkEndpoint output from "
|
||||
"AWS::GameLift::RegisterCompute().";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_CONNECT_FAILURE_TIMEOUT:
|
||||
return "Connection to the Amazon GameLift Servers WebSocket Connection has timed out.";
|
||||
case GAMELIFT_ERROR_TYPE::WEBSOCKET_SEND_MESSAGE_FAILURE:
|
||||
return "Sending Message to the Amazon GameLift Servers WebSocket has failed.";
|
||||
case GAMELIFT_ERROR_TYPE::VALIDATION_EXCEPTION:
|
||||
return "The input is invalid.";
|
||||
default:
|
||||
return "An unexpected error has occurred.";
|
||||
}
|
||||
}
|
||||
};
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
|
||||
#if defined(_MSC_VER) && !defined(GAMELIFT_USE_STD)
|
||||
#pragma warning(pop) // Restore warnings to previous state.
|
||||
#endif
|
||||
@@ -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 <string>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Common {
|
||||
|
||||
class GameLiftToolDetector {
|
||||
public:
|
||||
virtual ~GameLiftToolDetector() = default;
|
||||
virtual bool IsToolRunning() = 0;
|
||||
virtual std::string GetToolName() = 0;
|
||||
virtual std::string GetToolVersion() = 0;
|
||||
void SetGameLiftTool();
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4101)
|
||||
#elif defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdelete-non-abstract-non-virtual-dtor"
|
||||
#endif
|
||||
#include <string>
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
// disable windows complaining about max template size.
|
||||
#pragma warning(disable : 4503)
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable : 4251)
|
||||
#ifdef USE_IMPORT_EXPORT
|
||||
#ifdef AWS_GAMELIFT_EXPORTS
|
||||
#define AWS_GAMELIFT_API __declspec(dllexport)
|
||||
#else
|
||||
#define AWS_GAMELIFT_API __declspec(dllimport)
|
||||
#endif /* AWS_GAMELIFT_EXPORTS */
|
||||
#else
|
||||
#define AWS_GAMELIFT_API
|
||||
#endif //
|
||||
#else /* defined (_WIN32) */
|
||||
#define AWS_GAMELIFT_API
|
||||
#endif
|
||||
@@ -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.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <aws/gamelift/common/GameLiftToolDetector.h>
|
||||
#include <functional>
|
||||
|
||||
namespace Aws {
|
||||
namespace GameLift {
|
||||
namespace Common {
|
||||
|
||||
class MetricsDetector : public GameLiftToolDetector {
|
||||
public:
|
||||
bool IsToolRunning() override;
|
||||
std::string GetToolName() override;
|
||||
std::string GetToolVersion() override;
|
||||
|
||||
private:
|
||||
static constexpr const char* TOOL_NAME = "Metrics";
|
||||
static constexpr const char* TOOL_VERSION = "1.0.0";
|
||||
static constexpr const char* WINDOWS_SERVICE_COMMAND = "sc";
|
||||
static constexpr const char* WINDOWS_SERVICE_NAME = "GLOTelCollector";
|
||||
static constexpr const char* WINDOWS_SERVICE_ARGS = "query ";
|
||||
static constexpr const char* WINDOWS_RUNNING_STATUS = "RUNNING";
|
||||
static constexpr const char* LINUX_SERVICE_COMMAND = "systemctl";
|
||||
static constexpr const char* LINUX_SERVICE_NAME = "gl-otel-collector.service";
|
||||
static constexpr const char* LINUX_SERVICE_ARGS = "is-active ";
|
||||
static constexpr const char* LINUX_ACTIVE_STATUS = "active";
|
||||
|
||||
bool CheckService(const std::string& command, const std::string& arguments, std::function<bool(const std::string&)> outputValidator);
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
} // namespace GameLift
|
||||
} // namespace Aws
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user