Skip to content

Commit 20ec21a

Browse files
committed
Add NIORedisConnection that handles combining all Channel handlers and actually connects to Redis
1 parent cb3b02d commit 20ec21a

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import NIO
2+
import NIOConcurrencyHelpers
3+
4+
public final class NIORedisConnection {
5+
/// The `EventLoop` this connection uses to execute commands on.
6+
public var eventLoop: EventLoop { return channel.eventLoop }
7+
8+
/// Has the connection been closed?
9+
public private(set) var isClosed = Atomic<Bool>(value: false)
10+
11+
internal let redisPipeline: RedisMessenger
12+
13+
private let channel: Channel
14+
15+
deinit { assert(!isClosed.load(), "Redis connection was not properly shut down!") }
16+
17+
/// Creates a new connection on the provided channel, using the handler for executing commands.
18+
/// - Important: Call `close()` before deinitializing to properly cleanup resources!
19+
init(channel: Channel, handler: RedisMessenger) {
20+
self.channel = channel
21+
self.redisPipeline = handler
22+
}
23+
24+
/// Closes the connection to Redis.
25+
public func close() {
26+
guard isClosed.exchange(with: true) else { return }
27+
28+
channel.close(promise: nil)
29+
}
30+
31+
/// Executes the desired command with the specified arguments.
32+
/// - Important: All arguments should be in `.bulkString` format.
33+
public func command(_ command: String, _ arguments: [RedisData] = []) -> EventLoopFuture<RedisData> {
34+
return send(.array([RedisData(bulk: command)] + arguments))
35+
.thenThrowing { response in
36+
switch response {
37+
case let .error(error): throw error
38+
default: return response
39+
}
40+
}
41+
}
42+
43+
private func send(_ message: RedisData) -> EventLoopFuture<RedisData> {
44+
// ensure the connection is still open
45+
guard !isClosed.load() else { return eventLoop.makeFailedFuture(error: RedisError.connectionClosed) }
46+
47+
// create a new promise to store
48+
let promise = eventLoop.makePromise(of: RedisData.self)
49+
50+
// cascade this enqueue to the newly created promise
51+
redisPipeline.enqueue(message).cascade(promise: promise)
52+
53+
return promise.futureResult
54+
}
55+
}

Sources/NIORedis/RedisError.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,9 @@ public struct RedisError: CustomDebugStringConvertible, CustomStringConvertible,
1818
debugDescription = "⚠️ Redis Error: \(reason)\n- id: \(name).\(identifier)\n\n\(Thread.callStackSymbols)"
1919
}
2020
}
21+
22+
extension RedisError {
23+
internal static var connectionClosed: RedisError {
24+
return RedisError(identifier: "connection", reason: "Connection was closed while trying to execute.")
25+
}
26+
}

0 commit comments

Comments
 (0)