Skip to content

Commit

Permalink
Add custom message type support
Browse files Browse the repository at this point in the history
  • Loading branch information
jguz-pubnub committed Oct 4, 2024
1 parent 7ec9708 commit 5d0c392
Show file tree
Hide file tree
Showing 15 changed files with 480 additions and 155 deletions.
6 changes: 5 additions & 1 deletion Sources/PubNub/APIs/File+PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ public extension PubNub {
struct PublishFileRequest {
/// The optional message that will be include alongside the File information
public var additionalMessage: JSONCodable?
/// Custom message type
public var customMessageType: String? = nil
/// If true the published message is stored in history.
public var store: Bool?
/// Set a per message time to live in storage.
Expand All @@ -98,12 +100,14 @@ public extension PubNub {
/// - customRequestConfig: Custom configuration overrides for this request
public init(
additionalMessage: JSONCodable? = nil,
customMessageType: String? = nil,
store: Bool? = nil,
ttl: Int? = nil,
meta: JSONCodable? = nil,
customRequestConfig: RequestConfiguration = RequestConfiguration()
) {
self.additionalMessage = additionalMessage
self.customMessageType = customMessageType
self.store = store
self.ttl = ttl
self.meta = meta
Expand Down Expand Up @@ -222,7 +226,7 @@ public extension PubNub {

let router = PublishRouter(
.file(
message: fileMessage,
message: fileMessage, customMessageType: request.customMessageType,
shouldStore: request.store, ttl: request.ttl, meta: request.meta?.codableValue
),
configuration: configuration
Expand Down
14 changes: 12 additions & 2 deletions Sources/PubNub/Models/PubNubMessage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ public enum PubNubMessageType: Int, Codable, Hashable {
case object = 2
case messageAction = 3
case file = 4

case unknown = 999
}

Expand All @@ -38,6 +37,8 @@ public protocol PubNubMessage {
var metadata: JSONCodable? { get set }
/// The type of message that was received
var messageType: PubNubMessageType { get set }
/// A user-provided custom message type
var customMessageType: String? { get set }
/// An error (if any) occured while getting this message
var error: PubNubError? { get set }

Expand Down Expand Up @@ -76,6 +77,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
public var subscription: String?
public var published: Timetoken
public var messageType: PubNubMessageType
public var customMessageType: String?
public var error: PubNubError?

var concretePayload: AnyJSON
Expand Down Expand Up @@ -112,6 +114,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
subscription: other.subscription,
published: other.published,
metadata: other.metadata?.codableValue,
type: other.customMessageType,
messageType: other.messageType,
error: other.error
)
Expand All @@ -126,6 +129,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
subscription: subscribe.subscription,
published: subscribe.publishTimetoken.timetoken,
metadata: subscribe.metadata,
type: subscribe.customMessageType,
messageType: subscribe.messageType.asPubNubMessageType,
error: subscribe.error
)
Expand All @@ -146,7 +150,8 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
subscription: nil,
published: history.timetoken,
metadata: history.meta,
messageType: history.messageType ?? .unknown,
type: history.customMessageType,
messageType: history.messageType?.asPubNubMessageType ?? .unknown,
error: history.error
)
}
Expand All @@ -159,6 +164,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
subscription: String?,
published: Timetoken,
metadata: AnyJSON?,
type: String? = nil,
messageType: PubNubMessageType = .unknown,
error: PubNubError? = nil
) {
Expand All @@ -170,6 +176,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
self.published = published
self.concreteMetadata = metadata
self.messageType = messageType
self.customMessageType = type
self.error = error
}

Expand All @@ -184,6 +191,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
try container.encode(self.published, forKey: .published)
try container.encodeIfPresent(self.concreteMetadata, forKey: .concreteMetadata)
try container.encode(self.messageType, forKey: .messageType)
try container.encode(self.customMessageType, forKey: .customMessageType)
}

enum CodingKeys: CodingKey {
Expand All @@ -195,6 +203,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
case published
case concreteMetadata
case messageType
case customMessageType
}

public init(from decoder: Decoder) throws {
Expand All @@ -208,6 +217,7 @@ public struct PubNubMessageBase: PubNubMessage, Codable, Hashable {
self.published = try container.decode(Timetoken.self, forKey: .published)
self.concreteMetadata = try container.decodeIfPresent(AnyJSON.self, forKey: .concreteMetadata)
self.messageType = try container.decode(PubNubMessageType.self, forKey: .messageType)
self.customMessageType = try container.decodeIfPresent(String.self, forKey: .customMessageType)
}
}

Expand Down
2 changes: 2 additions & 0 deletions Sources/PubNub/Networking/HTTPRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,15 @@ enum QueryKey: String {
case remove
case add
case type
case customMessageType = "custom_message_type"
case start
case end
case channel
case count
case max
case includeMeta = "include_meta"
case includeMessageType = "include_message_type"
case includeCustomMessageType = "include_custom_message_type"
case includeUUID = "include_uuid"
case timetoken
case channelsTimetoken
Expand Down
85 changes: 49 additions & 36 deletions Sources/PubNub/Networking/Routers/HistoryRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ struct HistoryRouter: HTTPRouter {
enum Endpoint: CustomStringConvertible {
case fetch(
channels: [String], max: Int?, start: Timetoken?, end: Timetoken?,
includeMeta: Bool, includeMessageType: Bool, includeUUID: Bool
includeMeta: Bool, includeMessageType: Bool, includeCustomMessageType: Bool, includeUUID: Bool
)
case fetchWithActions(
channel: String, max: Int?, start: Timetoken?, end: Timetoken?,
includeMeta: Bool, includeMessageType: Bool, includeUUID: Bool
includeMeta: Bool, includeMessageType: Bool, includeCustomMessageType: Bool, includeUUID: Bool
)
case delete(channel: String, start: Timetoken?, end: Timetoken?)
case messageCounts(channels: [String], timetoken: Timetoken?, channelsTimetoken: [Timetoken]?)
Expand All @@ -41,9 +41,9 @@ struct HistoryRouter: HTTPRouter {

var firstChannel: String? {
switch self {
case let .fetchWithActions(channel, _, _, _, _, _, _):
case let .fetchWithActions(channel, _, _, _, _, _, _, _):
return channel
case let .fetch(channels, _, _, _, _, _, _):
case let .fetch(channels, _, _, _, _, _, _, _):
return channels.first
case let .delete(channel, _, _):
return channel
Expand Down Expand Up @@ -75,9 +75,9 @@ struct HistoryRouter: HTTPRouter {
let path: String

switch endpoint {
case let .fetchWithActions(channel, _, _, _, _, _, _):
case let .fetchWithActions(channel, _, _, _, _, _, _, _):
path = "/v3/history-with-actions/sub-key/\(subscribeKey)/channel/\(channel)"
case let .fetch(channels, _, _, _, _, _, _):
case let .fetch(channels, _, _, _, _, _, _, _):
path = "/v3/history/sub-key/\(subscribeKey)/channel/\(channels.csvString.urlEncodeSlash)"
case let .delete(channel, _, _):
path = "/v3/history/sub-key/\(subscribeKey)/channel/\(channel.urlEncodeSlash)"
Expand All @@ -91,27 +91,28 @@ struct HistoryRouter: HTTPRouter {
var query = defaultQueryItems

switch endpoint {
case let .fetchWithActions(_, max, start, end, includeMeta, includeMessageType, includeUUID):
case let .fetchWithActions(_, max, start, end, includeMeta, includeMessageType, includeCustomMessageType, includeUUID):
query.appendIfPresent(key: .max, value: max?.description)
query.appendIfPresent(key: .start, value: start?.description)
query.appendIfPresent(key: .end, value: end?.description)
query.appendIfPresent(key: .includeMeta, value: includeMeta.description)
query.appendIfPresent(key: .includeMessageType, value: includeMessageType.description)
query.appendIfPresent(key: .includeCustomMessageType, value: includeCustomMessageType.description)
query.appendIfPresent(key: .includeUUID, value: includeUUID.description)
case let .fetch(_, max, start, end, includeMeta, includeMessageType, includeUUID):
case let .fetch(_, max, start, end, includeMeta, includeMessageType, includeCustomMessageType, includeUUID):
query.appendIfPresent(key: .max, value: max?.description)
query.appendIfPresent(key: .start, value: start?.description)
query.appendIfPresent(key: .end, value: end?.description)
query.appendIfPresent(key: .includeMeta, value: includeMeta.description)
query.appendIfPresent(key: .includeMessageType, value: includeMessageType.description)
query.appendIfPresent(key: .includeCustomMessageType, value: includeCustomMessageType.description)
query.appendIfPresent(key: .includeUUID, value: includeUUID.description)
case let .delete(_, startTimetoken, endTimetoken):
query.appendIfPresent(key: .start, value: startTimetoken?.description)
query.appendIfPresent(key: .end, value: endTimetoken?.description)
case let .messageCounts(_, timetoken, channelsTimetoken):
query.appendIfPresent(key: .timetoken, value: timetoken?.description)
query.appendIfPresent(key: .channelsTimetoken,
value: channelsTimetoken?.map { $0.description }.csvString)
query.appendIfPresent(key: .channelsTimetoken, value: channelsTimetoken?.map { $0.description }.csvString)
}

return .success(query)
Expand All @@ -129,9 +130,9 @@ struct HistoryRouter: HTTPRouter {
// Validated
var validationErrorDetail: String? {
switch endpoint {
case let .fetchWithActions(channel, _, _, _, _, _, _):
case let .fetchWithActions(channel, _, _, _, _, _, _, _):
return isInvalidForReason((channel.isEmpty, ErrorDescription.emptyChannelString))
case let .fetch(channels, _, _, _, _, _, _):
case let .fetch(channels, _, _, _, _, _, _, _):
return isInvalidForReason((channels.isEmpty, ErrorDescription.emptyChannelArray))
case let .delete(channel, _, _):
return isInvalidForReason((channel.isEmpty, ErrorDescription.emptyChannelString))
Expand All @@ -152,16 +153,15 @@ struct MessageHistoryResponseDecoder: ResponseDecoder {
func decode(response: EndpointResponse<Data>) -> Result<EndpointResponse<MessageHistoryResponse>, Error> {
do {
// Version3
let payload = try Constant.jsonDecoder.decode(MessageHistoryResponse.self, from: response.payload)
let decodedResponse = EndpointResponse<MessageHistoryResponse>(router: response.router,
request: response.request,
response: response.response,
data: response.data,
payload: payload)

// Attempt to decode message response

return .success(decodedResponse)
return .success(
EndpointResponse<MessageHistoryResponse>(
router: response.router,
request: response.request,
response: response.response,
data: response.data,
payload: try Constant.jsonDecoder.decode(MessageHistoryResponse.self, from: response.payload)
)
)
} catch {
return .failure(PubNubError(.jsonDataDecodingFailure, response: response, error: error))
}
Expand Down Expand Up @@ -191,6 +191,7 @@ struct MessageHistoryResponseDecoder: ResponseDecoder {
meta: message.meta,
uuid: message.uuid,
messageType: message.messageType,
customMessageType: message.customMessageType,
error: nil
)
case .failure(let error):
Expand All @@ -200,6 +201,7 @@ struct MessageHistoryResponseDecoder: ResponseDecoder {
meta: message.meta,
uuid: message.uuid,
messageType: message.messageType,
customMessageType: message.customMessageType,
error: error
)
PubNub.log.warn("History message failed to decrypt due to \(error)")
Expand All @@ -211,27 +213,31 @@ struct MessageHistoryResponseDecoder: ResponseDecoder {
meta: message.meta,
uuid: message.uuid,
messageType: message.messageType,
customMessageType: message.customMessageType,
error: PubNubError(
.decryptionFailure,
additional: ["Cannot decrypt message due to invalid Base-64 input"]
)
)
}
}

return messages
}

// Replace previous payload with decrypted one
let decryptedPayload = MessageHistoryResponse(status: response.payload.status,
error: response.payload.error,
errorMessage: response.payload.errorMessage,
channels: channels)
let decryptedResponse = EndpointResponse<MessageHistoryResponse>(router: response.router,
request: response.request,
response: response.response,
data: response.data,
payload: decryptedPayload)
let decryptedResponse = EndpointResponse<MessageHistoryResponse>(
router: response.router,
request: response.request,
response: response.response,
data: response.data,
payload: MessageHistoryResponse(
status: response.payload.status,
error: response.payload.error,
errorMessage: response.payload.errorMessage,
channels: channels
)
)
return .success(decryptedResponse)
}
}
Expand Down Expand Up @@ -299,12 +305,14 @@ struct MessageHistoryMessagePayload: Codable {
typealias ActionType = String
typealias ActionValue = String
typealias RawMessageAction = [ActionType: [ActionValue: [MessageHistoryMessageAction]]]
typealias LegacyPubNubMessageType = SubscribeMessagePayload.Action

let message: AnyJSON
let timetoken: Timetoken
let meta: AnyJSON?
let uuid: String?
let messageType: PubNubMessageType?
let messageType: LegacyPubNubMessageType?
let customMessageType: String?
let actions: RawMessageAction
let error: PubNubError?

Expand All @@ -313,14 +321,16 @@ struct MessageHistoryMessagePayload: Codable {
timetoken: Timetoken = 0,
meta: JSONCodable? = nil,
uuid: String?,
messageType: PubNubMessageType?,
messageType: LegacyPubNubMessageType?,
customMessageType: String? = nil,
actions: RawMessageAction = [:],
error: PubNubError?
) {
self.message = message.codableValue
self.timetoken = timetoken
self.uuid = uuid
self.messageType = messageType
self.customMessageType = customMessageType
self.meta = meta?.codableValue
self.actions = actions
self.error = error
Expand All @@ -332,6 +342,7 @@ struct MessageHistoryMessagePayload: Codable {
case meta
case uuid
case messageType = "message_type"
case customMessageType = "custom_message_type"
case actions
}

Expand All @@ -341,9 +352,10 @@ struct MessageHistoryMessagePayload: Codable {
message = try container.decode(AnyJSON.self, forKey: .message)
meta = try container.decodeIfPresent(AnyJSON.self, forKey: .meta)
uuid = try container.decodeIfPresent(String.self, forKey: .uuid)
messageType = try container.decodeIfPresent(PubNubMessageType.self, forKey: .messageType)
timetoken = Timetoken(try container.decode(String.self, forKey: .timetoken)) ?? 0
actions = try container.decodeIfPresent(RawMessageAction.self, forKey: .actions) ?? [:]
messageType = try container.decodeIfPresent(LegacyPubNubMessageType.self, forKey: .messageType) ?? .message
customMessageType = try container.decodeIfPresent(String.self, forKey: .customMessageType)
error = nil
}

Expand All @@ -354,8 +366,9 @@ struct MessageHistoryMessagePayload: Codable {
try container.encode(timetoken.description, forKey: .timetoken)
try container.encodeIfPresent(meta, forKey: .meta)
try container.encodeIfPresent(uuid, forKey: .uuid)
try container.encodeIfPresent(messageType, forKey: .messageType)
try container.encode(actions, forKey: .actions)
try container.encodeIfPresent(messageType, forKey: .messageType)
try container.encodeIfPresent(customMessageType, forKey: .customMessageType)
}
}

Expand Down
Loading

0 comments on commit 5d0c392

Please sign in to comment.