I am using the Websockets module to establish a connection to a server. I have authored a latent blueprint node that, given a websocket (with a URL, protocol headers, etc.), can connect to the server, and includes a pass by reference boolean indicating success:
void UHttpBlueprintFunctionLibrary::ConnectToSocket(UObject* WorldContextObject, struct FLatentActionInfo LatentInfo, FSocketStruct SStruct, bool& bSuccess)
{
class FXWebSocketConnectLatentAction : public FPendingLatentAction
{
public:
// handle delegates
FDelegateHandle ConnectedHandler;
FDelegateHandle ConnectionErrorHandler;
FDelegateHandle OnMessageHandler;
FXWebSocketConnectLatentAction(const FLatentActionInfo& LatentInfo, TSharedPtr<IWebSocket> Socket, bool &ConnResult)
: ExecutionFunction(LatentInfo.ExecutionFunction)
, OutputLink(LatentInfo.Linkage)
, CallbackTarget(LatentInfo.CallbackTarget)
, WebSocket(Socket)
, ConnectionResult(ConnResult)
, Timer(0.0f)
{
ConnectedHandler = Socket->OnConnected().AddLambda([&ConnResult]() -> void {
GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Cyan, "Connected to Hansoft Server");
UE_LOG(LogHansoftBug, Display, TEXT("Connected to Hansoft Server"));
ConnResult = true;
});
ConnectionErrorHandler = Socket->OnConnectionError().AddLambda([&ConnResult](const FString& ErrorMsg) -> void {
UE_LOG(LogHansoftBug, Display, TEXT("Got connection result %s"), *ErrorMsg);
ConnResult = false;
});
OnMessageHandler = Socket->OnMessage().AddLambda([](const FString& Message) -> void {
// This code will run when we receive a string message from the server.
UE_LOG(LogHansoftBug, Display, TEXT("Received message from Hansoft: %s"), *Message);
GEngine->AddOnScreenDebugMessage(-1, 10.0f, FColor::Yellow, "Received message: " + Message);
});
// connect after establishing lambdas
Socket->Connect();
}
~FXWebSocketConnectLatentAction()
{
WebSocket->OnConnected().Remove(ConnectedHandler);
WebSocket->OnConnectionError().Remove(ConnectionErrorHandler);
WebSocket->OnMessage().Remove(ConnectionErrorHandler);
}
// Variables for latent action info
FName ExecutionFunction;
int32 OutputLink;
FWeakObjectPtr CallbackTarget;
TSharedPtr<IWebSocket> WebSocket;
bool& ConnectionResult;
float Timer;
// check for completion function
virtual void UpdateOperation(FLatentResponse& Response) override
{
Timer += Response.ElapsedTime();
if (ConnectionResult)
{
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
if (Timer >= 10.0f) // 10s timeout
{
ConnectionResult = false;
Response.FinishAndTriggerIf(true, ExecutionFunction, OutputLink, CallbackTarget);
}
}
};
// Add the latent action to the manager
FXWebSocketConnectLatentAction* CompletionAction = nullptr;
FLatentActionManager& LatentActionManager = WorldContextObject->GetWorld()->GetLatentActionManager();
if (LatentActionManager.FindExistingAction<FXWebSocketConnectLatentAction>(LatentInfo.CallbackTarget, LatentInfo.UUID) == nullptr)
{
CompletionAction = new FXWebSocketConnectLatentAction(LatentInfo, SStruct.Socket, bSuccess);
LatentActionManager.AddNewAction(LatentInfo.CallbackTarget, LatentInfo.UUID, CompletionAction);
}
}
Where SSocketStruct is a simple UStruct containing only one TSharedPtr<IWebSocket> member.
When playing my game in editor, the function above works flawlessly, opening a connection, allowing me to see the relevant OnConnected() logging, and getting the successful result in the output.
However, when I package the game and run the same function, the connection to the websocket times out and I see the message “client_connect_failed” in the OnConnectionError() callback.
I followed the steps on this very similar post ensuring that my target platform is correct (Win64 in this case), copying the cacert.pem file into my project’s content directory and re-cooking, but still, no avail.
Any help would be greatly appreciated!