punchnet-macos/punchnet/Core/DarwinNotificationCenter.swift

113 lines
3.1 KiB
Swift

//
// DarwinNotificationName.swift
// punchnet
//
// Created by on 2026/4/3.
//
import Foundation
// MARK: - Darwin Notification Name
public struct DarwinNotificationName: RawRepresentable, Hashable {
public let rawValue: String
public init(rawValue: String) {
self.rawValue = rawValue
}
}
//
extension DarwinNotificationName {
static let vpnStatusChanged = DarwinNotificationName(rawValue: "com.jihe.punchnetmac.vpnStatusChanged")
}
// MARK: - Manager
public final class DarwinNotificationCenter {
public static let shared = DarwinNotificationCenter()
private let center = CFNotificationCenterGetDarwinNotifyCenter()
private var observers: [DarwinNotificationName: (DarwinNotificationName) -> Void] = [:]
private let lock = NSLock()
private init() {}
// MARK: - Add Observer
public func addObserver(for name: DarwinNotificationName, queue: DispatchQueue = .main, using block: @escaping (DarwinNotificationName) -> Void ) {
lock.lock()
defer {
lock.unlock()
}
if observers[name] == nil {
// Darwin Center
CFNotificationCenterAddObserver(
center,
UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
{ (_, observer, cfName, _, _) in
guard let observer, let cfName else {
return
}
let instance = Unmanaged<DarwinNotificationCenter>
.fromOpaque(observer)
.takeUnretainedValue()
let name = DarwinNotificationName(rawValue: cfName.rawValue as String)
instance.handle(name: name)
},
name.rawValue as CFString,
nil,
.deliverImmediately
)
observers[name] = { n in
queue.async {
block(n)
}
}
}
}
// MARK: - Remove Observer
public func removeObserver(for name: DarwinNotificationName) {
lock.lock()
defer {
lock.unlock()
}
if observers[name] != nil {
CFNotificationCenterRemoveObserver(
center,
UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque()),
CFNotificationName(name.rawValue as CFString),
nil
)
}
observers.removeValue(forKey: name)
}
// MARK: - Post
public func post(_ name: DarwinNotificationName) {
CFNotificationCenterPostNotification(
center,
CFNotificationName(name.rawValue as CFString),
nil,
nil,
true
)
}
// MARK: - Handle
private func handle(name: DarwinNotificationName) {
lock.lock()
let block = observers[name]
lock.unlock()
block?(name)
}
}