Skip to content

Commit

Permalink
Easy configuration of global NetworkSession timeouts & more `URLSes…
Browse files Browse the repository at this point in the history
…sionConfiguration` convenience

Fixes #1

### NetworkRequestFactory configuratoin
`NetworkRequestSession.init` now accepts an `eventSession` parameter that is used solely when creating requests for `EventSource` & `EventPublusher` instances..  The parameter defaults to `nil` in which case it is coped from the standard `session` parameter. When copying the regular session it uses the new `URLSessionConfiguration.events()` convenience factory (see below).

### URLSessionConfiguration for “events”
Since Server-Sent Event requests have special requirements (e.g. long timeouts) a convenience extension factory method `events()` has been added. It creates a configuration sutiable for SSE streams.

### Global defaults
All of the defaults used by the `URLSessionConfiguration` extension factoires (both `rest()` and `events()`) now have configurable default values for easy global configuration.
  • Loading branch information
kdubb committed May 24, 2021
1 parent 77ad81f commit 1370e98
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 51 deletions.
31 changes: 6 additions & 25 deletions Sources/Sunday/NetworkRequestFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ public class NetworkRequestFactory: RequestFactory {

public let baseURL: URI.Template
public let session: NetworkSession
public let eventSession: NetworkSession
public let adapter: NetworkRequestAdapter?
public let requestQueue: DispatchQueue
public let mediaTypeEncoders: MediaTypeEncoders
Expand All @@ -34,13 +35,15 @@ public class NetworkRequestFactory: RequestFactory {
public init(
baseURL: URI.Template,
session: NetworkSession,
eventSession: NetworkSession? = nil,
adapter: NetworkRequestAdapter? = nil,
requestQueue: DispatchQueue = .global(qos: .utility),
mediaTypeEncoders: MediaTypeEncoders = .default,
mediaTypeDecoders: MediaTypeDecoders = .default
) {
self.baseURL = baseURL
self.session = session
self.eventSession = eventSession ?? session.copy(configuration: .events())
self.adapter = adapter
self.requestQueue = requestQueue
self.mediaTypeEncoders = mediaTypeEncoders
Expand Down Expand Up @@ -69,29 +72,6 @@ public class NetworkRequestFactory: RequestFactory {
session.close(cancelOutstandingTasks: true)
}

public func with(sessionConfiguration: URLSessionConfiguration) -> NetworkRequestFactory {
NetworkRequestFactory(
baseURL: baseURL,
adapter: adapter,
serverTrustPolicyManager: session.serverTrustPolicyManager,
sessionConfiguration: sessionConfiguration,
requestQueue: requestQueue,
mediaTypeEncoders: mediaTypeEncoders,
mediaTypeDecoders: mediaTypeDecoders
)
}

public func with(session: NetworkSession) -> NetworkRequestFactory {
NetworkRequestFactory(
baseURL: baseURL,
session: session,
adapter: adapter,
requestQueue: requestQueue,
mediaTypeEncoders: mediaTypeEncoders,
mediaTypeDecoders: mediaTypeDecoders
)
}

public func registerProblem(type: URL, problemType: Problem.Type) {
registerProblem(type: type.absoluteString, problemType: problemType)
}
Expand Down Expand Up @@ -380,7 +360,7 @@ public class NetworkRequestFactory: RequestFactory {

return EventSource(queue: requestQueue) { headers in
requestPublisher.flatMap { request in
self.session.dataTaskStreamPublisher(for: request.adding(httpHeaders: headers))
self.eventSession.dataTaskStreamPublisher(for: request.adding(httpHeaders: headers))
}
.eraseToAnyPublisher()
}
Expand Down Expand Up @@ -421,7 +401,7 @@ public class NetworkRequestFactory: RequestFactory {
return EventPublisher<D>(eventTypes: eventTypes, decoder: jsonDecoder, queue: requestQueue) { headers in

requestPublisher.flatMap { request in
self.session.dataTaskStreamPublisher(for: request.adding(httpHeaders: headers).with(timeoutInterval: 86400))
self.eventSession.dataTaskStreamPublisher(for: request.adding(httpHeaders: headers).with(timeoutInterval: 86400))
}
.eraseToAnyPublisher()

Expand All @@ -439,6 +419,7 @@ public class NetworkRequestFactory: RequestFactory {

public func close(cancelOutstandingRequests: Bool = true) {
session.close(cancelOutstandingTasks: cancelOutstandingRequests)
eventSession.close(cancelOutstandingTasks: cancelOutstandingRequests)
}

}
Expand Down
13 changes: 13 additions & 0 deletions Sources/Sunday/NetworkSession.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,19 @@ public class NetworkSession {
delegate.owner = self
}

public func copy(
configuration: URLSessionConfiguration? = nil,
serverTrustPolicyManager: ServerTrustPolicyManager? = nil,
delegate externalDelegate: URLSessionDelegate? = nil
) -> NetworkSession {

return NetworkSession(
configuration: configuration ?? self.session.configuration,
serverTrustPolicyManager: self.serverTrustPolicyManager,
delegate: self.delegate.delegate
)
}

public typealias DataTaskPublisher = URLSession.DataTaskPublisher

public func dataTaskPublisher(for request: URLRequest) -> DataTaskPublisher {
Expand Down
38 changes: 32 additions & 6 deletions Sources/Sunday/URLSessionConfigurations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ import Foundation

public extension URLSessionConfiguration {

static let restTimeoutIntervalForRequestDefault = TimeInterval(15)
static let restTimeoutIntervalForResourceDefault = TimeInterval(60)
static var restTimeoutIntervalForRequestDefault = TimeInterval(15)
static var restTimeoutIntervalForResourceDefault = TimeInterval(60)

static func rest(
from config: URLSessionConfiguration = .default,
requestTimeout: TimeInterval? = nil,
resourceTimeout: TimeInterval? = nil
requestTimeout: TimeInterval = restTimeoutIntervalForRequestDefault,
resourceTimeout: TimeInterval = restTimeoutIntervalForResourceDefault
) -> URLSessionConfiguration {

config.networkServiceType = .default
config.httpShouldUsePipelining = true
config.timeoutIntervalForRequest = requestTimeout ?? restTimeoutIntervalForRequestDefault
config.timeoutIntervalForResource = resourceTimeout ?? restTimeoutIntervalForResourceDefault
config.timeoutIntervalForRequest = requestTimeout
config.timeoutIntervalForResource = resourceTimeout
config.waitsForConnectivity = true
config.allowsExpensiveNetworkAccess = true
config.allowsConstrainedNetworkAccess = true
Expand All @@ -44,4 +44,30 @@ public extension URLSessionConfiguration {
return Self.rest(from: config, requestTimeout: timeout, resourceTimeout: timeout)
}


static var eventsTimeoutIntervalForRequestDefault = TimeInterval(180)
static var eventsTimeoutIntervalForResourceDefault = TimeInterval(600)

static func events(
from config: URLSessionConfiguration = .ephemeral,
requestTimeout: TimeInterval = eventsTimeoutIntervalForRequestDefault,
resourceTimeout: TimeInterval = eventsTimeoutIntervalForResourceDefault
) -> URLSessionConfiguration {

config.networkServiceType = .background
config.httpShouldUsePipelining = true
config.timeoutIntervalForRequest = requestTimeout
config.timeoutIntervalForResource = resourceTimeout
config.waitsForConnectivity = true
config.allowsExpensiveNetworkAccess = true
config.allowsConstrainedNetworkAccess = true
config.allowsCellularAccess = true

return config
}

static func events(from config: URLSessionConfiguration = .default, timeout: TimeInterval) -> URLSessionConfiguration {
return Self.events(from: config, requestTimeout: timeout, resourceTimeout: timeout)
}

}
20 changes: 0 additions & 20 deletions Tests/SundayTests/NetworkRequestFactoryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1016,24 +1016,4 @@ class NetworkRequestFactoryTests: XCTestCase {
waitForExpectations(timeout: 2.0, handler: nil)
}

func testFluent() {

let factory = NetworkRequestFactory(baseURL: "http://example.com", sessionConfiguration: .default)

let restConfig = URLSessionConfiguration.rest()
let restFactory = factory.with(sessionConfiguration: restConfig)

XCTAssertEqual(restFactory.session.session.configuration, restConfig)
}

func testFluent2() {

let factory = NetworkRequestFactory(baseURL: "http://example.com", sessionConfiguration: .default)

let restSession = NetworkSession(configuration: .rest())
let restFactory = factory.with(session: restSession)

XCTAssertEqual(restFactory.session.session.configuration, restSession.session.configuration)
}

}

0 comments on commit 1370e98

Please sign in to comment.