11import Foundation
22import os. log
33
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-
754public class EventSource : NSObject , URLSessionDataDelegate {
765
776 private let config : Config
@@ -88,12 +17,13 @@ public class EventSource: NSObject, URLSessionDataDelegate {
8817 private var errorHandlerAction : ConnectionErrorAction ? = nil
8918 private let utf8LineParser : UTF8LineParser = UTF8LineParser ( )
9019 private var eventParser : EventParser !
20+ private var sessionTask : URLSessionDataTask ?
9121
9222 public init ( config: Config ) {
9323 self . config = config
9424 self . lastEventId = config. lastEventId
9525 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 " )
9727 }
9828
9929 public func start( ) {
@@ -107,6 +37,14 @@ public class EventSource: NSObject, URLSessionDataDelegate {
10737 }
10838 }
10939
40+ public func stop( ) {
41+ sessionTask? . cancel ( )
42+ if readyState == . open {
43+ config. handler. onClosed ( )
44+ }
45+ readyState = . shutdown
46+ }
47+
11048 public func getLastEventId( ) -> String ? { lastEventId }
11149
11250 private func connect( ) {
@@ -127,7 +65,9 @@ public class EventSource: NSObject, URLSessionDataDelegate {
12765 urlRequest. httpBody = self . config. body
12866 urlRequest. setValue ( self . lastEventId, forHTTPHeaderField: " Last-Event-ID " )
12967 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
13171 }
13272
13373 private func dispatchError( error: Error ) -> ConnectionErrorAction {
0 commit comments