// Copyright Epic Games, Inc. All Rights Reserved. #include "Proxies/TargetDeviceProxyManager.h" #include "HAL/PlatformProcess.h" #include "MessageEndpoint.h" #include "MessageEndpointBuilder.h" #include "Proxies/TargetDeviceProxy.h" #include "TargetDeviceServiceMessages.h" /** Defines the interval in seconds in which devices are being pinged by the proxy manager. */ #define TARGET_DEVICE_SERVICES_PING_INTERVAL 2.5f LLM_DEFINE_TAG(TargetDeviceProxyManager); /* FTargetDeviceProxyManager structors *****************************************************************************/ FTargetDeviceProxyManager::FTargetDeviceProxyManager() { MessageEndpoint = FMessageEndpoint::Builder("FTargetDeviceProxyManager") .Handling(this, &FTargetDeviceProxyManager::HandlePongMessage); if (MessageEndpoint.IsValid()) { TickDelegate = FTickerDelegate::CreateRaw(this, &FTargetDeviceProxyManager::HandleTicker); TickDelegateHandle = FTSTicker::GetCoreTicker().AddTicker(TickDelegate, TARGET_DEVICE_SERVICES_PING_INTERVAL); SendPing(); } } FTargetDeviceProxyManager::~FTargetDeviceProxyManager() { FTSTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle); FMessageEndpoint::SafeRelease(MessageEndpoint); } /* ITargetDeviceProxyLocator interface *****************************************************************************/ TSharedPtr FTargetDeviceProxyManager::FindProxy(const FString& Name) { return Proxies.FindRef(Name); } TSharedRef FTargetDeviceProxyManager::FindOrAddProxy(const FString& Name) { TSharedPtr& Proxy = Proxies.FindOrAdd(Name); if (!Proxy.IsValid()) { Proxy = MakeShareable(new FTargetDeviceProxy(Name)); ProxyAddedDelegate.Broadcast(Proxy.ToSharedRef()); } return Proxy.ToSharedRef(); } TSharedPtr FTargetDeviceProxyManager::FindProxyDeviceForTargetDevice(const FString& DeviceId) { for (TMap >::TConstIterator ItProxies(Proxies); ItProxies; ++ItProxies) { const TSharedPtr& Proxy = ItProxies.Value(); if (Proxy->HasDeviceId(DeviceId)) { return Proxy; } } return TSharedPtr(); } void FTargetDeviceProxyManager::GetProxies(FName TargetPlatformName, bool IncludeUnshared, TArray>& OutProxies) { GetProxyList(TargetPlatformName, IncludeUnshared, false, OutProxies); } // the proxy list include aggregate (All__devices_on_) proxies void FTargetDeviceProxyManager::GetAllProxies(FName TargetPlatformName, TArray>& OutProxies) { GetProxyList(TargetPlatformName, false, true, OutProxies); } /** Gets a filtered list of proxies created by the device discovery routine */ void FTargetDeviceProxyManager::GetProxyList(FName TargetPlatformName, bool IncludeUnshared, bool bIncludeAggregate, TArray>& OutProxies) { OutProxies.Reset(); for (TMap >::TConstIterator It(Proxies); It; ++It) { const TSharedPtr& Proxy = It.Value(); if ((IncludeUnshared || Proxy->IsShared()) || (Proxy->GetHostUser() == FPlatformProcess::UserName(false))) { if (TargetPlatformName == NAME_None || Proxy->HasTargetPlatform(TargetPlatformName)) { if (bIncludeAggregate || !Proxy->IsAggregated()) { OutProxies.Add(Proxy); } } } } } /* FTargetDeviceProxyManager implementation *****************************************************************************/ void FTargetDeviceProxyManager::RemoveDeadProxies() { QUICK_SCOPE_CYCLE_COUNTER(STAT_FTargetDeviceProxyManager_RemoveDeadProxies); FDateTime CurrentTime = FDateTime::UtcNow(); for (auto ProxyIter = Proxies.CreateIterator(); ProxyIter; ++ProxyIter) { if (ProxyIter.Value()->HasTimedOut(CurrentTime)) { TSharedPtr RemovedProxy = ProxyIter.Value(); ProxyIter.RemoveCurrent(); ProxyRemovedDelegate.Broadcast(RemovedProxy.ToSharedRef()); } } } void FTargetDeviceProxyManager::SendPing() { QUICK_SCOPE_CYCLE_COUNTER(STAT_FTargetDeviceProxyManager_SendPing); if (MessageEndpoint.IsValid()) { // Add a timeout to all known devices const FDateTime Timeout = FDateTime::UtcNow() + FTimespan:: FromSeconds(3 * TARGET_DEVICE_SERVICES_PING_INTERVAL); for (const TPair>& Proxy : Proxies) { Proxy.Value->AddTimeout(Timeout); } // send to only this process, as we no longer want to send out pings to the local network and get another machine's list of devices MessageEndpoint->Publish(FMessageEndpoint::MakeMessage(FPlatformProcess::UserName(false)), EMessageScope::Process); } } /* FTargetDeviceProxyManager callbacks *****************************************************************************/ void FTargetDeviceProxyManager::HandlePongMessage(const FTargetDeviceServicePong& Message, const TSharedRef& Context) { // Another HACK: Ignore devices from other machines. See FTargetDeviceService::HandleClaimDeniedMessage() if (Message.HostName != FPlatformProcess::ComputerName()) { return; } LLM_SCOPE_BYTAG(TargetDeviceProxyManager); AddProxyFromPongMessage(Message, Context, false); if (Message.Aggregated) { // add the device to the aggregate (All__devices_on_) proxy // create the aggregate proxy if it wasn't created already by a previous messga AddProxyFromPongMessage(Message, Context, true); } } /** Add or update the proxy from the FTargetDeviceServicePong message */ void FTargetDeviceProxyManager::AddProxyFromPongMessage(const FTargetDeviceServicePong& Message, const TSharedRef& Context, bool InIsAggregated) { FString ProxyName = InIsAggregated ? Message.AllDevicesName : Message.Name; TSharedPtr& Proxy = Proxies.FindOrAdd(ProxyName); if (!Proxy.IsValid()) { Proxy = MakeShareable(new FTargetDeviceProxy(ProxyName, Message, Context, InIsAggregated)); ProxyAddedDelegate.Broadcast(Proxy.ToSharedRef()); } else { Proxy->UpdateFromMessage(Message, Context); } } bool FTargetDeviceProxyManager::HandleTicker(float DeltaTime) { LLM_SCOPE_BYTAG(TargetDeviceProxyManager); RemoveDeadProxies(); SendPing(); return true; }