Skip to content

Commit

Permalink
Use 2 spaces/tab
Browse files Browse the repository at this point in the history
  • Loading branch information
danthorpe committed Oct 19, 2023
1 parent 033b997 commit 9abd7d3
Show file tree
Hide file tree
Showing 67 changed files with 2,668 additions and 2,668 deletions.
534 changes: 267 additions & 267 deletions Package.swift

Large diffs are not rendered by default.

26 changes: 13 additions & 13 deletions Sources/Networking/Bodies/DataBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,17 @@ import Foundation
import HTTPTypes

public struct DataBody: HTTPRequestBody {
private let data: Data
public let additionalHeaders: HTTPFields

public var isEmpty: Bool { data.isEmpty }

public init(data: Data, additionalHeaders: HTTPFields) {
self.data = data
self.additionalHeaders = additionalHeaders
}

public func encode() throws -> Data {
data
}
private let data: Data
public let additionalHeaders: HTTPFields
public var isEmpty: Bool { data.isEmpty }
public init(data: Data, additionalHeaders: HTTPFields) {
self.data = data
self.additionalHeaders = additionalHeaders
}
public func encode() throws -> Data {
data
}
}
10 changes: 5 additions & 5 deletions Sources/Networking/Bodies/EmptyBody.swift
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import Foundation

public struct EmptyBody: HTTPRequestBody {
public let isEmpty = true
public init() { }
public func encode() throws -> Data {
Data()
}
public let isEmpty = true
public init() { }
public func encode() throws -> Data {
Data()
}
}
24 changes: 12 additions & 12 deletions Sources/Networking/Bodies/JSONBody.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import Foundation
import HTTPTypes

public struct JSONBody: HTTPRequestBody {
public let isEmpty = false
public var additionalHeaders: HTTPFields = [
.contentType: "application/json; charset=utf-8"
]
private let _encode: () throws -> Data
public init<Body: Encodable>(_ value: Body, encoder: JSONEncoder = JSONEncoder()) {
_encode = { try encoder.encode(value) }
}

public func encode() throws -> Data {
try _encode()
}
public let isEmpty = false
public var additionalHeaders: HTTPFields = [
.contentType: "application/json; charset=utf-8"
]
private let _encode: () throws -> Data
public init<Body: Encodable>(_ value: Body, encoder: JSONEncoder = JSONEncoder()) {
_encode = { try encoder.encode(value) }
}
public func encode() throws -> Data {
try _encode()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ extension NetworkingComponent {
struct Authentication<Delegate: AuthenticationDelegate>: NetworkingModifier {
typealias Credentials = Delegate.Credentials
let delegate: Delegate

func send(upstream: NetworkingComponent, request: HTTPRequestData) -> ResponseStream<HTTPResponseData> {
guard let method = request.authenticationMethod, method == Credentials.method else {
return upstream.send(request)
}
return ResponseStream { continuation in
Task {

// Fetch the initial credentials
var credentials: Credentials
do {
Expand All @@ -32,10 +32,10 @@ struct Authentication<Delegate: AuthenticationDelegate>: NetworkingModifier {
)
return
}

// Update the request to use the credentials
let newRequest = credentials.apply(to: request)

// Process the stream
do {
for try await event in upstream.send(newRequest) {
Expand All @@ -55,7 +55,7 @@ struct Authentication<Delegate: AuthenticationDelegate>: NetworkingModifier {
}
}
}

func refresh(
unauthorized credentials: inout Credentials,
response: HTTPResponseData,
Expand Down Expand Up @@ -99,7 +99,7 @@ extension AuthenticationError: NetworkingError {
return response.request
}
}

public var response: HTTPResponseData? {
switch self {
case .fetchCredentialsFailed:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
/// A system which can asynchronously fetch or refresh credentials
/// in order to make authenticated HTTP requests
public protocol AuthenticationDelegate<Credentials>: Sendable { // swiftlint:disable:this class_delegate_protocol

/// A type which represents the credentials to be used
associatedtype Credentials: AuthenticatingCredentials

/// The entry point into the authentication flow
///
/// Conforming types should manage their own state, providing thread safety
/// and perform whatever actions are necessary to retreive credentials from
/// an external system. For example - present a login interface to the user
/// to collect a username and password.
func fetch(for request: HTTPRequestData) async throws -> Credentials

/// After supplying a request with credentials, it is still possible to
/// encounter HTTP unauthorized errors. In such an event, this method will
/// be called, allowing for a single attempt to retry with a new set of
Expand All @@ -22,10 +22,10 @@ public protocol AuthenticationDelegate<Credentials>: Sendable { // swiftlint:dis
}

public protocol AuthenticatingCredentials: Hashable, Sendable {

/// The authentication method
static var method: AuthenticationMethod { get }

/// Create a new request making use of the credentials in whichever way
/// suits their purpose. E.g. by appending a query parameter
func apply(to request: HTTPRequestData) -> HTTPRequestData
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
public struct AuthenticationMethod: Hashable, RawRepresentable, Sendable, HTTPRequestDataOption {
public static let defaultOption: Self? = nil

public let rawValue: String

public init(rawValue: String) {
self.rawValue = rawValue
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extension AuthenticationMethod {
public struct BasicCredentials: Hashable, Sendable, AuthenticatingCredentials, HTTPRequestDataOption {
public static var method: AuthenticationMethod = .basic
public static let defaultOption: Self? = nil

public let user: String
public let password: String

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@ extension AuthenticationMethod {
public struct BearerCredentials: Hashable, Sendable, Codable, HTTPRequestDataOption, AuthenticatingCredentials {
public static let method: AuthenticationMethod = .bearer
public static let defaultOption: Self? = nil

public let token: String

public init(token: String) {
self.token = token
}

public func apply(to request: HTTPRequestData) -> HTTPRequestData {
var copy = request
copy.headerFields[.authorization] = "Bearer \(token)"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
public struct HeaderBasedAuthentication<Delegate: AuthenticationDelegate> {
actor StateMachine: AuthenticationDelegate {
typealias Credentials = Delegate.Credentials

private enum State {
case idle
case fetching(Task<Credentials, Error>)
case authorized(Credentials)
}

let delegate: Delegate
private var state: State = .idle

@NetworkEnvironment(\.logger) var logger

init(delegate: Delegate) {
self.delegate = delegate
}

private func set(state: State) {
self.state = state
}

func fetch(for request: HTTPRequestData) async throws -> Credentials {
switch state {
case let .authorized(credentials):
Expand All @@ -33,7 +33,7 @@ public struct HeaderBasedAuthentication<Delegate: AuthenticationDelegate> {
return try await task.value
}
}

private func performCredentialFetch(for request: HTTPRequestData) async throws -> Credentials {
logger?.info("🔐 Fetching credentials for \(Credentials.method.rawValue, privacy: .public) authorization method")
do {
Expand All @@ -45,17 +45,17 @@ public struct HeaderBasedAuthentication<Delegate: AuthenticationDelegate> {
throw AuthenticationError.fetchCredentialsFailed(request, Credentials.method, error)
}
}

func refresh(unauthorized credentials: Credentials, from response: HTTPResponseData) async throws -> Credentials {
if case let .fetching(task) = state {
return try await task.value
}

let task = Task { try await performCredentialRefresh(unauthorized: credentials, from: response) }
set(state: .fetching(task))
return try await task.value
}

private func performCredentialRefresh(
unauthorized credentials: Credentials,
from response: HTTPResponseData
Expand All @@ -73,9 +73,9 @@ public struct HeaderBasedAuthentication<Delegate: AuthenticationDelegate> {
}
}
}

fileprivate let state: StateMachine

public init(delegate: Delegate) {
state = StateMachine(delegate: delegate)
}
Expand Down
38 changes: 19 additions & 19 deletions Sources/Networking/Components/CheckedStatusCode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@ import Foundation
import HTTPTypes

extension NetworkingComponent {
public func checkedStatusCode() -> some NetworkingComponent {
modified(CheckedStatusCode())
}
public func checkedStatusCode() -> some NetworkingComponent {
modified(CheckedStatusCode())
}
}

struct CheckedStatusCode: NetworkingModifier {
func send(upstream: NetworkingComponent, request: HTTPRequestData) -> ResponseStream<HTTPResponseData> {
ResponseStream<HTTPResponseData>(
upstream.send(request)
.map { try $0.onValue(perform: checkStatusCode) }
)
}

private func checkStatusCode(_ response: HTTPResponseData) throws {
guard response.status.isFailure else { return }
// Check for authentication issues
switch response.status {
case .unauthorized:
throw StackError.unauthorized(response)
default:
throw StackError.statusCode(response)
}
func send(upstream: NetworkingComponent, request: HTTPRequestData) -> ResponseStream<HTTPResponseData> {
ResponseStream<HTTPResponseData>(
upstream.send(request)
.map { try $0.onValue(perform: checkStatusCode) }
)
}

private func checkStatusCode(_ response: HTTPResponseData) throws {
guard response.status.isFailure else { return }
// Check for authentication issues
switch response.status {
case .unauthorized:
throw StackError.unauthorized(response)
default:
throw StackError.statusCode(response)
}
}
}
48 changes: 24 additions & 24 deletions Sources/Networking/Components/Delayed.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,33 @@ import Dependencies
import os.log

extension NetworkingComponent {
public func delayed(by duration: Duration) -> some NetworkingComponent {
modified(Delayed(duration: duration))
}
public func delayed(by duration: Duration) -> some NetworkingComponent {
modified(Delayed(duration: duration))
}
}

struct Delayed: NetworkingModifier {
@Dependency(\.continuousClock) var clock
@NetworkEnvironment(\.instrument) var instrument
@NetworkEnvironment(\.logger) var logger

let duration: Duration

func send(upstream: NetworkingComponent, request: HTTPRequestData) -> ResponseStream<HTTPResponseData> {
ResponseStream { continuation in
Task {
do {
await instrument?.measureElapsedTime("Delay")
if duration > .zero {
logger?.info("\(request.debugDescription) delay for \(duration)")
}
try await clock.sleep(for: duration)
} catch {
continuation.finish(throwing: error)
}

await upstream.send(request).redirect(into: continuation)
}
@Dependency(\.continuousClock) var clock
@NetworkEnvironment(\.instrument) var instrument
@NetworkEnvironment(\.logger) var logger

let duration: Duration

func send(upstream: NetworkingComponent, request: HTTPRequestData) -> ResponseStream<HTTPResponseData> {
ResponseStream { continuation in
Task {
do {
await instrument?.measureElapsedTime("Delay")
if duration > .zero {
logger?.info("\(request.debugDescription) delay for \(duration)")
}
try await clock.sleep(for: duration)
} catch {
continuation.finish(throwing: error)
}

await upstream.send(request).redirect(into: continuation)
}
}
}
}
Loading

0 comments on commit 9abd7d3

Please sign in to comment.