1
1
import Foundation
2
2
import os. log
3
3
4
- /// Error class that means the remote server returned an HTTP error.
5
- public class UnsuccessfulResponseError : Error {
6
- /// The HTTP response code received
7
- public let responseCode : Int
8
-
9
- public init ( responseCode: Int ) {
10
- self . responseCode = responseCode
11
- }
12
- }
13
-
14
- /// Protocol for an object that will receive SSE events.
15
- public protocol EventHandler {
16
- /// EventSource calls this method when the stream connection has been opened.
17
- func onOpened( )
18
- /// EventSource calls this method when the stream connection has been closed.
19
- func onClosed( )
20
- /// EventSource calls this method when it has received a new event from the stream.
21
- func onMessage( event: String , messageEvent: MessageEvent )
22
- /// EventSource calls this method when it has received a comment line from the stream
23
- /// (any line starting with a colon).
24
- func onComment( comment: String )
25
- /// This method will be called for all exceptions that occur on the socket connection
26
- /// (including an {@link UnsuccessfulResponseError} if the server returns an unexpected HTTP status),
27
- /// but only after the ConnectionErrorHandler (if any) has processed it. If you need to
28
- /// do anything that affects the state of the connection, use ConnectionErrorHandler.
29
- func onError( error: Error )
30
- }
31
-
32
- typealias ConnectionHandler = ( setReconnectionTime: ( TimeInterval ) -> ( ) , setLastEventId: ( String ) -> ( ) )
33
- /// Type for a function that will be notified when EventSource encounters a connection failure.
34
- /// This is different from onError in that it will not be called for other kinds of errors; also,
35
- /// it has the ability to tell EventSource to stop reconnecting.
36
- public typealias ConnectionErrorHandler = ( Error ) -> ConnectionErrorAction
37
-
38
- /// Potential actions a ConnectionErrorHandler can return
39
- public enum ConnectionErrorAction {
40
- /// Specifies that the error should be logged normally and dispatched to the EventHandler.
41
- /// Connection retrying will proceed normally if appropriate.
42
- case proceed
43
- /// Specifies that the connection should be immediately shut down and not retried. The error
44
- /// will not be dispatched to the EventHandler
45
- case shutdown
46
- }
47
-
48
- /// Enum values representing the states of an EventSource
49
- public enum ReadyState : String , Equatable {
50
- /// The EventSource has not been started yet.
51
- case raw
52
- /// The EventSource is attempting to make a connection.
53
- case connecting
54
- /// The EventSource is active and the EventSource is listening for events.
55
- case open
56
- /// The connection has been closed or has failed, and the EventSource will attempt to reconnect.
57
- case closed
58
- /// The connection has been permanently closed and will not reconnect.
59
- case shutdown
60
- }
61
-
62
- /// Struct representing received event from the stream.
63
- public struct MessageEvent : Equatable , Hashable {
64
- /// Returns the event data.
65
- public let data : String
66
- /// The last seen event id, or the event id set in the Config if none have been received.
67
- public let lastEventId : String ?
68
-
69
- public init ( data: String , lastEventId: String ? = nil ) {
70
- self . data = data
71
- self . lastEventId = lastEventId
72
- }
73
- }
74
-
75
4
public class EventSource : NSObject , URLSessionDataDelegate {
76
5
77
6
private let config : Config
@@ -88,12 +17,13 @@ public class EventSource: NSObject, URLSessionDataDelegate {
88
17
private var errorHandlerAction : ConnectionErrorAction ? = nil
89
18
private let utf8LineParser : UTF8LineParser = UTF8LineParser ( )
90
19
private var eventParser : EventParser !
20
+ private var sessionTask : URLSessionDataTask ?
91
21
92
22
public init ( config: Config ) {
93
23
self . config = config
94
24
self . lastEventId = config. lastEventId
95
25
self . reconnectTime = config. reconnectTime
96
- self . logger = OSLog ( subsystem: " com.launchdarkly.swift-event-source " , category: " LDEventSource " )
26
+ self . logger = OSLog ( subsystem: " com.launchdarkly.swift-eventsource " , category: " LDEventSource " )
97
27
}
98
28
99
29
public func start( ) {
@@ -107,6 +37,14 @@ public class EventSource: NSObject, URLSessionDataDelegate {
107
37
}
108
38
}
109
39
40
+ public func stop( ) {
41
+ sessionTask? . cancel ( )
42
+ if readyState == . open {
43
+ config. handler. onClosed ( )
44
+ }
45
+ readyState = . shutdown
46
+ }
47
+
110
48
public func getLastEventId( ) -> String ? { lastEventId }
111
49
112
50
private func connect( ) {
@@ -127,7 +65,9 @@ public class EventSource: NSObject, URLSessionDataDelegate {
127
65
urlRequest. httpBody = self . config. body
128
66
urlRequest. setValue ( self . lastEventId, forHTTPHeaderField: " Last-Event-ID " )
129
67
urlRequest. allHTTPHeaderFields? . merge ( self . config. headers, uniquingKeysWith: { $1 } )
130
- session. dataTask ( with: urlRequest) . resume ( )
68
+ let task = session. dataTask ( with: urlRequest)
69
+ task. resume ( )
70
+ sessionTask = task
131
71
}
132
72
133
73
private func dispatchError( error: Error ) -> ConnectionErrorAction {
0 commit comments