Skip to content

Commit

Permalink
Subscribe & Presence Event Engine (#152)
Browse files Browse the repository at this point in the history
feat(subscribe & presence): introducing Subscribe & Presence EventEngine
  • Loading branch information
jguz-pubnub authored Jan 22, 2024
1 parent b47b478 commit 649a9e9
Show file tree
Hide file tree
Showing 79 changed files with 10,244 additions and 1,623 deletions.
9 changes: 7 additions & 2 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
---
name: swift
scm: github.com/pubnub/swift
version: "6.2.3"
version: "6.3.0"
schema: 1
changelog:
- date: 2024-01-22
version: 6.3.0
changes:
- type: feature
text: "Introducing Subscribe & Presence EventEngine."
- date: 2023-11-28
version: 6.2.3
changes:
Expand Down Expand Up @@ -512,7 +517,7 @@ sdks:
- distribution-type: source
distribution-repository: GitHub release
package-name: PubNub
location: https://github.com/pubnub/swift/archive/refs/tags/6.2.3.zip
location: https://github.com/pubnub/swift/archive/refs/tags/6.3.0.zip
supported-platforms:
supported-operating-systems:
macOS:
Expand Down
2 changes: 2 additions & 0 deletions Examples/Sources/MasterDetailTableViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,8 @@ class MasterDetailTableViewController: UITableViewController {
print("Status disconnected")
case .disconnectedUnexpectedly:
print("Status disconnected unexpectedly!")
case .connectionError:
print("Cannot establish initial conection to the remote system")
}
case let .subscriptionChanged(subscribeChange):
switch subscribeChange {
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.12.1
COCOAPODS: 1.14.3
332 changes: 320 additions & 12 deletions PubNub.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

7 changes: 6 additions & 1 deletion PubNubMembership/Sources/Membership+PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import PubNubUser
public protocol PubNubMembershipInterface {
/// A copy of the configuration object used for this session
var configuration: PubNubConfiguration { get }

/// Session used for performing request/response REST calls
var networkSession: SessionReplaceable { get }

Expand Down Expand Up @@ -268,6 +267,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchMultipleValueResponseDecoder<PubNubMembership.PartialSpace>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -320,6 +320,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchMultipleValueResponseDecoder<PubNubMembership.PartialUser>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -365,6 +366,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -401,6 +403,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -463,6 +466,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -499,6 +503,7 @@ public extension PubNubMembershipInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down
5 changes: 4 additions & 1 deletion PubNubSpace/Sources/Space+PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import PubNub
public protocol PubNubSpaceInterface {
/// A copy of the configuration object used for this session
var configuration: PubNubConfiguration { get }

/// Session used for performing request/response REST calls
var networkSession: SessionReplaceable { get }

Expand Down Expand Up @@ -213,6 +212,7 @@ public extension PubNubSpaceInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchMultipleValueResponseDecoder<PubNubSpace>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand All @@ -237,6 +237,7 @@ public extension PubNubSpaceInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchSingleValueResponseDecoder<PubNubSpace>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -273,6 +274,7 @@ public extension PubNubSpaceInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchSingleValueResponseDecoder<PubNubSpace>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -317,6 +319,7 @@ public extension PubNubSpaceInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down
2 changes: 1 addition & 1 deletion PubNubSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'PubNubSwift'
s.version = '6.2.3'
s.version = '6.3.0'
s.homepage = 'https://github.com/pubnub/swift'
s.documentation_url = 'https://www.pubnub.com/docs/swift-native/pubnub-swift-sdk'
s.authors = { 'PubNub, Inc.' => '[email protected]' }
Expand Down
6 changes: 4 additions & 2 deletions PubNubUser/Sources/User+PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,12 @@
//

import Foundation

import PubNub

/// Protocol interface to manage `PubNubUser` entities using closures
public protocol PubNubUserInterface {
/// A copy of the configuration object used for this session
var configuration: PubNubConfiguration { get }

/// Session used for performing request/response REST calls
var networkSession: SessionReplaceable { get }

Expand Down Expand Up @@ -221,6 +219,7 @@ public extension PubNubUserInterface {
(requestConfig.customSession ?? networkSession)?
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchMultipleValueResponseDecoder<PubNubUser>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -248,6 +247,7 @@ public extension PubNubUserInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchSingleValueResponseDecoder<PubNubUser>(),
responseQueue: requestConfig.responseQueue
) {
Expand Down Expand Up @@ -288,6 +288,7 @@ public extension PubNubUserInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchSingleValueResponseDecoder<PubNubUser>(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down Expand Up @@ -336,6 +337,7 @@ public extension PubNubUserInterface {
(requestConfig.customSession ?? networkSession)
.route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .appContext),
responseDecoder: FetchStatusResponseDecoder(),
responseQueue: requestConfig.responseQueue
) { result in
Expand Down
12 changes: 9 additions & 3 deletions Sources/PubNub/APIs/File+PubNub.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public extension PubNub {
) {
route(
FileManagementRouter(.list(channel: channel, limit: limit, next: next), configuration: configuration),
requestOperator: configuration.automaticRetry?.retryOperator(for: .files),
responseDecoder: FileListResponseDecoder(),
custom: requestConfig
) { result in
Expand Down Expand Up @@ -60,6 +61,7 @@ public extension PubNub {
) {
route(
FileManagementRouter(.delete(channel: channel, fileId: fileId, filename: filename), configuration: configuration),
requestOperator: configuration.automaticRetry?.retryOperator(for: .files),
responseDecoder: FileGeneralSuccessResponseDecoder(),
custom: requestConfig
) { result in
Expand Down Expand Up @@ -137,6 +139,7 @@ public extension PubNub {
.generateURL(channel: channel, body: .init(name: remoteFilename)),
configuration: configuration
),
requestOperator: configuration.automaticRetry?.retryOperator(for: .files),
responseDecoder: FileGenerateResponseDecoder(),
custom: requestConfig
) { [configuration] result in
Expand Down Expand Up @@ -225,9 +228,12 @@ public extension PubNub {
configuration: configuration
)

route(router,
responseDecoder: PublishResponseDecoder(),
custom: request.customRequestConfig) { result in
route(
router,
requestOperator: configuration.automaticRetry?.retryOperator(for: .files),
responseDecoder: PublishResponseDecoder(),
custom: request.customRequestConfig
) { result in
completion?(result.map { $0.payload.timetoken })
}
}
Expand Down
113 changes: 113 additions & 0 deletions Sources/PubNub/EventEngine/Core/Dispatcher.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
//
// Dispatcher.swift
//
// Copyright (c) PubNub Inc.
// All rights reserved.
//
// This source code is licensed under the license found in the
// LICENSE file in the root directory of this source tree.
//

import Foundation

// MARK: - DispatcherListener

struct DispatcherListener<Event> {
let onAnyInvocationCompleted: (([Event]) -> Void)
}

// MARK: - Dispatcher

protocol Dispatcher<Invocation, Event, Dependencies> {
associatedtype Invocation: AnyEffectInvocation
associatedtype Event
associatedtype Dependencies

func dispatch(
invocations: [EffectInvocation<Invocation>],
with dependencies: EventEngineDependencies<Dependencies>,
notify listener: DispatcherListener<Event>
)
}

// MARK: - EffectDispatcher

class EffectDispatcher<Invocation: AnyEffectInvocation, Event, Dependencies>: Dispatcher {
private let factory: any EffectHandlerFactory<Invocation, Event, Dependencies>
private let effectsCache = EffectsCache<Event>()

init(factory: some EffectHandlerFactory<Invocation, Event, Dependencies>) {
self.factory = factory
}

func hasPendingInvocation(_ invocation: Invocation) -> Bool {
effectsCache.hasPendingEffect(with: invocation.id)
}

func dispatch(
invocations: [EffectInvocation<Invocation>],
with dependencies: EventEngineDependencies<Dependencies>,
notify listener: DispatcherListener<Event>
) {
invocations.forEach {
switch $0 {
case .managed(let invocation):
executeEffect(
effect: factory.effect(for: invocation, with: dependencies),
storageId: invocation.id,
notify: listener
)
case .regular(let invocation):
executeEffect(
effect: factory.effect(for: invocation, with: dependencies),
storageId: UUID().uuidString,
notify: listener
)
case .cancel(let cancelInvocation):
effectsCache.getEffect(with: cancelInvocation.id)?.cancelTask()
effectsCache.removeEffect(id: cancelInvocation.id)
}
}
}

private func executeEffect(
effect: some EffectHandler<Event>,
storageId id: String,
notify listener: DispatcherListener<Event>
) {
effectsCache.put(effect: effect, with: id)
effect.performTask { [weak effectsCache] results in
effectsCache?.removeEffect(id: id)
listener.onAnyInvocationCompleted(results)
}
}
}

// MARK: - EffectsCache

fileprivate class EffectsCache<Event> {
private var managedEffects: Atomic<[String: EffectWrapper<Event>]> = Atomic([:])

func hasPendingEffect(with id: String) -> Bool {
managedEffects.lockedRead { $0[id] } != nil
}

func put(effect: some EffectHandler<Event>, with id: String) {
managedEffects.lockedWrite { $0[id] = EffectWrapper<Event>(id: id, effect: effect) }
}

func getEffect(with id: String) -> (any EffectHandler<Event>)? {
managedEffects.lockedRead() { $0[id] }?.effect
}

func removeEffect(id: String) {
managedEffects.lockedWrite { $0[id] = nil }
}
}

// MARK: - EffectWrapper

fileprivate struct EffectWrapper<Action> {
let id: String
let effect: any EffectHandler<Action>
}
Loading

0 comments on commit 649a9e9

Please sign in to comment.