1
1
import Vapor
2
2
import APNS
3
+ #if canImport(Darwin)
3
4
import Foundation
5
+ #else
6
+ // JSONEncoder / JSONDecoder is not Sendable in scf, but is in Darwin...
7
+ // Import as `@preconcurrency` to fix warnings.
8
+ @preconcurrency import Foundation
9
+ #endif
4
10
import NIO
5
11
import NIOConcurrencyHelpers
6
12
7
13
public typealias APNSGenericClient = APNSClient < JSONDecoder , JSONEncoder >
8
14
9
- public class APNSContainers {
10
- public struct ID : Hashable , Codable {
15
+ public final class APNSContainers : Sendable {
16
+ public struct ID : Sendable , Hashable , Codable {
11
17
public let string : String
12
18
public init ( string: String ) {
13
19
self . string = string
14
20
}
15
21
}
16
22
17
- public final class Container {
23
+ public final class Container : Sendable {
18
24
public let configuration : APNSClientConfiguration
19
25
public let client : APNSGenericClient
20
26
21
- internal init ( configuration: APNSClientConfiguration , client: APNSGenericClient ) {
27
+ internal init ( configuration: APNSClientConfiguration , client: APNSGenericClient ) {
22
28
self . configuration = configuration
23
29
self . client = client
24
30
}
25
31
}
26
32
27
- private var containers : [ ID : Container ]
28
- private var defaultID : ID ?
29
- private var lock : NIOLock
33
+ private let storage : NIOLockedValueBox < ( containers: [ ID : Container ] , defaultID: ID ? ) >
30
34
31
35
init ( ) {
32
- self . containers = [ : ]
33
- self . lock = . init( )
36
+ storage = . init( ( containers: [ : ] , defaultID: nil ) )
34
37
}
35
38
36
39
public func syncShutdown( ) {
37
- self . lock. lock ( )
38
- defer { self . lock. unlock ( ) }
39
- do {
40
- try containers. forEach { key, container in
41
- try container. client. syncShutdown ( )
40
+ storage. withLockedValue {
41
+ do {
42
+ try $0. containers. values. forEach { container in
43
+ try container. client. syncShutdown ( )
44
+ }
45
+ } catch {
46
+ fatalError ( " Could not shutdown APNS Containers " )
42
47
}
43
- } catch {
44
- fatalError ( " Could not shutdown APNS Containers " )
45
48
}
46
49
}
47
50
}
@@ -57,42 +60,40 @@ extension APNSContainers {
57
60
as id: ID ,
58
61
isDefault: Bool ? = nil
59
62
) {
60
- self . lock. lock ( )
61
- defer { self . lock. unlock ( ) }
62
-
63
- self . containers [ id] = Container (
64
- configuration: config,
65
- client: APNSGenericClient (
63
+ storage. withLockedValue {
64
+ $0. containers [ id] = Container (
66
65
configuration: config,
67
- eventLoopGroupProvider: eventLoopGroupProvider,
68
- responseDecoder: responseDecoder,
69
- requestEncoder: requestEncoder,
70
- byteBufferAllocator: byteBufferAllocator
66
+ client: APNSGenericClient (
67
+ configuration: config,
68
+ eventLoopGroupProvider: eventLoopGroupProvider,
69
+ responseDecoder: responseDecoder,
70
+ requestEncoder: requestEncoder,
71
+ byteBufferAllocator: byteBufferAllocator
72
+ )
71
73
)
72
- )
73
74
74
- if isDefault == true || ( self . defaultID == nil && isDefault != false ) {
75
- self . defaultID = id
75
+ if isDefault == true || ( $0. defaultID == nil && isDefault != false ) {
76
+ $0. defaultID = id
77
+ }
76
78
}
77
79
}
78
80
79
81
public func `default`( to id: ID ) {
80
- self . lock . lock ( )
81
- defer { self . lock . unlock ( ) }
82
- self . defaultID = id
82
+ storage . withLockedValue {
83
+ $0 . defaultID = id
84
+ }
83
85
}
84
86
85
87
public func container( for id: ID ? = nil ) -> APNSContainers . Container ? {
86
- self . lock. lock ( )
87
- defer { self . lock. unlock ( ) }
88
- guard let id = id ?? self . defaultID else {
89
- return nil
88
+ storage. withLockedValue {
89
+ guard let id = id ?? $0. defaultID else {
90
+ return nil
91
+ }
92
+ return $0. containers [ id]
90
93
}
91
- return self . containers [ id]
92
94
}
93
95
94
96
public var container : APNSContainers . Container ? {
95
97
container ( )
96
98
}
97
99
}
98
-
0 commit comments