2
2
//
3
3
// This source file is part of the RediStack open source project
4
4
//
5
- // Copyright (c) 2019-2020 RediStack project authors
5
+ // Copyright (c) 2019-2022 RediStack project authors
6
6
// Licensed under Apache License v2.0
7
7
//
8
8
// See LICENSE.txt for license information
@@ -26,10 +26,10 @@ extension TimeAmount {
26
26
27
27
// MARK: Pipeline manipulation
28
28
29
- extension Channel {
29
+ extension ChannelPipeline {
30
30
/// Adds the baseline channel handlers needed to support sending and receiving messages in Redis Serialization Protocol (RESP) format to the pipeline.
31
31
///
32
- /// For implementation details, see `RedisMessageEncoder`, `RedisByteDecoder`, and `RedisCommandHandler`.
32
+ /// For implementation details, see `` RedisMessageEncoder`` , `` RedisByteDecoder`` , and `` RedisCommandHandler` `.
33
33
///
34
34
/// # Pipeline chart
35
35
/// RedisClient.send
@@ -62,20 +62,20 @@ extension Channel {
62
62
( RedisCommandHandler ( ) , " RediStack.CommandHandler " )
63
63
]
64
64
return . andAllSucceed(
65
- handlers. map { self . pipeline . addHandler ( $0, name: $1) } ,
65
+ handlers. map { self . addHandler ( $0, name: $1) } ,
66
66
on: self . eventLoop
67
67
)
68
68
}
69
69
70
70
/// Adds the channel handler that is responsible for handling everything related to Redis PubSub.
71
- /// - Important: The connection that manages this channel is responsible for removing the `RedisPubSubHandler`.
71
+ /// - Important: The connection that manages this channel is responsible for removing the `` RedisPubSubHandler` `.
72
72
///
73
73
/// # Discussion
74
74
/// PubSub responsibilities include managing subscription callbacks as well as parsing and dispatching messages received from Redis.
75
75
///
76
- /// For implementation details, see `RedisPubSubHandler`.
76
+ /// For implementation details, see `` RedisPubSubHandler` `.
77
77
///
78
- /// The handler will be inserted in the `NIO.ChannelPipeline` just before the `RedisCommandHandler` instance.
78
+ /// The handler will be inserted in the `NIO.ChannelPipeline` just before the `` RedisCommandHandler` ` instance.
79
79
///
80
80
/// # Pipeline chart
81
81
/// RedisClient.send
@@ -106,14 +106,38 @@ extension Channel {
106
106
/// | [ Socket.read ] | | [ Socket.write ] |
107
107
/// +-----------------+ +------------------+
108
108
/// - Returns: A `NIO.EventLoopFuture` that resolves the instance of the PubSubHandler that was added to the pipeline.
109
- public func addPubSubHandler( ) -> EventLoopFuture < RedisPubSubHandler > {
110
- return self . pipeline
111
- . handler ( type: RedisCommandHandler . self)
112
- . flatMap {
113
- let pubsubHandler = RedisPubSubHandler ( eventLoop: self . eventLoop)
114
- return self . pipeline
115
- . addHandler ( pubsubHandler, name: " RediStack.PubSubHandler " , position: . before( $0) )
116
- . map { pubsubHandler }
109
+ public func addRedisPubSubHandler( ) -> EventLoopFuture < RedisPubSubHandler > {
110
+ // first try to return the handler that already exists in the pipeline
111
+
112
+ return self . handler ( type: RedisPubSubHandler . self)
113
+ . flatMapError {
114
+ // if it doesn't exist, add it to the pipeline
115
+ guard
116
+ let error = $0 as? ChannelPipelineError ,
117
+ error == . notFound
118
+ else { return self . eventLoop. makeFailedFuture ( $0) }
119
+
120
+ return self . handler ( type: RedisCommandHandler . self)
121
+ . flatMap {
122
+ let pubsubHandler = RedisPubSubHandler ( eventLoop: self . eventLoop)
123
+ return self . addHandler ( pubsubHandler, name: " RediStack.PubSubHandler " , position: . before( $0) )
124
+ . map { pubsubHandler }
125
+ }
126
+ }
127
+ }
128
+
129
+ /// Removes the provided Redis PubSub handler.
130
+ /// - Returns: A `NIO.EventLoopFuture` that resolves when the handler was removed from the pipeline.
131
+ public func removeRedisPubSubHandler( _ handler: RedisPubSubHandler ) -> EventLoopFuture < Void > {
132
+ self . removeHandler ( handler)
133
+ . flatMapError {
134
+ // if it was already removed, then we can just succeed
135
+ guard
136
+ let error = $0 as? ChannelPipelineError ,
137
+ error == . alreadyRemoved
138
+ else { return self . eventLoop. makeFailedFuture ( $0) }
139
+
140
+ return self . eventLoop. makeSucceededVoidFuture ( )
117
141
}
118
142
}
119
143
}
@@ -124,9 +148,9 @@ extension ClientBootstrap {
124
148
/// Makes a new `ClientBootstrap` instance with a baseline Redis `Channel` pipeline
125
149
/// for sending and receiving messages in Redis Serialization Protocol (RESP) format.
126
150
///
127
- /// For implementation details, see `RedisMessageEncoder`, `RedisByteDecoder`, and `RedisCommandHandler`.
151
+ /// For implementation details, see `` RedisMessageEncoder`` , `` RedisByteDecoder`` , and `` RedisCommandHandler` `.
128
152
///
129
- /// See also `Channel .addBaseRedisHandlers()`.
153
+ /// See also `ChannelPipeline .addBaseRedisHandlers()`.
130
154
/// - Parameter group: The `EventLoopGroup` to create the `ClientBootstrap` with.
131
155
/// - Returns: A TCP connection with the base configuration of a `Channel` pipeline for RESP messages.
132
156
public static func makeRedisTCPClient( group: EventLoopGroup ) -> ClientBootstrap {
@@ -135,6 +159,6 @@ extension ClientBootstrap {
135
159
ChannelOptions . socket ( SocketOptionLevel ( SOL_SOCKET) , SO_REUSEADDR) ,
136
160
value: 1
137
161
)
138
- . channelInitializer { $0. addBaseRedisHandlers ( ) }
162
+ . channelInitializer { $0. pipeline . addBaseRedisHandlers ( ) }
139
163
}
140
164
}
0 commit comments