Skip to content

Commit 9335390

Browse files
authored
Release 0.3.0 (#4)
## [0.3.0] - 2020-06-02 ### Added - Added `stop()` method to shutdown the EventSource connection. ### Changed - Logging `subsystem` renamed from `com.launchdarkly.swift-event-source` to `com.launchdarkly.swift-eventsource`
1 parent 5844672 commit 9335390

File tree

6 files changed

+103
-74
lines changed

6 files changed

+103
-74
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
All notable changes to the LaunchDarkly Swift EventSource library will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org).
44

5+
## [0.3.0] - 2020-06-02
6+
### Added
7+
- Added `stop()` method to shutdown the EventSource connection.
8+
### Changed
9+
- Logging `subsystem` renamed from `com.launchdarkly.swift-event-source` to `com.launchdarkly.swift-eventsource`
10+
511
## [0.2.0] - 2020-05-21
612
### Added
713
- Public constructors for `UnsuccessfulResponseError` and `MessageEvent` to allow consumers of the library to use them for unit tests.

LDSwiftEventSource.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = "LDSwiftEventSource"
3-
s.version = "0.2.0"
3+
s.version = "0.3.0"
44
s.summary = "Swift EventSource library"
55
s.homepage = "https://github.com/launchdarkly/swift-eventsource"
66
s.license = { :type => "Apache License, Version 2.0", :file => "LICENSE.txt" }

LDSwiftEventSource.xcodeproj/project.pbxproj

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
B495D4A8248652DF00AE9233 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = B495D4A7248652DF00AE9233 /* Types.swift */; };
11+
B495D4A9248652DF00AE9233 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = B495D4A7248652DF00AE9233 /* Types.swift */; };
12+
B495D4AA248652DF00AE9233 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = B495D4A7248652DF00AE9233 /* Types.swift */; };
13+
B495D4AB248652DF00AE9233 /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = B495D4A7248652DF00AE9233 /* Types.swift */; };
1014
B49B5DE924667D07008BF867 /* LDSwiftEventSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B49B5DE024667D06008BF867 /* LDSwiftEventSource.framework */; };
1115
B49B5E2124667D5E008BF867 /* LDSwiftEventSource.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B49B5E1824667D5E008BF867 /* LDSwiftEventSource.framework */; };
1216
B49B5E4824667F59008BF867 /* UTF8LineParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = B49B5E4524667F43008BF867 /* UTF8LineParser.swift */; };
@@ -65,6 +69,7 @@
6569
/* End PBXContainerItemProxy section */
6670

6771
/* Begin PBXFileReference section */
72+
B495D4A7248652DF00AE9233 /* Types.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = "<group>"; };
6873
B49B5DE024667D06008BF867 /* LDSwiftEventSource.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LDSwiftEventSource.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6974
B49B5DE324667D06008BF867 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7075
B49B5DE824667D07008BF867 /* LDSwiftEventSource iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "LDSwiftEventSource iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -188,6 +193,7 @@
188193
B49B5E4624667F43008BF867 /* EventParser.swift */,
189194
B49B5E4724667F43008BF867 /* LDSwiftEventSource.swift */,
190195
B49B5E65246684B9008BF867 /* LDSwiftEventSource.h */,
196+
B495D4A7248652DF00AE9233 /* Types.swift */,
191197
);
192198
path = Source;
193199
sourceTree = "<group>";
@@ -484,6 +490,7 @@
484490
buildActionMask = 2147483647;
485491
files = (
486492
B49B5E4824667F59008BF867 /* UTF8LineParser.swift in Sources */,
493+
B495D4A8248652DF00AE9233 /* Types.swift in Sources */,
487494
B49B5E4924667F59008BF867 /* EventParser.swift in Sources */,
488495
B49B5E4A24667F59008BF867 /* LDSwiftEventSource.swift in Sources */,
489496
);
@@ -505,6 +512,7 @@
505512
buildActionMask = 2147483647;
506513
files = (
507514
B49B5E4B24667F62008BF867 /* UTF8LineParser.swift in Sources */,
515+
B495D4A9248652DF00AE9233 /* Types.swift in Sources */,
508516
B49B5E4C24667F62008BF867 /* EventParser.swift in Sources */,
509517
B49B5E4D24667F62008BF867 /* LDSwiftEventSource.swift in Sources */,
510518
);
@@ -526,6 +534,7 @@
526534
buildActionMask = 2147483647;
527535
files = (
528536
B49B5E4E24667F67008BF867 /* UTF8LineParser.swift in Sources */,
537+
B495D4AA248652DF00AE9233 /* Types.swift in Sources */,
529538
B49B5E4F24667F67008BF867 /* EventParser.swift in Sources */,
530539
B49B5E5024667F67008BF867 /* LDSwiftEventSource.swift in Sources */,
531540
);
@@ -547,6 +556,7 @@
547556
buildActionMask = 2147483647;
548557
files = (
549558
B49B5E5124667F72008BF867 /* UTF8LineParser.swift in Sources */,
559+
B495D4AB248652DF00AE9233 /* Types.swift in Sources */,
550560
B49B5E5224667F72008BF867 /* EventParser.swift in Sources */,
551561
B49B5E5324667F72008BF867 /* LDSwiftEventSource.swift in Sources */,
552562
);

Source/EventParser.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import Foundation
22

3+
typealias ConnectionHandler = (setReconnectionTime: (TimeInterval) -> (), setLastEventId: (String) -> ())
4+
35
class EventParser {
46
private struct Constants {
57
static let dataLabel: Substring = "data"

Source/LDSwiftEventSource.swift

Lines changed: 13 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,77 +1,6 @@
11
import Foundation
22
import 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-
754
public 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 {

Source/Types.swift

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import Foundation
2+
3+
/// Type for a function that will be notified when EventSource encounters a connection failure.
4+
/// This is different from onError in that it will not be called for other kinds of errors; also,
5+
/// it has the ability to tell EventSource to stop reconnecting.
6+
public typealias ConnectionErrorHandler = (Error) -> ConnectionErrorAction
7+
8+
/// Potential actions a ConnectionErrorHandler can return
9+
public enum ConnectionErrorAction {
10+
/// Specifies that the error should be logged normally and dispatched to the EventHandler.
11+
/// Connection retrying will proceed normally if appropriate.
12+
case proceed
13+
/// Specifies that the connection should be immediately shut down and not retried. The error
14+
/// will not be dispatched to the EventHandler
15+
case shutdown
16+
}
17+
18+
/// Struct representing received event from the stream.
19+
public struct MessageEvent: Equatable, Hashable {
20+
/// Returns the event data.
21+
public let data: String
22+
/// The last seen event id, or the event id set in the Config if none have been received.
23+
public let lastEventId: String?
24+
25+
public init(data: String, lastEventId: String? = nil) {
26+
self.data = data
27+
self.lastEventId = lastEventId
28+
}
29+
}
30+
31+
/// Protocol for an object that will receive SSE events.
32+
public protocol EventHandler {
33+
/// EventSource calls this method when the stream connection has been opened.
34+
func onOpened()
35+
/// EventSource calls this method when the stream connection has been closed.
36+
func onClosed()
37+
/// EventSource calls this method when it has received a new event from the stream.
38+
func onMessage(event: String, messageEvent: MessageEvent)
39+
/// EventSource calls this method when it has received a comment line from the stream
40+
/// (any line starting with a colon).
41+
func onComment(comment: String)
42+
/// This method will be called for all exceptions that occur on the socket connection
43+
/// (including an {@link UnsuccessfulResponseError} if the server returns an unexpected HTTP status),
44+
/// but only after the ConnectionErrorHandler (if any) has processed it. If you need to
45+
/// do anything that affects the state of the connection, use ConnectionErrorHandler.
46+
func onError(error: Error)
47+
}
48+
49+
/// Enum values representing the states of an EventSource
50+
public enum ReadyState: String, Equatable {
51+
/// The EventSource has not been started yet.
52+
case raw
53+
/// The EventSource is attempting to make a connection.
54+
case connecting
55+
/// The EventSource is active and the EventSource is listening for events.
56+
case open
57+
/// The connection has been closed or has failed, and the EventSource will attempt to reconnect.
58+
case closed
59+
/// The connection has been permanently closed and will not reconnect.
60+
case shutdown
61+
}
62+
63+
/// Error class that means the remote server returned an HTTP error.
64+
public class UnsuccessfulResponseError: Error {
65+
/// The HTTP response code received
66+
public let responseCode: Int
67+
68+
public init(responseCode: Int) {
69+
self.responseCode = responseCode
70+
}
71+
}

0 commit comments

Comments
 (0)