Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add CustomMessageType support. #37

Merged
merged 8 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .pubnub.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,19 @@ version: 0.1.0
schema: 1
scm: github.com/pubnub/unreal-engine
changelog:
- date: 2024-11-25
version: 0.2.2
changes:
- type: feature
text: "Add Unreal 5.5 support"
- type: feature
text: "Add documentation in code"
- type: feature
text: "Add CustomMessageType parameter to publish, signal and history"
- type: improvement
text: "Rename uuid to user in all inputs and functions."
- type: improvement
text: "Rename ChannelName to Channel in in function inputs."
- date: 2024-09-16
version: 0.1.4
changes:
Expand Down
4 changes: 2 additions & 2 deletions PubnubLibrary.uplugin
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "0.2.1",
"Version": 2,
"VersionName": "0.2.2",
"FriendlyName": "Pubnub Unreal SDK",
"Description": "Quickly add interactive features to your game that scale without building your backend infrastructure.",
"Category": "Code",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ void UPubnubJsonUtilities::FetchHistoryJsonToData(FString ResponseJson, bool& Er
MessageValue->AsObject()->TryGetStringField(ANSI_TO_TCHAR("uuid"), CurrentMessage.UserID);
MessageValue->AsObject()->TryGetStringField(ANSI_TO_TCHAR("timetoken"), CurrentMessage.Timetoken);
MessageValue->AsObject()->TryGetStringField(ANSI_TO_TCHAR("message_type"), CurrentMessage.MessageType);
MessageValue->AsObject()->TryGetStringField(ANSI_TO_TCHAR("custom_message_type"), CurrentMessage.MessageType);
if(!MessageValue->AsObject()->TryGetStringField(ANSI_TO_TCHAR("meta"), CurrentMessage.Meta))
{
UE_LOG(LogTemp, Warning, TEXT("Reading Meta as Json Object"));
Expand Down
10 changes: 10 additions & 0 deletions Source/PubnubLibrary/Private/FunctionLibraries/PubnubUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,13 @@ FString UPubnubUtilities::AddQuotesToString(const FString InString, bool SkipIfH

return InString;
}

FString UPubnubUtilities::PubnubCharMemBlockToString(const pubnub_char_mem_block PnChar)
{
if(!PnChar.ptr)
{
return "";
}

return FString::ConstructFromPtrSize(PnChar.ptr, PnChar.size);
}
81 changes: 56 additions & 25 deletions Source/PubnubLibrary/Private/PubnubSubsystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,14 +115,14 @@ void UPubnubSubsystem::PublishMessage(FString Channel, FString Message, FPubnubP
});
}

void UPubnubSubsystem::Signal(FString Channel, FString Message)
void UPubnubSubsystem::Signal(FString Channel, FString Message, FPubnubSignalSettings SignalSettings)
{
if(!CheckIsPubnubInitialized() || !CheckQuickActionThreadValidity())
{return;}

QuickActionThread->AddFunctionToQueue( [this, Channel, Message]
QuickActionThread->AddFunctionToQueue( [this, Channel, Message, SignalSettings]
{
PublishMessage_priv(Channel, Message);
Signal_priv(Channel, Message, SignalSettings);
});
}

Expand Down Expand Up @@ -804,16 +804,21 @@ void UPubnubSubsystem::StartPubnubSubscribeLoop()
if(SubscribedChannels.IsEmpty() && SubscribedGroups.IsEmpty())
{return;}

//Subscribe to channels - this is blocking function
pubnub_subscribe(ctx_sub, TCHAR_TO_ANSI(*StringArrayToCommaSeparated(SubscribedChannels)), TCHAR_TO_ANSI(*StringArrayToCommaSeparated(SubscribedGroups)));

pubnub_subscribe_v2_options PubnubOptions = pubnub_subscribe_v2_defopts();
auto CharConverter = StringCast<ANSICHAR>(*StringArrayToCommaSeparated(SubscribedGroups));
PubnubOptions.channel_group = CharConverter.Get();

//Subscribe to channels - this is blocking function
pubnub_res SubscribeResult = pubnub_subscribe_v2(ctx_sub, TCHAR_TO_ANSI(*StringArrayToCommaSeparated(SubscribedChannels)), PubnubOptions);

//If context was released on deinitializing subsystem it should just return
if(!IsInitialized)
{return;}

//Check for subscribe result
pubnub_res SubscribeResult = pubnub_await(ctx_sub);
if (SubscribeResult != PNR_OK)
pubnub_await(ctx_sub);
if (SubscribeResult != PNR_OK && SubscribeResult != PNR_STARTED )
{
PubnubResponseError(SubscribeResult, "Failed to subscribe to channel.");
{return;}
Expand All @@ -822,28 +827,24 @@ void UPubnubSubsystem::StartPubnubSubscribeLoop()
//Check once again, as subsystem could be deinitialized during await
if(!IsInitialized)
{return;}

//At this stage we received messages, so read them and get channel from where they were sent
const char* MessageChar = pubnub_get(ctx_sub);
const char* ChannelChar = pubnub_get_channel(ctx_sub);
while(MessageChar != NULL)

//At this stage we received messages, so just read them and parse to correct structure
pubnub_v2_message message = pubnub_get_v2(ctx_sub);
while(message.payload.ptr)
{
FString Message(MessageChar);
FString Channel(ChannelChar);
FPubnubMessageData MessageData = UEMessageFromPubnub(message);

//Skip system messages, we don't need to display them to user
if(Message != SystemPublishMessage)
if(MessageData.Message != SystemPublishMessage)
{
//Broadcast callback with message content
//Message needs to be called back on Game Thread
AsyncTask(ENamedThreads::GameThread, [this, Message, Channel]()
AsyncTask(ENamedThreads::GameThread, [this, MessageData]()
{
OnMessageReceived.Broadcast(Message, Channel);
OnMessageReceived.Broadcast(MessageData);
});
}

MessageChar = pubnub_get(ctx_sub);
ChannelChar = pubnub_get_channel(ctx_sub);
message = pubnub_get_v2(ctx_sub);
}
});
}
Expand Down Expand Up @@ -1145,10 +1146,13 @@ void UPubnubSubsystem::PublishMessage_priv(FString Channel, FString Message, FPu
pubnub_publish_options PubnubOptions;
auto CharConverter = StringCast<ANSICHAR>(*PublishSettings.MetaData);
PubnubOptions.meta = CharConverter.Get();

PublishUESettingsToPubnubPublishOptions(PublishSettings, PubnubOptions);

auto TypeCharConverter = StringCast<ANSICHAR>(*PublishSettings.CustomMessageType);
PubnubOptions.custom_message_type = TypeCharConverter.Get();

PublishUESettingsToPubnubPublishOptions(PublishSettings, PubnubOptions);
pubnub_publish_ex(ctx_pub, TCHAR_TO_ANSI(*Channel), TCHAR_TO_ANSI(*Message), PubnubOptions);

pubnub_res PublishResult = pubnub_await(ctx_pub);

if(PublishResult != PNR_OK)
Expand All @@ -1157,15 +1161,25 @@ void UPubnubSubsystem::PublishMessage_priv(FString Channel, FString Message, FPu
}
}

void UPubnubSubsystem::Signal_priv(FString Channel, FString Message)
void UPubnubSubsystem::Signal_priv(FString Channel, FString Message, FPubnubSignalSettings SignalSettings)
{
if(!CheckIsUserIDSet())
{return;}

if(CheckIsFieldEmpty(Channel, "ChannelName", "Signal") || CheckIsFieldEmpty(Message, "Message", "Signal"))
{return;}

pubnub_signal_options PubnubOptions = pubnub_signal_defopts();
auto CharConverter = StringCast<ANSICHAR>(*SignalSettings.CustomMessageType);
PubnubOptions.custom_message_type = CharConverter.Get();
pubnub_signal_ex(ctx_pub, TCHAR_TO_ANSI(*Channel), TCHAR_TO_ANSI(*Message), PubnubOptions);

pubnub_res PublishResult = pubnub_await(ctx_pub);

pubnub_signal(ctx_pub, TCHAR_TO_ANSI(*Channel), TCHAR_TO_ANSI(*Message));
if(PublishResult != PNR_OK)
{
PubnubPublishError();
}
}

void UPubnubSubsystem::SubscribeToChannel_priv(FString Channel)
Expand Down Expand Up @@ -2429,7 +2443,9 @@ void UPubnubSubsystem::PublishUESettingsToPubnubPublishOptions(FPubnubPublishSet
PubnubPublishOptions.store = PublishSettings.StoreInHistory;
PubnubPublishOptions.replicate = PublishSettings.Replicate;
PubnubPublishOptions.cipher_key = NULL;
PubnubPublishOptions.ttl = PublishSettings.Ttl;
PublishSettings.MetaData.IsEmpty() ? PubnubPublishOptions.meta = NULL : nullptr;
PublishSettings.CustomMessageType.IsEmpty() ? PubnubPublishOptions.custom_message_type = NULL : nullptr;
PubnubPublishOptions.method = (pubnub_method)(uint8)PublishSettings.PublishMethod;
}

Expand All @@ -2455,10 +2471,25 @@ void UPubnubSubsystem::FetchHistoryUESettingsToPbFetchHistoryOptions(FPubnubFetc
PubnubFetchHistoryOptions.include_message_type = FetchHistorySettings.IncludeMessageType;
PubnubFetchHistoryOptions.include_user_id = FetchHistorySettings.IncludeUserID;
PubnubFetchHistoryOptions.include_message_actions = FetchHistorySettings.IncludeMessageActions;
PubnubFetchHistoryOptions.include_custom_message_type = FetchHistorySettings.IncludeCustomMessageType;
FetchHistorySettings.Start.IsEmpty() ? PubnubFetchHistoryOptions.start = NULL : nullptr;
FetchHistorySettings.End.IsEmpty() ? PubnubFetchHistoryOptions.end = NULL : nullptr;
}

FPubnubMessageData UPubnubSubsystem::UEMessageFromPubnub(pubnub_v2_message PubnubMessage)
{
FPubnubMessageData MessageData;
MessageData.Message = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.payload);
MessageData.Channel = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.channel);
MessageData.UserID = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.publisher);
MessageData.Timetoken = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.tt);
MessageData.Metadata = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.metadata);
MessageData.MessageType = (EPubnubMessageType)(PubnubMessage.message_type);
MessageData.CustomMessageType = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.custom_message_type);
MessageData.MatchOrGroup = UPubnubUtilities::PubnubCharMemBlockToString(PubnubMessage.match_or_group);
return MessageData;
}

//This functions assumes that Channels and Permissions are already checked. It means that there is the same amount of permissions as channels or there is exactly one permission
TSharedPtr<FJsonObject> UPubnubSubsystem::AddChannelPermissionsToJson(TArray<FString> Channels, TArray<FPubnubChannelPermissions> ChannelPermissions)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#pragma once

#include <pubnub_memory_block.h>
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "PubnubUtilities.generated.h"
Expand All @@ -16,4 +17,5 @@ class PUBNUBLIBRARY_API UPubnubUtilities : public UBlueprintFunctionLibrary
public:

static FString AddQuotesToString(const FString InString, bool SkipIfHasQuotes = true);
static FString PubnubCharMemBlockToString(const pubnub_char_mem_block PnChar);
};
15 changes: 15 additions & 0 deletions Source/PubnubLibrary/Public/PubnubEnumLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,18 @@ enum class EPubnubErrorType : uint8
PET_Error UMETA(DisplayName="Error"),
PET_Warning UMETA(DisplayName="Warning")
};

UENUM(BlueprintType)
enum class EPubnubMessageType : uint8
{
/* Indicates that message was received as a signal */
PMT_Signal,
/* Indicates that message was published */
PMT_Published,
/* Indicates action on published message */
PMT_Action,
/* Message about Objects */
PMT_Objects,
/* Message about Files */
PMT_Files,
};
50 changes: 50 additions & 0 deletions Source/PubnubLibrary/Public/PubnubStructLibrary.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ struct FPubnubPublishSettings
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString MetaData = "";
//Defines the method by which publish transaction will be performed. Can be HTTP GET or POST. If using POST, content can be GZIP compressed.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") EPubnubPublishMethod PublishMethod = EPubnubPublishMethod::PPM_SendViaGET;
//For how many hours message should be kept and available with history API. If 0, server default will be used.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") int Ttl = 0;
/** User-specified message type.
Important: String limited by **3**-**50** case-sensitive alphanumeric characters with only `-` and `_` special characters allowed.
*/
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString CustomMessageType = "";
};

USTRUCT(BlueprintType)
struct FPubnubSignalSettings
{
GENERATED_BODY()

/** User-specified message type.
Important: String limited by **3**-**50** case-sensitive alphanumeric characters with only `-` and `_` special characters allowed.
*/
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString CustomMessageType = "";
};

USTRUCT(BlueprintType)
Expand Down Expand Up @@ -128,6 +145,10 @@ struct FPubnubFetchHistorySettings
* false.
*/
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") bool IncludeMessageActions = false;
/** Include messages' custom type flag.
Message / signal and file messages may contain user-provided type.
*/
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") bool IncludeCustomMessageType = false;
};

USTRUCT(BlueprintType)
Expand Down Expand Up @@ -253,6 +274,8 @@ struct FPubnubHistoryMessageData
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Meta = "";
//Type of the message. Refer to Message types for more information.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString MessageType = "";
//User-specified message type.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString CustomMessageType = "";
//An array of FPubnubMessageActionData structs which are message actions that were added to the historical messages.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") TArray<FPubnubMessageActionData> MessageActions;
};
Expand Down Expand Up @@ -343,4 +366,31 @@ struct FPubnubGetChannelMembersWrapper
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Updated = "";
//Version identifier of the membership metadata.
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString ETag = "";
};

USTRUCT(BlueprintType)
struct FPubnubMessageData
{
GENERATED_BODY()

/** The message itself */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Message = "";
/** Channel that message was published to */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Channel = "";
/** The message information about publisher */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString UserID = "";
/** The time token of the message - when it was published. */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Timetoken = "";
/** The message metadata, as published */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString Metadata = "";
/** Indicates the message type: a signal, published, or something else */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") EPubnubMessageType MessageType = EPubnubMessageType::PMT_Published;
/** User-provided message type. */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString CustomMessageType = "";
/** Subscription match or the channel group */
UPROPERTY(BlueprintReadWrite, VisibleAnywhere, Category = "Pubnub") FString MatchOrGroup = "";
/** Region of the message - not interesting in most cases */
int region = 0;
/** Message flags */
int flags = 0;
};
11 changes: 5 additions & 6 deletions Source/PubnubLibrary/Public/PubnubSubsystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class FPubnubFunctionThread;
class FPubnubLoopingThread;
class UPubnubChatSystem;

DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnMessageReceived, FString, MessageJson, FString, Channel);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMessageReceived, FPubnubMessageData, Message);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnPubnubError, FString, ErrorMessage, EPubnubErrorType, ErrorType);
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnPubnubResponse, FString, JsonResponse);
DECLARE_DYNAMIC_DELEGATE_OneParam(FOnPubnubIntResponse, int, IntValue);
Expand Down Expand Up @@ -113,7 +113,7 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem
* @param Message The message to send as the signal. This message can be any data type that can be serialized into JSON.
*/
UFUNCTION(BlueprintCallable, Category = "Pubnub|Publish")
void Signal(FString Channel, FString Message);
void Signal(FString Channel, FString Message, FPubnubSignalSettings SignalSettings = FPubnubSignalSettings());

/**
* Subscribes to a specified channel - start listening for messages on that channel.
Expand Down Expand Up @@ -814,7 +814,7 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem
void SetUserID_priv(FString UserID);
void SetSecretKey_priv();
void PublishMessage_priv(FString Channel, FString Message, FPubnubPublishSettings PublishSettings = FPubnubPublishSettings());
void Signal_priv(FString Channel, FString Message);
void Signal_priv(FString Channel, FString Message, FPubnubSignalSettings SignalSettings = FPubnubSignalSettings());
void SubscribeToChannel_priv(FString Channel);
void SubscribeToGroup_priv(FString GroupName);
void UnsubscribeFromChannel_priv(FString Channel);
Expand Down Expand Up @@ -885,12 +885,11 @@ class PUBNUBLIBRARY_API UPubnubSubsystem : public UGameInstanceSubsystem
void HereNowUESettingsToPubnubHereNowOptions(FPubnubListUsersFromChannelSettings &HereNowSettings, pubnub_here_now_options &PubnubHereNowOptions);
void SetStateUESettingsToPubnubSetStateOptions(FPubnubSetStateSettings &SetStateSettings, pubnub_set_state_options &PubnubSetStateOptions);
void FetchHistoryUESettingsToPbFetchHistoryOptions(FPubnubFetchHistorySettings &FetchHistorySettings, pubnub_fetch_history_options &PubnubFetchHistoryOptions);

FPubnubMessageData UEMessageFromPubnub(pubnub_v2_message PubnubMessage);

/* GRANT TOKEN HELPERS */

TSharedPtr<FJsonObject> AddChannelPermissionsToJson(TArray<FString> Channels, TArray<FPubnubChannelPermissions> ChannelPermissions);
TSharedPtr<FJsonObject> AddChannelGroupPermissionsToJson(TArray<FString> ChannelGroups, TArray<FPubnubChannelGroupPermissions> ChannelGroupPermissions);
TSharedPtr<FJsonObject> AddUserPermissionsToJson(TArray<FString> Users, TArray<FPubnubUserPermissions> UserPermissions);
};


Loading