-
Notifications
You must be signed in to change notification settings - Fork 33
Added support for Notifications that use DispatchSource #59
base: master
Are you sure you want to change the base?
Changes from 6 commits
fbff23b
df578b7
0837a50
38e9728
d5ac0a4
ec2116a
9ccf4a2
e2491ca
e85f737
3ea5e82
85128d9
455a3bc
dae1219
62de864
b127f46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -152,6 +152,15 @@ public final class Connection: ConnInfoInitializable { | |
public let channel: String | ||
public let payload: String? | ||
|
||
/// initializer usable without knowledge of CPostgreSQL | ||
/// required to allow unit testing of classes using Notifications | ||
public init(pid: Int, channel: String, payload: String?) { | ||
self.pid = pid | ||
self.channel = channel | ||
self.payload = payload | ||
} | ||
|
||
/// internal initializer | ||
init(pgNotify: PGnotify) { | ||
channel = String(cString: pgNotify.relname) | ||
pid = Int(pgNotify.be_pid) | ||
|
@@ -171,6 +180,37 @@ public final class Connection: ConnInfoInitializable { | |
} | ||
} | ||
|
||
/// Creates a dispatch read source for this connection that will call `callback` on `queue` when a notification is received | ||
/// | ||
/// - Parameter channel: the channel to register for | ||
/// - Parameter queue: the queue to create the DispatchSource on | ||
/// - Parameter callback: the callback | ||
/// - Parameter note: The notification received from the database | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why? If you comment them that way, option clicking on the listen function shows them in a nested table underneath the callback parameter. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok sorry, didn’t know it worked like that. |
||
/// - Parameter err: Any error while reading the notification. If not nil, the source will have been canceled | ||
/// - Returns: the dispatch socket to activate | ||
/// - Throws: if fails to get the socket for the connection | ||
public func makeListenDispatchSource(toChannel channel: String, queue: DispatchQueue, callback: @escaping (_ note: Notification?, _ err: Error?) -> Void) throws -> DispatchSourceRead { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would simply call this function There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. I'd just copied Apple's naming convention. Better to use a swifty one. |
||
guard let sock = Optional.some(PQsocket(self.cConnection)), sock >= 0 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems a bit strange, why create an optional out of something not optional. Also, there is a callback, I would use this callback in case of an error. This way you can remove let sock = PQsocket(cConnection)
guard sock >= 0 else {
let error = PostgreSQLError(code: .ioError, reason: "failed to get socket for connection")
callback(nil, error)
return
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The optional allows using it in a guard statement. I try to put all precondition guards at the top of the function. I'll change. It can't just return because it returns a non-optional DispatchSource. That's why it throws. Better to explicitly generate an error instead of returning nil. |
||
else { throw PostgreSQLError(code: .ioError, reason: "failed to get socket for connection") } | ||
let src = DispatchSource.makeReadSource(fileDescriptor: sock, queue: queue) | ||
src.setEventHandler { [unowned self] in | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Using src.setEventHandler { [weak self] in
guard let strongSelf = self else {
return
}
// Use strongSelf instead of self
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
do { | ||
try self.validateConnection() | ||
PQconsumeInput(self.cConnection) | ||
while let pgNotify = PQnotifies(self.cConnection) { | ||
let notification = Notification(pgNotify: pgNotify.pointee) | ||
callback(notification, nil) | ||
PQfreemem(pgNotify) | ||
} | ||
} catch { | ||
callback(nil, error) | ||
src.cancel() | ||
} | ||
} | ||
try self.execute("LISTEN \(channel)") | ||
return src | ||
} | ||
|
||
/// Registers as a listener on a specific notification channel. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Considering the new method should be the way to go, I would mark the old function as deprecated. |
||
/// | ||
/// - Parameters: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You do not need to make this
init
public. If you do@testable import
, it should just work. This struct should not be initializable outside of this library.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll remove that change