From 3d287d7e7b1b4d754c387fa85f4f3578f33e75a7 Mon Sep 17 00:00:00 2001 From: getnamo Date: Sun, 1 Sep 2019 14:02:15 -0700 Subject: [PATCH] add thread override option - allows per event override of threading. Should allow for lowest possible latency handling of certain time sensitive events (e.g. speech/streaming rt data) - default to native default option (game thread for components) - change namespace default option to TEXT() --- SocketIOClient.uplugin | 2 +- .../Private/SocketIOClientComponent.cpp | 16 ++++++-- .../SocketIOClient/Private/SocketIONative.cpp | 33 ++++++++++++++--- .../Public/SocketIOClientComponent.h | 37 +++++++++++-------- Source/SocketIOClient/Public/SocketIONative.h | 16 +++++++- 5 files changed, 76 insertions(+), 28 deletions(-) diff --git a/SocketIOClient.uplugin b/SocketIOClient.uplugin index fd21ca8d..b65b89e5 100644 --- a/SocketIOClient.uplugin +++ b/SocketIOClient.uplugin @@ -1,7 +1,7 @@ { "FileVersion": 3, "Version": 1, - "VersionName": "1.0.18", + "VersionName": "1.0.19", "EngineVersion" : "4.22.0", "FriendlyName": "Socket.IO Client", "Description": "Real-time networking library Socket.IO Client usable from blueprints and c++.", diff --git a/Source/SocketIOClient/Private/SocketIOClientComponent.cpp b/Source/SocketIOClient/Private/SocketIOClientComponent.cpp index cc979689..858af892 100644 --- a/Source/SocketIOClient/Private/SocketIOClientComponent.cpp +++ b/Source/SocketIOClient/Private/SocketIOClientComponent.cpp @@ -571,7 +571,12 @@ void USocketIOClientComponent::BindEvent(const FString& EventName, const FString }, Namespace); } -void USocketIOClientComponent::BindEventToFunction(const FString& EventName, const FString& FunctionName, UObject* Target, const FString& Namespace /*= FString(TEXT("/"))*/, UObject* WorldContextObject /*= nullptr*/) +void USocketIOClientComponent::BindEventToFunction(const FString& EventName, + const FString& FunctionName, + UObject* Target, + const FString& Namespace /*= FString(TEXT("/"))*/, + ESIOThreadOverrideOption ThreadOverride /*= USE_DEFAULT*/, + UObject* WorldContextObject /*= nullptr*/) { if (!FunctionName.IsEmpty()) { @@ -582,7 +587,7 @@ void USocketIOClientComponent::BindEventToFunction(const FString& EventName, con OnNativeEvent(EventName, [&, FunctionName, Target](const FString& Event, const TSharedPtr& Message) { CallBPFunctionWithMessage(Target, FunctionName, Message); - }, Namespace); + }, Namespace, ThreadOverride); } else { @@ -591,9 +596,12 @@ void USocketIOClientComponent::BindEventToFunction(const FString& EventName, con } } -void USocketIOClientComponent::OnNativeEvent(const FString& EventName, TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, const FString& Namespace /*= FString(TEXT("/"))*/) +void USocketIOClientComponent::OnNativeEvent(const FString& EventName, + TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, + const FString& Namespace /*= FString(TEXT("/"))*/, + ESIOThreadOverrideOption ThreadOverride /*= USE_DEFAULT*/) { - NativeClient->OnEvent(EventName, CallbackFunction, Namespace); + NativeClient->OnEvent(EventName, CallbackFunction, Namespace, ThreadOverride); } #if PLATFORM_WINDOWS diff --git a/Source/SocketIOClient/Private/SocketIONative.cpp b/Source/SocketIOClient/Private/SocketIONative.cpp index 0216dfc1..84ca014c 100644 --- a/Source/SocketIOClient/Private/SocketIONative.cpp +++ b/Source/SocketIOClient/Private/SocketIONative.cpp @@ -224,7 +224,10 @@ void FSocketIONative::EmitRawBinary(const FString& EventName, uint8* Data, int32 PrivateClient->socket(USIOMessageConvert::StdString(Namespace))->emit(USIOMessageConvert::StdString(EventName), std::make_shared((char*)Data, DataLength)); } -void FSocketIONative::OnEvent(const FString& EventName, TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, const FString& Namespace /*= FString(TEXT("/"))*/) +void FSocketIONative::OnEvent(const FString& EventName, + TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, + const FString& Namespace /*= FString(TEXT("/"))*/, + ESIOThreadOverrideOption CallbackThread /*= USE_DEFAULT*/) { //Keep track of all the bound native JsonValue functions FSIOBoundEvent BoundEvent; @@ -234,21 +237,41 @@ void FSocketIONative::OnEvent(const FString& EventName, TFunction< void(const FS OnRawEvent(EventName, [&, CallbackFunction](const FString& Event, const sio::message::ptr& RawMessage) { CallbackFunction(Event, USIOMessageConvert::ToJsonValue(RawMessage)); - }, Namespace); + }, Namespace, CallbackThread); } -void FSocketIONative::OnRawEvent(const FString& EventName, TFunction< void(const FString&, const sio::message::ptr&)> CallbackFunction, const FString& Namespace /*= FString(TEXT("/"))*/) +void FSocketIONative::OnRawEvent(const FString& EventName, + TFunction< void(const FString&, const sio::message::ptr&)> CallbackFunction, + const FString& Namespace /*= FString(TEXT("/"))*/, + ESIOThreadOverrideOption CallbackThread /*= USE_DEFAULT*/) { const TFunction< void(const FString&, const sio::message::ptr&)> SafeFunction = CallbackFunction; //copy the function so it remains in context + + //determine thread override option + bool bCallbackThisEventOnGameThread = bCallbackOnGameThread; + switch (CallbackThread) + { + case USE_DEFAULT: + break; + case GAME_THREAD: + bCallbackThisEventOnGameThread = true; + break; + case NETWORK_THREAD: + bCallbackThisEventOnGameThread = false; + break; + default: + break; + } PrivateClient->socket(USIOMessageConvert::StdString(Namespace))->on( USIOMessageConvert::StdString(EventName), sio::socket::event_listener_aux( - [&, SafeFunction](std::string const& name, sio::message::ptr const& data, bool isAck, sio::message::list &ack_resp) + [&, SafeFunction, bCallbackThisEventOnGameThread](std::string const& name, sio::message::ptr const& data, bool isAck, sio::message::list &ack_resp) { const FString SafeName = USIOMessageConvert::FStringFromStd(name); - if (bCallbackOnGameThread) + + if (bCallbackThisEventOnGameThread) { FLambdaRunnable::RunShortLambdaOnGameThread([&, SafeFunction, SafeName, data] { diff --git a/Source/SocketIOClient/Public/SocketIOClientComponent.h b/Source/SocketIOClient/Public/SocketIOClientComponent.h index e90724d5..90cbf536 100644 --- a/Source/SocketIOClient/Public/SocketIOClientComponent.h +++ b/Source/SocketIOClient/Public/SocketIOClientComponent.h @@ -157,7 +157,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent * @param Namespace Namespace within socket.io */ UFUNCTION(BlueprintCallable, Category = "SocketIO Functions") - void Emit(const FString& EventName, USIOJsonValue* Message = nullptr, const FString& Namespace = FString(TEXT("/"))); + void Emit(const FString& EventName, USIOJsonValue* Message = nullptr, const FString& Namespace = TEXT("/")); /** * Emit an event with a JsonValue message with a callback function defined by CallBackFunctionName @@ -173,7 +173,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent USIOJsonValue* Message = nullptr, const FString& CallbackFunctionName = FString(""), UObject* Target = nullptr, - const FString& Namespace = FString(TEXT("/")), + const FString& Namespace = TEXT("/"), UObject* WorldContextObject = nullptr); @@ -191,7 +191,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent struct FLatentActionInfo LatentInfo, USIOJsonValue*& Result, USIOJsonValue* Message = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * Bind an event, then respond to it with 'OnEvent' multi-cast delegate @@ -200,7 +200,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent * @param Namespace Optional namespace, defaults to default namespace */ UFUNCTION(BlueprintCallable, Category = "SocketIO Functions") - void BindEvent(const FString& EventName, const FString& Namespace = FString(TEXT("/"))); + void BindEvent(const FString& EventName, const FString& Namespace = TEXT("/")); /** @@ -210,12 +210,15 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent * @param EventName Event name * @param FunctionName The function that gets called when the event is received * @param Target Optional, defaults to caller self. Change to delegate to another class. + * @param Namespace Optional namespace, defaults to default namespace + * @param ThreadOverride Optional override to receive event on specified thread. Note NETWORK thread is lower latency but unsafe for a lot of blueprint use. Use with CAUTION. */ UFUNCTION(BlueprintCallable, Category = "SocketIO Functions", meta = (WorldContext = "WorldContextObject")) void BindEventToFunction( const FString& EventName, const FString& FunctionName, UObject* Target, - const FString& Namespace = FString(TEXT("/")), + const FString& Namespace = TEXT("/"), + ESIOThreadOverrideOption ThreadOverride = USE_DEFAULT, UObject* WorldContextObject = nullptr); // //C++ functions @@ -246,7 +249,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const TSharedPtr& Message = nullptr, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a Json Object message @@ -259,7 +262,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const TSharedPtr& ObjectMessage = nullptr, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a string message @@ -272,7 +275,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const FString& StringMessage = FString(), TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a string message @@ -285,7 +288,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const SIO_TEXT_TYPE StringMessage = TEXT(""), TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a number (double) message @@ -298,7 +301,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, double NumberMessage, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a bool message @@ -311,7 +314,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, bool BooleanMessage, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with a binary message @@ -324,7 +327,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const TArray& BinaryMessage, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with an array message @@ -337,7 +340,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent void EmitNative(const FString& EventName, const TArray>& ArrayMessage, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * (Overloaded) Emit an event with an UStruct message @@ -352,7 +355,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent UStruct* Struct, const void* StructPtr, TFunction< void(const TArray>&)> CallbackFunction = nullptr, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** * Call function callback on receiving socket event. C++ only. @@ -360,10 +363,12 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent * @param EventName Event name * @param TFunction Lambda callback, JSONValue * @param Namespace Optional namespace, defaults to default namespace + * @param ThreadOverride Optional override to receive event on specified thread. Note NETWORK thread is lower latency but unsafe for a lot of blueprint use. Use with CAUTION. */ void OnNativeEvent( const FString& EventName, TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/"), + ESIOThreadOverrideOption ThreadOverride = USE_DEFAULT); /** * Call function callback on receiving binary event. C++ only. @@ -374,7 +379,7 @@ class SOCKETIOCLIENT_API USocketIOClientComponent : public UActorComponent */ void OnBinaryEvent( const FString& EventName, TFunction< void(const FString&, const TArray&)> CallbackFunction, - const FString& Namespace = FString(TEXT("/"))); + const FString& Namespace = TEXT("/")); /** Called by SocketIOFunctionLibrary to initialize statically constructed components. */ diff --git a/Source/SocketIOClient/Public/SocketIONative.h b/Source/SocketIOClient/Public/SocketIONative.h index da508e3a..f42cf663 100644 --- a/Source/SocketIOClient/Public/SocketIONative.h +++ b/Source/SocketIOClient/Public/SocketIONative.h @@ -16,6 +16,14 @@ enum ESIOConnectionCloseReason CLOSE_REASON_DROP }; +UENUM(BlueprintType) +enum ESIOThreadOverrideOption +{ + USE_DEFAULT, + GAME_THREAD, + NETWORK_THREAD +}; + //Wrapper function for TFunctions which can be hashed based on pointers. I.e. no duplicate functions allowed //NB: Not currently used template @@ -310,11 +318,13 @@ class SOCKETIOCLIENT_API FSocketIONative * @param EventName Event name * @param TFunction Lambda callback, JSONValue * @param Namespace Optional namespace, defaults to default namespace + * @param CallbackThread Override default bCallbackOnGameThread option to specified option for this event */ void OnEvent( const FString& EventName, TFunction< void(const FString&, const TSharedPtr&)> CallbackFunction, - const FString& Namespace = TEXT("/")); + const FString& Namespace = TEXT("/"), + ESIOThreadOverrideOption CallbackThread = USE_DEFAULT); /** * Call function callback on receiving raw event. C++ only. @@ -322,11 +332,13 @@ class SOCKETIOCLIENT_API FSocketIONative * @param EventName Event name * @param TFunction Lambda callback, raw flavor * @param Namespace Optional namespace, defaults to default namespace + * @param CallbackThread Override default bCallbackOnGameThread option to specified option for this event */ void OnRawEvent( const FString& EventName, TFunction< void(const FString&, const sio::message::ptr&)> CallbackFunction, - const FString& Namespace = TEXT("/")); + const FString& Namespace = TEXT("/"), + ESIOThreadOverrideOption CallbackThread = USE_DEFAULT); /** * Call function callback on receiving binary event. C++ only. *