CommandLineToolkit
62 строки · 1.7 Кб
1import Dispatch
2import Foundation
3import Signals
4import Types
5
6public typealias SignalHandler = (Int32) -> ()
7
8private let syncQueue = DispatchQueue(label: "SignalHandling.syncQueue")
9private var signalHandlers = [Int32: [UUID: SignalHandler]]()
10
11// swiftlint:disable sync
12
13public final class SignalHandling {
14public struct Handle {
15var signal: Int32
16var id: UUID
17}
18
19private init() {}
20
21/// Captures and holds a given handler and invokes it when a required signal occurs.
22@discardableResult
23public static func addSignalHandler(signal: Signal, handler: @escaping SignalHandler) -> Handle {
24let id = UUID()
25
26syncQueue.sync {
27signalHandlers[signal.intValue, default: [:]][id] = handler
28}
29
30Signals.trap(signal: signal.blueSignal) { signalValue in
31_handleSignal(signalValue)
32}
33
34return Handle(signal: signal.intValue, id: id)
35}
36
37public static func removeSignalHandler(handle: Handle) {
38syncQueue.sync {
39signalHandlers[handle.signal]?[handle.id] = nil
40}
41}
42
43public static func listen(signal: Signal) -> AsyncStream<Signal> {
44AsyncStream { continuation in
45let handle = addSignalHandler(signal: signal) { signal in
46continuation.yield(.init(rawValue: signal))
47}
48
49continuation.onTermination = { _ in
50removeSignalHandler(handle: handle)
51}
52}
53}
54}
55
56/// Universal signal handler
57private func _handleSignal(_ signalValue: Int32) {
58let registeredHandlers = syncQueue.sync { signalHandlers[signalValue, default: [:]] }
59for (_, handler) in registeredHandlers {
60handler(signalValue)
61}
62}
63