Skip to content

Commit

Permalink
Refactor: make datafile handler async (#72)
Browse files Browse the repository at this point in the history
* feat: make datafilehandler async
* feat: define all min platform versions because of `Task` usage
* feat: update to 5.9 to support visionOS too
* update github action to use swift 5.9.2
* update setup-swift action version
  • Loading branch information
polok authored May 6, 2024
1 parent 69fdb0e commit 9886301
Show file tree
Hide file tree
Showing 7 changed files with 58 additions and 51 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ jobs:

steps:
- uses: actions/checkout@v3
- uses: swift-actions/setup-swift@65540b95f51493d65f5e59e97dcef9629ddf11bf
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5.8"
swift-version: "5.9.2"
- name: Install swift-format tool
run: brew install swift-format
- name: Swift-format linting Sources directory
Expand Down
2 changes: 1 addition & 1 deletion .swift-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
5.8
5.9
5 changes: 3 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
// swift-tools-version:5.7
// swift-tools-version:5.9
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
name: "FeaturevisorSDK",
products: [
platforms: [.iOS(.v13), .tvOS(.v13), .macOS(.v10_15), .watchOS(.v6), .macCatalyst(.v13), .visionOS(.v1)],
products: [
// Products define the executables and libraries produced by a package, and make them visible to other packages.
.library(
name: "FeaturevisorSDK",
Expand Down
32 changes: 13 additions & 19 deletions Sources/FeaturevisorSDK/Instance+Fetch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,38 +11,32 @@ extension FeaturevisorInstance {
completion: @escaping (Result<DatafileContent, Error>) -> Void
) throws {

guard let datafileURL = URL(string: url) else {
throw FeaturevisorError.invalidURL(string: url)
}

guard let handleDatafileFetch else {
try fetchDatafileContent(from: url, completion: completion)
fetch(from: datafileURL, completion: completion)
return
}

completion(handleDatafileFetch(url))
Task {
completion(await handleDatafileFetch(datafileURL))
}
}
}

extension FeaturevisorInstance {

fileprivate func fetchDatafileContent(
from url: String,
completion: @escaping (Result<DatafileContent, Error>) -> Void
) throws {

guard let datafileUrl = URL(string: url) else {
throw FeaturevisorError.invalidURL(string: url)
}

var request = URLRequest(url: datafileUrl)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("no-cache", forHTTPHeaderField: "Cache-Control")

fetch(using: request, completion: completion)
}

fileprivate func fetch<T>(
using request: URLRequest,
from url: URL,
completion: @escaping (Result<T, Error>) -> Void
) where T: Decodable {

var request = URLRequest(url: url)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("no-cache", forHTTPHeaderField: "Cache-Control")

let task = urlSession.dataTask(with: request) { (data, response, error) in

if let error = error {
Expand Down
49 changes: 26 additions & 23 deletions Sources/FeaturevisorSDK/Instance+Refresh.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,35 +19,38 @@ extension FeaturevisorInstance {

statuses.refreshInProgress = true

try? fetchDatafileContent(
from: datafileUrl,
handleDatafileFetch: handleDatafileFetch
) { [weak self] result in
guard let self else {
return
}
Task { [weak self] in
try? await self?
.fetchDatafileContent(
from: datafileUrl,
handleDatafileFetch: handleDatafileFetch
) { [weak self] result in
guard let self else {
return
}

switch result {
case .success(let datafileContent):
let currentRevision = self.getRevision()
let newRevision = datafileContent.revision
let isNotSameRevision = currentRevision != newRevision
switch result {
case .success(let datafileContent):
let currentRevision = self.getRevision()
let newRevision = datafileContent.revision
let isNotSameRevision = currentRevision != newRevision

self.datafileReader = DatafileReader(datafileContent: datafileContent)
logger.info("refreshed datafile")
self.datafileReader = DatafileReader(datafileContent: datafileContent)
logger.info("refreshed datafile")

self.emitter.emit(.refresh)
self.emitter.emit(.refresh)

if isNotSameRevision {
self.emitter.emit(.update)
}
if isNotSameRevision {
self.emitter.emit(.update)
}

self.statuses.refreshInProgress = false
self.statuses.refreshInProgress = false

case .failure(let error):
self.logger.error("failed to refresh datafile", ["error": error])
self.statuses.refreshInProgress = false
}
case .failure(let error):
self.logger.error("failed to refresh datafile", ["error": error])
self.statuses.refreshInProgress = false
}
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/FeaturevisorSDK/Instance.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
public typealias ConfigureBucketKey = (Feature, Context, BucketKey) -> BucketKey
public typealias ConfigureBucketValue = (Feature, Context, BucketValue) -> BucketValue
public typealias InterceptContext = (Context) -> Context
public typealias DatafileFetchHandler = (_ datafileUrl: String) -> Result<DatafileContent, Error>
public typealias DatafileFetchHandler = (_ datafileURL: URL) async -> Result<DatafileContent, Error>

public struct Statuses {
public var ready: Bool
Expand Down
15 changes: 12 additions & 3 deletions Tests/FeaturevisorSDKTests/InstanceTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,12 @@ class FeaturevisorInstanceTests: XCTestCase {
func testHandleDatafileFetchReturnsValidResponse() {

// GIVEN
let expectation = expectation(description: "datafile_error_response_expectation")
var options = InstanceOptions.default
options.datafileUrl = "https://dazn.featurevisor.datafilecontent.com"
options.datafileUrl = "https://featurevisor.datafilecontent.com"
options.onReady = { _ in
expectation.fulfill()
}
options.handleDatafileFetch = { _ in
let datafileContent = DatafileContent(
schemaVersion: "2",
Expand All @@ -1136,15 +1140,17 @@ class FeaturevisorInstanceTests: XCTestCase {
let sdk = try! createInstance(options: options)

// THEN
waitForExpectations(timeout: 1)
XCTAssertEqual(sdk.getRevision(), "6.6.6")
}

func testHandleDatafileFetchReturnErrorResponse() {

// GIVEN
let expectation = expectation(description: "datafile_error_response_expectation")
var wasDatafileContentFetchErrorThrown = false
var options = InstanceOptions.default
options.datafileUrl = "https://dazn.featurevisor.datafilecontent.com"
options.datafileUrl = "https://featurevisor.datafilecontent.com"
options.handleDatafileFetch = { _ in
return .failure(FeaturevisorError.unparseableJSON(data: nil, errorMessage: "Error :("))
}
Expand All @@ -1156,6 +1162,8 @@ class FeaturevisorInstanceTests: XCTestCase {
if message.contains("Failed to fetch datafile") {
wasDatafileContentFetchErrorThrown = true
}

expectation.fulfill()
}
options.datafile = DatafileContent(
schemaVersion: "1",
Expand All @@ -1166,9 +1174,10 @@ class FeaturevisorInstanceTests: XCTestCase {
)

// WHEN
_ = try! createInstance(options: options)
let sdk = try! createInstance(options: options)

// THEN
waitForExpectations(timeout: 1)
XCTAssertTrue(wasDatafileContentFetchErrorThrown)
}

Expand Down

0 comments on commit 9886301

Please sign in to comment.