2
2
//
3
3
// This source file is part of the RediStack open source project
4
4
//
5
- // Copyright (c) 2020 RediStack project authors
5
+ // Copyright (c) 2020-2022 RediStack project authors
6
6
// Licensed under Apache License v2.0
7
7
//
8
8
// See LICENSE.txt for license information
@@ -24,18 +24,44 @@ import NIO
24
24
/// - message: The message data that was received from the `publisher`.
25
25
public typealias RedisSubscriptionMessageReceiver = ( _ publisher: RedisChannelName , _ message: RESPValue ) -> Void
26
26
27
- /// A closure handler invoked for Pub/Sub subscription changes.
27
+ /// The details of the subscription change.
28
+ /// - Parameters:
29
+ /// - subscriptionKey: The subscribed channel or pattern that had its subscription status changed.
30
+ /// - currentSubscriptionCount: The current total number of subscriptions the connection has.
31
+ public typealias RedisSubscriptionChangeDetails = ( subscriptionKey: String , currentSubscriptionCount: Int )
32
+
33
+ /// A closure handler invoked for Pub/Sub subscribe commands.
34
+ ///
35
+ /// This closure will be invoked only *once* for each individual channel or pattern that is having its subscription changed,
36
+ /// even if it was done as a single PSUBSCRIBE or SUBSCRIBE command.
37
+ /// - Warning: The receiver is called on the same `NIO.EventLoop` that processed the message.
38
+ ///
39
+ /// If you are doing non-trivial work in response to PubSub messages, it is **highly recommended** that the work be dispatched to another thread
40
+ /// so as to not block further messages from being processed.
41
+ /// - Parameter details: The details of the subscription.
42
+ public typealias RedisSubscribeHandler = ( _ details: RedisSubscriptionChangeDetails ) -> Void
43
+
44
+ /// An enumeration of possible sources of Pub/Sub unsubscribe events.
45
+ public enum RedisUnsubscribeEventSource {
46
+ /// The client sent an unsubscribe command either as UNSUBSCRIBE or PUNSUBSCRIBE.
47
+ case userInitiated
48
+ /// The client encountered an error and had to unsubscribe.
49
+ /// - Parameter _: The error the client encountered.
50
+ case clientError( _ error: Error )
51
+ }
52
+
53
+ /// A closure handler invoked for Pub/Sub unsubscribe commands.
28
54
///
29
55
/// This closure will be invoked only *once* for each individual channel or pattern that is having its subscription changed,
30
- /// even if it was done as a single PSUBSCRIBE, SUBSCRIBE, PUNSUBSCRIBE, or UNSUBSCRIBE command.
56
+ /// even if it was done as a single PUNSUBSCRIBE or UNSUBSCRIBE command.
31
57
/// - Warning: The receiver is called on the same `NIO.EventLoop` that processed the message.
32
58
///
33
59
/// If you are doing non-trivial work in response to PubSub messages, it is **highly recommended** that the work be dispatched to another thread
34
60
/// so as to not block further messages from being processed.
35
61
/// - Parameters:
36
- /// - subscriptionKey : The subscribed channel or pattern that had its subscription status changed .
37
- /// - currentSubscriptionCount : The current total number of subscriptions the connection has .
38
- public typealias RedisSubscriptionChangeHandler = ( _ subscriptionKey : String , _ currentSubscriptionCount : Int ) -> Void
62
+ /// - details : The details of the subscription.
63
+ /// - source : The source of the unsubscribe event .
64
+ public typealias RedisUnsubscribeHandler = ( _ details : RedisSubscriptionChangeDetails , _ source : RedisUnsubscribeEventSource ) -> Void
39
65
40
66
/// A list of patterns or channels that a Pub/Sub subscription change is targetting.
41
67
///
@@ -146,7 +172,7 @@ extension RedisPubSubHandler {
146
172
147
173
guard let subscription = self . subscriptions [ prefixedKey] else { return }
148
174
149
- subscription. onSubscribe ? ( subscriptionKey, subscriptionCount)
175
+ subscription. onSubscribe ? ( ( subscriptionKey, subscriptionCount) )
150
176
subscription. onSubscribe = nil // nil to free memory
151
177
self . subscriptions [ prefixedKey] = subscription
152
178
@@ -161,8 +187,8 @@ extension RedisPubSubHandler {
161
187
) {
162
188
let prefixedKey = self . prefixKey ( subscriptionKey, with: keyPrefix)
163
189
guard let subscription = self . subscriptions. removeValue ( forKey: prefixedKey) else { return }
164
-
165
- subscription. onUnsubscribe ? ( subscriptionKey, subscriptionCount)
190
+
191
+ subscription. onUnsubscribe ? ( ( subscriptionKey, subscriptionCount) , . userInitiated )
166
192
subscription. type. gauge. decrement ( )
167
193
168
194
switch self . pendingUnsubscribes. removeValue ( forKey: prefixedKey) {
@@ -208,8 +234,8 @@ extension RedisPubSubHandler {
208
234
public func addSubscription(
209
235
for target: RedisSubscriptionTarget ,
210
236
messageReceiver receiver: @escaping RedisSubscriptionMessageReceiver ,
211
- onSubscribe subscribeHandler: RedisSubscriptionChangeHandler ? ,
212
- onUnsubscribe unsubscribeHandler: RedisSubscriptionChangeHandler ?
237
+ onSubscribe subscribeHandler: RedisSubscribeHandler ? ,
238
+ onUnsubscribe unsubscribeHandler: RedisUnsubscribeHandler ?
213
239
) -> EventLoopFuture < Int > {
214
240
guard self . eventLoop. inEventLoop else {
215
241
return self . eventLoop. flatSubmit {
@@ -481,7 +507,8 @@ extension RedisPubSubHandler: ChannelInboundHandler {
481
507
let receivers = self . subscriptions
482
508
self . subscriptions. removeAll ( )
483
509
receivers. forEach {
484
- $0. value. onUnsubscribe ? ( $0. key, 0 )
510
+ let source : RedisUnsubscribeEventSource = error. map { . clientError( $0) } ?? . userInitiated
511
+ $0. value. onUnsubscribe ? ( ( $0. key, 0 ) , source)
485
512
$0. value. type. gauge. decrement ( )
486
513
}
487
514
}
@@ -521,14 +548,14 @@ extension RedisPubSubHandler {
521
548
fileprivate final class Subscription {
522
549
let type : SubscriptionType
523
550
let onMessage : RedisSubscriptionMessageReceiver
524
- var onSubscribe : RedisSubscriptionChangeHandler ? // will be set to nil after first call
525
- let onUnsubscribe : RedisSubscriptionChangeHandler ?
551
+ var onSubscribe : RedisSubscribeHandler ? // will be set to nil after first call
552
+ let onUnsubscribe : RedisUnsubscribeHandler ?
526
553
527
554
init (
528
555
type: SubscriptionType ,
529
556
messageReceiver: @escaping RedisSubscriptionMessageReceiver ,
530
- subscribeHandler: RedisSubscriptionChangeHandler ? ,
531
- unsubscribeHandler: RedisSubscriptionChangeHandler ?
557
+ subscribeHandler: RedisSubscribeHandler ? ,
558
+ unsubscribeHandler: RedisUnsubscribeHandler ?
532
559
) {
533
560
self . type = type
534
561
self . onMessage = messageReceiver
0 commit comments