|
1 | 1 | extension PostgreSQLConnection {
|
2 |
| - internal func listen(_ channelName: String, handler: @escaping (String) throws -> ()) throws -> Future<Void> { |
3 |
| - closeHandlers.append({ conn in |
4 |
| - return conn.send([.query(.init(query: "UNLISTEN \"\(channelName)\";"))], onResponse: { _ in }) |
5 |
| - }) |
6 |
| - |
7 |
| - notificationHandlers[channelName] = { message in |
8 |
| - try handler(message) |
9 |
| - } |
10 |
| - return queue.enqueue([.query(.init(query: "LISTEN \"\(channelName)\";"))], onInput: { message in |
| 2 | + /// Begins listening for notifications on a channel. |
| 3 | + /// |
| 4 | + /// LISTEN "<channel name>" |
| 5 | + /// |
| 6 | + /// To subscribe to a channel, call `listen(...)` and provide the channel name. |
| 7 | + /// |
| 8 | + /// conn.listen("foo") { message in |
| 9 | + /// print(message) |
| 10 | + /// return true |
| 11 | + /// } |
| 12 | + /// |
| 13 | + /// Once a connection is listening, it may not be used to send further queries until `UNLISTEN` is sent. |
| 14 | + /// To unlisten, return `true` in the callback handler. Returning `false` will continue the subscription. |
| 15 | + /// |
| 16 | + /// See `notify(...)` to send messages. |
| 17 | + /// |
| 18 | + /// - parameters: |
| 19 | + /// - channelName: String identifier for the channel to subscribe to. |
| 20 | + /// - handler: Handles incoming String messages. Returning `true` here will end the subscription |
| 21 | + /// sending an `UNLISTEN` command. |
| 22 | + /// - returns: A future that signals completion of the `UNLISTEN` command. |
| 23 | + public func listen(_ channelName: String, handler: @escaping (String) throws -> (Bool)) -> Future<Void> { |
| 24 | + let promise = eventLoop.newPromise(Void.self) |
| 25 | + return queue.enqueue([.query(.init(query: "LISTEN \"\(channelName)\";"))]) { message in |
11 | 26 | switch message {
|
12 |
| - case let .notificationResponse(notification): |
13 |
| - try self.notificationHandlers[notification.channel]?(notification.message) |
14 |
| - default: |
15 |
| - break |
| 27 | + case .close: return false |
| 28 | + case .readyForQuery: return false |
| 29 | + case .notification(let notif): |
| 30 | + if try handler(notif.message) { |
| 31 | + self.simpleQuery("UNLISTEN \"\(channelName)\"").transform(to: ()).cascade(promise: promise) |
| 32 | + return true |
| 33 | + } else { |
| 34 | + return false |
| 35 | + } |
| 36 | + default: throw PostgreSQLError(identifier: "listen", reason: "Unexpected message during listen: \(message).") |
16 | 37 | }
|
17 |
| - return false |
18 |
| - }) |
19 |
| - } |
20 |
| - |
21 |
| - internal func notify(_ channelName: String, message: String) throws -> Future<Void> { |
22 |
| - return send([.query(.init(query: "NOTIFY \"\(channelName)\", '\(message)';"))]).map(to: Void.self, { _ in }) |
| 38 | + }.flatMap { promise.futureResult } |
23 | 39 | }
|
24 | 40 |
|
25 |
| - internal func unlisten(_ channelName: String, unlistenHandler: (() -> Void)? = nil) throws -> Future<Void> { |
26 |
| - notificationHandlers.removeValue(forKey: channelName) |
27 |
| - return send([.query(.init(query: "UNLISTEN \"\(channelName)\";"))], onResponse: { _ in unlistenHandler?() }) |
| 41 | + /// Sends a notification to a listening connection. Use in conjunction with `listen(...)`. |
| 42 | + /// |
| 43 | + /// NOTIFY "foo" 'hello' |
| 44 | + /// |
| 45 | + /// A single connection can be used to send notifications to as many channels as desired. |
| 46 | + /// |
| 47 | + /// conn.notify("foo", message: "hello") |
| 48 | + /// |
| 49 | + /// - parameters: |
| 50 | + /// - channelName: String identifier for the channel to send to. |
| 51 | + /// - message: String message to send to subscribers. |
| 52 | + /// - returns: A future that signals completion of the send. |
| 53 | + public func notify(_ channelName: String, message: String) -> Future<Void> { |
| 54 | + return simpleQuery("NOTIFY \"\(channelName)\", '\(message)'").transform(to: ()) |
28 | 55 | }
|
29 | 56 | }
|
| 57 | + |
0 commit comments