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

Introduced flag for enabling Event Engine #149

Closed
Closed
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
8 changes: 4 additions & 4 deletions Examples/Sources/MasterDetailTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -269,12 +269,12 @@ class MasterDetailTableViewController: UITableViewController {
switch connectionChange {
case .connected:
print("Status connected!")
case .connectionError(let error):
print("Error while attempting to initialize connection: \(error)")
case .connectionError:
print("Error while attempting to initialize connection")
case .disconnected:
print("Status disconnected")
case .disconnectedUnexpectedly(let error):
print("Disconnected unexpectedly: \(error)")
case .disconnectedUnexpectedly:
print("Disconnected unexpectedly")
}
case let .presenceChanged(presenceChange):
print("The channel \(presenceChange.channel) has an updated occupancy of \(presenceChange.occupancy)")
Expand Down
2 changes: 1 addition & 1 deletion Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ SPEC CHECKSUMS:

PODFILE CHECKSUM: 61a40240486621bb01f596fdd5bc632504940fab

COCOAPODS: 1.11.3
COCOAPODS: 1.13.0
80 changes: 66 additions & 14 deletions PubNub.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class DelayedHeartbeatEffect: DelayedEffectHandler {
case 1:
return 0.5 * Double(configuration.durationUntilTimeout)
case 2:
return Double(configuration.durationUntilTimeout) - 1.0
return 0.5 * Double(configuration.durationUntilTimeout) - 1.0
default:
return nil
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class PresenceHeartbeatRequest {
func execute(completionBlock: @escaping (Result<Void, PubNubError>) -> Void) {
request = session.request(with: PresenceRouter(
.heartbeat(channels: channels, groups: groups, presenceTimeout: configuration.durationUntilTimeout),
configuration: configuration), requestOperator: nil
configuration: configuration, eventEngineEnabled: true), requestOperator: nil
)
request?.validate().response(on: sessionResponseQueue, decoder: GenericServiceResponseDecoder()) { result in
switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class PresenceLeaveRequest {
func execute(completionBlock: @escaping (Result<Void, PubNubError>) -> Void) {
request = session.request(with: PresenceRouter(
.leave(channels: channels, groups: groups),
configuration: configuration), requestOperator: nil
configuration: configuration, eventEngineEnabled: true), requestOperator: nil
)
request?.validate().response(on: sessionResponseQueue, decoder: GenericServiceResponseDecoder()) { result in
switch result {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class PresenceTransition: TransitionProtocol {
case .left(_,_):
return !(state is Presence.HeartbeatInactive)
case .heartbeatSuccess:
return state is Presence.Heartbeating
return state is Presence.Heartbeating || state is Presence.HeartbeatReconnecting
case .heartbeatFailed(_):
return state is Presence.Heartbeating || state is Presence.HeartbeatReconnecting
case .heartbeatGiveUp(_):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,15 @@
import Foundation

struct SubscribeInput: Equatable {
let channels: [String: PubNubChannel]
let groups: [String: PubNubChannel]
private let channels: [String: PubNubChannel]
private let groups: [String: PubNubChannel]

init(channels: [PubNubChannel] = [], groups: [PubNubChannel] = []) {
self.channels = channels.reduce(into: [String: PubNubChannel]()) { r, channel in _ = r.insert(channel) }
self.groups = groups.reduce(into: [String: PubNubChannel]()) { r, channel in _ = r.insert(channel) }
}

private init(
channels: [String: PubNubChannel],
groups: [String: PubNubChannel]
) {
private init(channels: [String: PubNubChannel], groups: [String: PubNubChannel]) {
self.channels = channels
self.groups = groups
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ class SubscribeRequest {
timetoken: timetoken,
region: region?.description ?? nil,
heartbeat: configuration.durationUntilTimeout,
filter: configuration.filterExpression
filter: configuration.filterExpression,
eventEngineEnabled: true
), configuration: configuration
), requestOperator: nil
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ fileprivate extension SubscribeTransition {
), invocations: [
.managed(.emitStatus(change: Subscribe.ConnectionStatusChange(
oldStatus: state.connectionStatus,
newStatus: .connectionError(error.underlying),
newStatus: .connectionError,
error: error
)))
]
Expand Down Expand Up @@ -363,7 +363,7 @@ fileprivate extension SubscribeTransition {
), invocations: [
.managed(.emitStatus(change: Subscribe.ConnectionStatusChange(
oldStatus: state.connectionStatus,
newStatus: .disconnectedUnexpectedly(error.underlying),
newStatus: .disconnectedUnexpectedly,
error: error
)))
]
Expand Down
28 changes: 24 additions & 4 deletions Sources/PubNub/Events/Subscription/SubscriptionStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,30 @@

import Foundation

/// A channel or group that has successfully been subscribed or unsubscribed
public enum SubscriptionChangeEvent {
/// The channels or groups that have successfully been subscribed
case subscribed(channels: [PubNubChannel], groups: [PubNubChannel])
/// The response header for one or more subscription events
case responseHeader(
channels: [PubNubChannel], groups: [PubNubChannel], previous: SubscribeCursor?, next: SubscribeCursor?
)
/// The channels or groups that have successfully been unsubscribed
case unsubscribed(channels: [PubNubChannel], groups: [PubNubChannel])

/// Whether this event represents an actual change or contains no data
var didChange: Bool {
switch self {
case let .subscribed(channels, groups):
return !channels.isEmpty || !groups.isEmpty
case .responseHeader:
return false
case let .unsubscribed(channels, groups):
return !channels.isEmpty || !groups.isEmpty
}
}
}

/// Local events emitted from the Subscribe method
public enum PubNubSubscribeEvent {
/// The connection status of the PubNub subscription was changed
Expand Down Expand Up @@ -118,7 +142,6 @@ public final class CoreListener: BaseSubscriptionListener {
public var didReceiveBatchSubscription: (([SubscriptionEvent]) -> Void)?
/// Receiver for all subscription events
public var didReceiveSubscription: ((SubscriptionEvent) -> Void)?

/// Receiver for status (Connection & Error) events
public var didReceiveStatus: ((StatusEvent) -> Void)?
/// Receiver for presence events
Expand Down Expand Up @@ -215,12 +238,10 @@ public final class CoreListener: BaseSubscriptionListener {
self?.didReceiveMessage?(message)
case let .signalReceived(signal):
self?.didReceiveSignal?(signal)

case let .connectionStatusChanged(status):
self?.didReceiveStatus?(.success(status))
case let .presenceChanged(presence):
self?.didReceivePresence?(presence)

case let .uuidMetadataSet(metadata):
self?.didReceiveObjectMetadataEvent?(.setUUID(metadata))
case let .uuidMetadataRemoved(metadataId):
Expand All @@ -233,7 +254,6 @@ public final class CoreListener: BaseSubscriptionListener {
self?.didReceiveObjectMetadataEvent?(.setMembership(membership))
case let .membershipMetadataRemoved(membership):
self?.didReceiveObjectMetadataEvent?(.removedMembership(membership))

case let .messageActionAdded(action):
self?.didReceiveMessageAction?(.added(action))
case let .messageActionRemoved(action):
Expand Down
1 change: 1 addition & 0 deletions Sources/PubNub/Networking/HTTPRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ enum QueryKey: String {
case filter
case sort
case descending = "desc"
case eventEngine = "ee"
}

/// The PubNub Key requirement for a given Endpoint
Expand Down
10 changes: 9 additions & 1 deletion Sources/PubNub/Networking/Routers/PresenceRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ struct PresenceRouter: HTTPRouter {
}

// Init
init(_ endpoint: Endpoint, configuration: RouterConfiguration) {
init(_ endpoint: Endpoint, configuration: RouterConfiguration, eventEngineEnabled: Bool = false) {
self.endpoint = endpoint
self.configuration = configuration
self.eventEngineEnabled = eventEngineEnabled
}

var endpoint: Endpoint
var configuration: RouterConfiguration
var eventEngineEnabled: Bool

// Protocol Properties
var service: PubNubService {
Expand Down Expand Up @@ -143,8 +145,14 @@ struct PresenceRouter: HTTPRouter {
case let .heartbeat(_, groups, presenceTimeout):
query.appendIfNotEmpty(key: .channelGroup, value: groups)
query.appendIfPresent(key: .heartbeat, value: presenceTimeout?.description)
if eventEngineEnabled {
query.append(URLQueryItem(key: .eventEngine, value: nil))
}
case let .leave(_, groups):
query.appendIfNotEmpty(key: .channelGroup, value: groups)
if eventEngineEnabled {
query.append(URLQueryItem(key: .eventEngine, value: nil))
}
case let .hereNow(_, groups, includeUUIDs, includeState):
query.appendIfNotEmpty(key: .channelGroup, value: groups)
query.append(URLQueryItem(key: .disableUUIDs, value: (!includeUUIDs).stringNumber))
Expand Down
18 changes: 12 additions & 6 deletions Sources/PubNub/Networking/Routers/SubscribeRouter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,11 @@ import Foundation
struct SubscribeRouter: HTTPRouter {
// Nested Endpoint
enum Endpoint: CaseAccessible, CustomStringConvertible {
case subscribe(channels: [String], groups: [String],
timetoken: Timetoken?, region: String?,
heartbeat: UInt?, filter: String?)
case subscribe(
channels: [String], groups: [String],
timetoken: Timetoken?, region: String?,
heartbeat: UInt?, filter: String?, eventEngineEnabled: Bool
)

var description: String {
switch self {
Expand Down Expand Up @@ -66,7 +68,7 @@ struct SubscribeRouter: HTTPRouter {
let path: String

switch endpoint {
case let .subscribe(channels, _, _, _, _, _):
case let .subscribe(channels, _, _, _, _, _, _):
path = "/v2/subscribe/\(subscribeKey)/\(channels.commaOrCSVString.urlEncodeSlash)/0"
}

Expand All @@ -77,12 +79,16 @@ struct SubscribeRouter: HTTPRouter {
var query = defaultQueryItems

switch endpoint {
case let .subscribe(_, groups, timetoken, region, heartbeat, filter):
case let .subscribe(_, groups, timetoken, region, heartbeat, filter, eventEngineEnabled):
query.appendIfNotEmpty(key: .channelGroup, value: groups)
query.appendIfPresent(key: .timetokenShort, value: timetoken?.description)
query.appendIfPresent(key: .regionShort, value: region?.description)
query.appendIfPresent(key: .filterExpr, value: filter)
query.appendIfPresent(key: .heartbeat, value: heartbeat?.description)

if eventEngineEnabled {
query.append(URLQueryItem(key: .eventEngine, value: nil))
}
}

return .success(query)
Expand All @@ -91,7 +97,7 @@ struct SubscribeRouter: HTTPRouter {
// Validated
var validationErrorDetail: String? {
switch endpoint {
case let .subscribe(channels, groups, _, _, _, _):
case let .subscribe(channels, groups, _, _, _, _, _):
return isInvalidForReason(
(channels.isEmpty && groups.isEmpty, ErrorDescription.missingChannelsAnyGroups))
}
Expand Down
6 changes: 5 additions & 1 deletion Sources/PubNub/PubNubConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public struct PubNubConfiguration: Hashable {
heartbeatInterval: UInt = 0,
supressLeaveEvents: Bool = false,
requestMessageCountThreshold: UInt = 100,
filterExpression: String? = nil
filterExpression: String? = nil,
enableEventEngine: Bool = false
) {
guard userId.trimmingCharacters(in: .whitespacesAndNewlines).count > 0 else {
preconditionFailure("UserId should not be empty.")
Expand All @@ -127,6 +128,7 @@ public struct PubNubConfiguration: Hashable {
self.supressLeaveEvents = supressLeaveEvents
self.requestMessageCountThreshold = requestMessageCountThreshold
self.filterExpression = filterExpression
self.enableEventEngine = enableEventEngine
}

// swiftlint:disable:next line_length
Expand Down Expand Up @@ -220,6 +222,8 @@ public struct PubNubConfiguration: Hashable {
public var useInstanceId: Bool
/// Whether a request identifier should be included on outgoing requests
public var useRequestId: Bool
/// A flag describing whether to enable the new strategy for handling subscription loop
public var enableEventEngine: Bool = false
/// Reconnection policy which will be used if/when a request fails
public var automaticRetry: AutomaticRetry?
/// URLSessionConfiguration used for URLSession network events
Expand Down
25 changes: 18 additions & 7 deletions Sources/PubNub/Subscription/ConnectionStatus.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,16 @@ public enum ConnectionStatus: Equatable {
/// Explicit disconnect from a remote system
case disconnected
/// Unexpected disconnect from a remote system
case disconnectedUnexpectedly(PubNubError)
case disconnectedUnexpectedly
/// Unable to establish initial connection
case connectionError(PubNubError)
case connectionError

/// If the connection is connected or attempting to connect
public var isActive: Bool {
switch self {
case .connected:
return true
case .disconnected:
return false
case .connectionError(_):
return false
case .disconnectedUnexpectedly(_):
default:
return false
}
}
Expand All @@ -60,4 +56,19 @@ public enum ConnectionStatus: Equatable {
return false
}
}

func canTransition(to state: ConnectionStatus) -> Bool {
switch (self, state) {
case (.connected, .disconnected):
return true
case (.disconnected, .connected):
return true
case (.connected, .disconnectedUnexpectedly):
return true
case (.disconnected, .connectionError):
return true
default:
return false
}
}
}
Loading