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

Changes for proposal "Mocking Centrifuge Client for Testing Without a Server" #113

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
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
35 changes: 27 additions & 8 deletions Example/SwiftCentrifuge/ViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ class ViewController: UIViewController {
@IBOutlet weak var connectButton: UIButton!
@IBOutlet weak var resetReconnectStateButton: UIButton!

private var client: CentrifugeClient?
private var sub: CentrifugeSubscription?
private var client: SwiftCentrifuge.Client?
private var sub: SwiftCentrifuge.ClientSubscription?

override func viewDidLoad() {
super.viewDidLoad()

Expand All @@ -29,21 +29,38 @@ class ViewController: UIViewController {
NotificationCenter.default.addObserver(self, selector: #selector(self.connectClient(_:)), name: UIApplication.didBecomeActiveNotification, object: nil)

let config = CentrifugeClientConfig(
token: "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0c3VpdGVfand0In0.hPmHsVqvtY88PvK4EmJlcdwNuKFuy3BGaF7dMaKdPlw",
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0LXVzZXIiLCJleHAiOjE3MzczMTM1OTAsImlhdCI6MTczNjcwODc5MH0.4e0MRE0TnS6MsDtQasKq8FbL1AVRurWgH6qzW_i6sqA",
tokenGetter: self,
logger: PrintLogger()
)
let url = "ws://127.0.0.1:8000/connection/websocket?cf_protocol=protobuf"
self.client = CentrifugeClient(endpoint: url, config: config, delegate: self)
self.client = CentrifugeClient.newClient(endpoint: url, config: config, delegate: self)
self.subscribe()
}

func subscribe() {
guard sub == nil else { return }

let channel = "chat:index"

do {
sub = try self.client?.newSubscription(channel: "chat:index", delegate: self)
sub!.subscribe()
sub = try self.client?.newClientSubscription(channel: channel, delegate: self)
sub?.subscribe()
print("Created subscription to \"\(channel)\"")
} catch {
print("Can not create subscription: \(error)")
print("Can not create subscription to \"\(channel)\": \(error)")
return
}
}

func unsubscribe() {
guard let sub else { return }

client?.removeClientSubscription(sub)
self.sub = nil
print("Unsubscribed from \"\(sub.channel)\"")
}

override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
client?.connect()
Expand All @@ -55,10 +72,12 @@ class ViewController: UIViewController {
}

@objc func disconnectClient(_ notification: Notification) {
unsubscribe()
client?.disconnect()
}

@objc func connectClient(_ notification: Notification) {
subscribe()
client?.connect()
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/SwiftCentrifuge/Client.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public enum CentrifugeClientState {
case connected
}

public class CentrifugeClient {
public class CentrifugeClient: Client {
public weak var delegate: CentrifugeClientDelegate?

//MARK -
Expand Down
129 changes: 129 additions & 0 deletions Sources/SwiftCentrifuge/ClientProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
//
// Client.swift
// SwiftCentrifuge
//
// Created by shalom-aviv on 12/01/2025.
// Copyright © 2025 shalom-aviv. All rights reserved.
//

import Foundation

public protocol Client: AnyObject {
var delegate: CentrifugeClientDelegate? { get set }

var state: CentrifugeClientState { get }

func connect()

func disconnect()

func resetReconnectState()

func setToken(token: String)

func newSubscription(
channel: String,
delegate: CentrifugeSubscriptionDelegate,
config: CentrifugeSubscriptionConfig?
) throws -> CentrifugeSubscription

func getSubscription(channel: String) -> CentrifugeSubscription?

func removeSubscription(_ sub: CentrifugeSubscription)

func getSubscriptions() -> [String: CentrifugeSubscription]

func send(data: Data, completion: @escaping (Error?) -> Void)

func publish(channel: String, data: Data, completion: @escaping (Result<CentrifugePublishResult, Error>) -> Void)

func rpc(method: String, data: Data, completion: @escaping (Result<CentrifugeRpcResult, Error>) -> Void)

func presence(channel: String, completion: @escaping (Result<CentrifugePresenceResult, Error>) -> Void)

func presenceStats(channel: String, completion: @escaping (Result<CentrifugePresenceStatsResult, Error>) -> Void)

func history(
channel: String,
limit: Int32,
since: CentrifugeStreamPosition?,
reverse: Bool,
completion: @escaping (Result<CentrifugeHistoryResult, Error>) -> Void
)
}

public extension Client {
func newSubscription(channel: String, delegate: CentrifugeSubscriptionDelegate) throws -> CentrifugeSubscription {
try newSubscription(
channel: channel,
delegate: delegate,
config: nil
)
}

func history(
channel: String,
limit: Int32 = 0,
sincePosition: CentrifugeStreamPosition? = nil,
reverse: Bool = false,
completion: @escaping (Result<CentrifugeHistoryResult, Error>) -> Void
) {
history(
channel: channel,
limit: limit,
since: sincePosition,
reverse: reverse,
completion: completion
)
}
}

/// Adopt Client protocol to use protocol ClientSubscription instead of CentrifugeSubscription class
public extension Client {

func newClientSubscription(
channel: String,
delegate: CentrifugeSubscriptionDelegate,
config: CentrifugeSubscriptionConfig?
) throws -> CentrifugeSubscription {
try newSubscription(channel: channel, delegate: delegate, config: config)
}

func newClientSubscription(
channel: String,
delegate: CentrifugeSubscriptionDelegate
) throws -> CentrifugeSubscription {
try newClientSubscription(channel: channel, delegate: delegate, config: nil)
}

func getClientSubscription(channel: String) -> ClientSubscription? {
getSubscription(channel: channel)
}

func removeClientSubscription(_ sub: ClientSubscription) {
guard let sub = sub as? CentrifugeSubscription else { return }

removeSubscription(sub)
}

func getClientSubscription() -> [String: ClientSubscription] {
getSubscriptions()
}

}

public extension CentrifugeClient {
/// Static constructor that create CentrifugeClient and return it as Client protocol
///
/// - Parameters:
/// - url: protobuf URL endpoint of Centrifugo/Centrifuge.
/// - config: config object.
/// - delegate: delegate protocol implementation to react on client events.
static func newClient(endpoint: String, config: CentrifugeClientConfig, delegate: CentrifugeClientDelegate? = nil) -> Client {
CentrifugeClient(
endpoint: endpoint,
config: config,
delegate: delegate
)
}
}
48 changes: 48 additions & 0 deletions Sources/SwiftCentrifuge/ClientSubscriptionProtocol.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// ClientSubscription.swift
// SwiftCentrifuge
//
// Created by shalom-aviv on 12/01/2025.
// Copyright © 2025 shalom-aviv. All rights reserved.
//

import Foundation

public protocol ClientSubscription: AnyObject {
var channel: String { get }

var state: CentrifugeSubscriptionState { get set }

func subscribe()

func unsubscribe()

func publish(data: Data, completion: @escaping (Result<CentrifugePublishResult, Error>) -> Void)

func presence(completion: @escaping (Result<CentrifugePresenceResult, Error>) -> Void)

func presenceStats(completion: @escaping (Result<CentrifugePresenceStatsResult, Error>) -> Void)

func history(
limit: Int32,
since: CentrifugeStreamPosition?,
reverse: Bool,
completion: @escaping (Result<CentrifugeHistoryResult, Error>) -> Void
)
}

public extension ClientSubscription {
func history(
limit: Int32 = 0,
sincePosition: CentrifugeStreamPosition? = nil,
reverse: Bool = false,
completion: @escaping (Result<CentrifugeHistoryResult, Error>) -> Void
) {
history(
limit: limit,
since: sincePosition,
reverse: reverse,
completion: completion
)
}
}
Loading