2019-12-26 14:45:42 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
2019-05-10 12:24:40 -04:00
# include "HttpServerModule.h"
# include "HttpListener.h"
# include "Modules/ModuleManager.h"
2020-09-01 14:07:48 -04:00
# include "Stats/Stats.h"
2019-05-10 12:24:40 -04:00
2023-12-13 13:40:37 -05:00
class FHttpServerModuleImpl
{
public :
/** The association of port bindings and respective HTTP listeners */
TMap < uint32 , TUniquePtr < FHttpListener > > Listeners ;
/** Whether listeners can be started */
bool bHttpListenersEnabled = false ;
} ;
2019-11-27 10:24:13 -05:00
DEFINE_LOG_CATEGORY ( LogHttpServerModule ) ;
2019-05-10 12:24:40 -04:00
// FHttpServerModule
IMPLEMENT_MODULE ( FHttpServerModule , HTTPServer ) ;
FHttpServerModule * FHttpServerModule : : Singleton = nullptr ;
2023-12-13 13:40:37 -05:00
FHttpServerModule : : FHttpServerModule ( )
: Impl ( new FHttpServerModuleImpl )
{
}
FHttpServerModule : : ~ FHttpServerModule ( )
{
delete Impl ;
Impl = nullptr ;
}
2019-05-10 12:24:40 -04:00
void FHttpServerModule : : StartupModule ( )
{
Singleton = this ;
}
void FHttpServerModule : : ShutdownModule ( )
{
// stop all listeners
StopAllListeners ( ) ;
// destroy all listeners
2023-12-13 13:40:37 -05:00
Impl - > Listeners . Empty ( ) ;
2019-11-27 10:24:13 -05:00
Singleton = nullptr ;
2019-05-10 12:24:40 -04:00
}
2019-05-16 17:53:39 -04:00
void FHttpServerModule : : StartAllListeners ( )
{
2023-12-13 13:40:37 -05:00
Impl - > bHttpListenersEnabled = true ;
2019-05-16 17:53:39 -04:00
UE_LOG ( LogHttpServerModule , Log ,
TEXT ( " Starting all listeners... " ) ) ;
2023-12-13 13:40:37 -05:00
for ( const auto & Listener : Impl - > Listeners )
2019-05-16 17:53:39 -04:00
{
if ( ! Listener . Value - > IsListening ( ) )
{
Listener . Value - > StartListening ( ) ;
}
}
UE_LOG ( LogHttpServerModule , Log ,
TEXT ( " All listeners started " ) ) ;
}
2019-05-10 12:24:40 -04:00
void FHttpServerModule : : StopAllListeners ( )
{
2019-11-27 10:24:13 -05:00
UE_LOG ( LogHttpServerModule , Log ,
2019-05-16 17:53:39 -04:00
TEXT ( " Stopping all listeners... " ) ) ;
2023-12-13 13:40:37 -05:00
Impl - > bHttpListenersEnabled = false ;
2020-06-23 18:40:00 -04:00
2023-12-13 13:40:37 -05:00
for ( const auto & Listener : Impl - > Listeners )
2019-05-10 12:24:40 -04:00
{
if ( Listener . Value - > IsListening ( ) )
{
Listener . Value - > StopListening ( ) ;
}
}
2019-05-16 17:53:39 -04:00
UE_LOG ( LogHttpServerModule , Log ,
TEXT ( " All listeners stopped " ) ) ;
2019-05-10 12:24:40 -04:00
}
2019-11-27 10:24:13 -05:00
bool FHttpServerModule : : HasPendingListeners ( ) const
2019-05-10 12:24:40 -04:00
{
2023-12-13 13:40:37 -05:00
for ( const auto & Listener : Impl - > Listeners )
2019-05-10 12:24:40 -04:00
{
if ( Listener . Value - > HasPendingConnections ( ) )
{
return true ;
}
}
return false ;
}
2019-11-27 10:24:13 -05:00
bool FHttpServerModule : : IsAvailable ( )
{
return nullptr ! = Singleton ;
}
2019-05-10 12:24:40 -04:00
FHttpServerModule & FHttpServerModule : : Get ( )
{
if ( nullptr = = Singleton )
{
check ( IsInGameThread ( ) ) ;
FModuleManager : : LoadModuleChecked < FHttpServerModule > ( " HTTPServer " ) ;
}
check ( Singleton ) ;
return * Singleton ;
}
2022-06-16 19:07:59 -04:00
TSharedPtr < IHttpRouter > FHttpServerModule : : GetHttpRouter ( uint32 Port , bool bFailOnBindFailure /* = false */ )
2019-05-10 12:24:40 -04:00
{
2019-11-27 10:24:13 -05:00
check ( Singleton = = this ) ;
2019-05-10 12:24:40 -04:00
2022-06-16 19:07:59 -04:00
bool bFailedToListen = false ;
// We may already have a listener for this port
2023-12-13 13:40:37 -05:00
TUniquePtr < FHttpListener > * ExistingListener = Impl - > Listeners . Find ( Port ) ;
2019-05-10 12:24:40 -04:00
if ( ExistingListener )
{
2023-12-13 13:40:37 -05:00
if ( Impl - > bHttpListenersEnabled )
2022-06-16 19:07:59 -04:00
{
// if listeners are enabled, the existing listener for this port
// should always be listening (IsListening() will only be true
// if it fully initialized/successfully bound and actually started listening)
2022-10-27 13:16:00 -04:00
if ( ExistingListener - > Get ( ) - > IsListening ( ) )
2022-06-16 19:07:59 -04:00
{
UE_LOG ( LogHttpServerModule , Verbose , TEXT ( " [%s] found an existing, active listener for port %d " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , Port ) ;
return ExistingListener - > Get ( ) - > GetRouter ( ) ;
}
else
{
// get rid of it and create a new one for now
2022-10-27 13:16:00 -04:00
UE_LOG ( LogHttpServerModule , Error , TEXT ( " [%s] the existing listener for port %d is not listening/bound and listeners are still enabled " ) ,
ANSI_TO_TCHAR ( __FUNCTION__ ) , Port ) ;
2023-12-13 13:40:37 -05:00
Impl - > Listeners . Remove ( Port ) ;
2022-06-16 19:07:59 -04:00
}
}
else
{
UE_LOG ( LogHttpServerModule , Verbose , TEXT ( " [%s] found an existing listener for port %d but listeners are currently disabled " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , Port ) ;
return ExistingListener - > Get ( ) - > GetRouter ( ) ;
}
2019-05-10 12:24:40 -04:00
}
2019-05-16 17:53:39 -04:00
// Otherwise create a new one
2022-06-16 19:07:59 -04:00
UE_LOG ( LogHttpServerModule , VeryVerbose , TEXT ( " [%s] creating a new listener for port %d " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , Port ) ;
2019-05-16 17:53:39 -04:00
TUniquePtr < FHttpListener > NewListener = MakeUnique < FHttpListener > ( Port ) ;
2019-11-27 10:24:13 -05:00
// Try to start this listener now
2023-12-13 13:40:37 -05:00
if ( Impl - > bHttpListenersEnabled )
2019-05-10 12:24:40 -04:00
{
2022-06-16 19:07:59 -04:00
if ( ! NewListener - > StartListening ( ) )
{
UE_LOG ( LogHttpServerModule , Warning , TEXT ( " [%s] failed to start listening on port %d! (bFailOnBindFailure? %s) " ) , ANSI_TO_TCHAR ( __FUNCTION__ ) , Port , * LexToString ( bFailOnBindFailure ) ) ;
bFailedToListen = true ;
}
}
if ( bFailedToListen & & bFailOnBindFailure )
{
// if we actually failed to listen on a port for whatever reason
// (i.e. listeners are enabled and we attempted to do so) then
// let the one we created fall out of scope and try again next time
return nullptr ;
}
else
{
// the legacy behavior returns the router regardless of listener success
2023-12-13 13:40:37 -05:00
const auto & NewListenerRef = Impl - > Listeners . Add ( Port , MoveTemp ( NewListener ) ) ;
2022-06-16 19:07:59 -04:00
return NewListenerRef - > GetRouter ( ) ;
2019-05-10 12:24:40 -04:00
}
}
bool FHttpServerModule : : Tick ( float DeltaTime )
{
2020-09-01 14:07:48 -04:00
QUICK_SCOPE_CYCLE_COUNTER ( STAT_FHttpServerModule_Tick ) ;
2019-05-10 12:24:40 -04:00
check ( Singleton = = this ) ;
2023-12-13 13:40:37 -05:00
if ( Impl - > bHttpListenersEnabled )
2019-05-10 12:24:40 -04:00
{
2023-12-13 13:40:37 -05:00
for ( const auto & Listener : Impl - > Listeners )
2019-05-16 17:53:39 -04:00
{
Listener . Value - > Tick ( DeltaTime ) ;
}
2019-05-10 12:24:40 -04:00
}
return true ;
}