Skip to content

Instantly share code, notes, and snippets.

@storoj
Created June 29, 2023 00:05
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save storoj/bc5c0d24dde6b5bb0b5f7fe2706c61e9 to your computer and use it in GitHub Desktop.
Save storoj/bc5c0d24dde6b5bb0b5f7fe2706c61e9 to your computer and use it in GitHub Desktop.
import notify
import Combine
enum Notify {}
extension Notify {
struct Status: Error {
let rawValue: UInt32
init(_ rawValue: UInt32) {
self.rawValue = rawValue
}
func ok() throws {
guard rawValue == NOTIFY_STATUS_OK else { throw self }
}
}
}
extension Notify {
struct Token {
typealias State = UInt64
typealias RawValue = Int32
var rawValue: RawValue = NOTIFY_TOKEN_INVALID
init(_ rawValue: RawValue) {
self.rawValue = rawValue
}
init(dispatch name: String, queue: DispatchQueue = .main, handler: @escaping notify_handler_t) throws {
try Status(notify_register_dispatch(name, &rawValue, queue, handler)).ok()
}
init(check name: String) throws {
try Status(notify_register_check(name, &rawValue)).ok()
}
func state() throws -> State {
var state: State = 0
try Status(notify_get_state(rawValue, &state)).ok()
return state
}
func cancel() throws {
try Status(notify_cancel(rawValue)).ok()
}
}
}
extension Notify {
class Listener {
private class Helper {
let name: String
var token: Token?
let publisher = PassthroughSubject<UInt64, Status>()
init(name: String) {
self.name = name
}
func subscribe() {
do {
token = try Token(dispatch: name) { [publisher] token in
do {
publisher.send(try Token(token).state())
} catch {
publisher.send(completion: .failure(error as! Status))
}
}
} catch {
publisher.send(completion: .failure(error as! Status))
}
}
func cancel() {
try? token?.cancel()
}
func value() throws -> UInt64 {
try Token(check: name).state()
}
}
private let helper: Helper
init(name: String) {
helper = Helper(name: name)
}
func value() throws -> UInt64 {
try helper.value()
}
lazy var publisher: AnyPublisher<UInt64, Status> = {
helper.publisher
.handleEvents(receiveSubscription: { [helper] sub in
helper.subscribe()
}, receiveCancel: helper.cancel)
.share()
.eraseToAnyPublisher()
}()
}
}
@storoj
Copy link
Author

storoj commented Jun 29, 2023

Usage:

let listener = try Notify.Listener(name: "notification_name") // throws Notify.Status

try listener.value() // get momentary value
listener.publisher.sink { ... } // Combine publisher

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment