Skip to content

Commit

Permalink
fix: breaking changes
Browse files Browse the repository at this point in the history
  • Loading branch information
duyhungtnn committed Jul 3, 2023
1 parent f9014fc commit a4212d4
Show file tree
Hide file tree
Showing 6 changed files with 148 additions and 93 deletions.
189 changes: 103 additions & 86 deletions Bucketeer/Sources/Public/BKTConfig.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import UIKit

public class BKTConfig {
public struct BKTConfig {
let apiKey: String
let apiEndpoint: URL
let featureTag: String
Expand All @@ -11,73 +11,7 @@ public class BKTConfig {
let sdkVersion: String
let appVersion: String
let logger: BKTLogger?

internal init(apiKey: String,
apiEndpoint: URL,
featureTag: String,
eventsFlushInterval: Int64,
eventsMaxQueueSize: Int,
pollingInterval: Int64,
backgroundPollingInterval: Int64,
sdkVersion: String,
appVersion: String,
logger: BKTLogger? = nil) {
self.apiKey = apiKey
self.apiEndpoint = apiEndpoint
self.featureTag = featureTag
self.eventsFlushInterval = eventsFlushInterval
self.eventsMaxQueueSize = eventsMaxQueueSize
self.pollingInterval = pollingInterval
self.backgroundPollingInterval = backgroundPollingInterval
self.sdkVersion = sdkVersion
self.appVersion = appVersion
self.logger = logger
}

private convenience init(with builder: Builder) throws {
guard let apiKeyForSDK = builder.apiKey, apiKeyForSDK.isNotEmpty() else {
throw BKTError.illegalArgument(message: "apiKey is required")
}
guard let endpoint = builder.apiEndpoint, let apiEndpointURL = URL(string: endpoint) else {
throw BKTError.illegalArgument(message: "endpoint is required")
}
guard let featureTag = builder.featureTag, featureTag.isNotEmpty() else {
throw BKTError.illegalArgument(message: "featureTag is required")
}
guard let appVersion = builder.appVersion, appVersion.isNotEmpty() else {
throw BKTError.illegalArgument(message: "appVersion is required")
}

var pollingInterval : Int64 = builder.pollingInterval ?? Constant.MINIMUM_POLLING_INTERVAL_MILLIS
if pollingInterval < Constant.MINIMUM_POLLING_INTERVAL_MILLIS {
builder.logger?.warn(message: "pollingInterval: \(pollingInterval) is set but must be above \(Constant.MINIMUM_POLLING_INTERVAL_MILLIS)")
pollingInterval = Constant.MINIMUM_POLLING_INTERVAL_MILLIS
}
var backgroundPollingInterval : Int64 = builder.backgroundPollingInterval ?? Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS
if backgroundPollingInterval < Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS {
builder.logger?.warn(message: "backgroundPollingInterval: \(backgroundPollingInterval) is set but must be above \(Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS)")
backgroundPollingInterval = Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS
}
var eventsFlushInterval: Int64 = builder.eventsFlushInterval ?? Constant.DEFAULT_FLUSH_INTERVAL_MILLIS
if eventsFlushInterval < Constant.MINIMUM_FLUSH_INTERVAL_MILLIS {
builder.logger?.warn(message: "eventsFlushInterval: \(eventsFlushInterval) is set but must be above \(Constant.MINIMUM_FLUSH_INTERVAL_MILLIS)")
eventsFlushInterval = Constant.DEFAULT_FLUSH_INTERVAL_MILLIS
}

let eventsMaxQueueSize = builder.eventsMaxQueueSize ?? Constant.DEFAULT_MAX_QUEUE_SIZE

self.init(apiKey: apiKeyForSDK,
apiEndpoint: apiEndpointURL,
featureTag: featureTag,
eventsFlushInterval: eventsFlushInterval,
eventsMaxQueueSize: eventsMaxQueueSize,
pollingInterval: pollingInterval,
backgroundPollingInterval: backgroundPollingInterval,
sdkVersion: builder.sdkVersion,
appVersion: appVersion,
logger: builder.logger)
}


public class Builder {
private(set) var apiKey: String?
private(set) var apiEndpoint: String?
Expand All @@ -86,68 +20,151 @@ public class BKTConfig {
private(set) var eventsMaxQueueSize: Int?
private(set) var pollingInterval: Int64?
private(set) var backgroundPollingInterval: Int64?
private(set) var sdkVersion: String = Version.current
private(set) var appVersion: String?
private(set) var logger: BKTLogger?

/**
* Create a new builder with your API key.
*/
public init(apiKey: String) {
self.apiKey = apiKey
}


public init() {}

public func with(apiKey: String) -> Builder {
self.apiKey = apiKey
return self
}

public func with(apiEndpoint: String) -> Builder {
self.apiEndpoint = apiEndpoint
return self
}

public func with(featureTag: String) -> Builder {
self.featureTag = featureTag
return self
}

public func with(eventsFlushInterval: Int64) -> Builder {
self.eventsFlushInterval = eventsFlushInterval
return self
}

public func with(eventsMaxQueueSize: Int) -> Builder {
self.eventsMaxQueueSize = eventsMaxQueueSize
return self
}

public func with(pollingInterval: Int64) -> Builder {
self.pollingInterval = pollingInterval
return self
}

public func with(backgroundPollingInterval: Int64) -> Builder {
self.backgroundPollingInterval = backgroundPollingInterval
return self
}

public func with(appVersion: String) -> Builder {
self.appVersion = appVersion
return self
}

public func with(logger: BKTLogger) -> Builder {
self.logger = logger
return self
}

public func build() throws -> BKTConfig {
return try BKTConfig.init(with: self)
}
}
}

extension BKTConfig {
// Public init - that will support to init of the BKTConfig like before we add the Builder.
// So it will not create breaking changes
public init(
apiKey: String,
apiEndpoint: String,
featureTag: String,
eventsFlushInterval: Int64 = Constant.DEFAULT_FLUSH_INTERVAL_MILLIS,
eventsMaxQueueSize: Int = Constant.DEFAULT_MAX_QUEUE_SIZE,
pollingInterval: Int64 = Constant.DEFAULT_POLLING_INTERVAL_MILLIS,
backgroundPollingInterval: Int64 = Constant.DEFAULT_BACKGROUND_POLLING_INTERVAL_MILLIS,
appVersion: String,
logger: BKTLogger? = nil
) throws {
// String empty check
guard !apiKey.isEmpty else {
throw BKTError.illegalArgument(message: "apiKey is required")
}
guard let apiEndpointURL = URL(string: apiEndpoint) else {
throw BKTError.illegalArgument(message: "endpoint is required")
}
guard !featureTag.isEmpty else {
throw BKTError.illegalArgument(message: "featureTag is required")
}
guard !appVersion.isEmpty else {
throw BKTError.illegalArgument(message: "appVersion is required")
}

var pollingInterval = pollingInterval
if pollingInterval < Constant.MINIMUM_POLLING_INTERVAL_MILLIS {
logger?.warn(message: "pollingInterval: \(pollingInterval) is set but must be above \(Constant.MINIMUM_POLLING_INTERVAL_MILLIS)")
pollingInterval = Constant.MINIMUM_POLLING_INTERVAL_MILLIS
}
var backgroundPollingInterval = backgroundPollingInterval
if backgroundPollingInterval < Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS {
logger?.warn(message: "backgroundPollingInterval: \(backgroundPollingInterval) is set but must be above \(Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS)")
backgroundPollingInterval = Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS
}
var eventsFlushInterval = eventsFlushInterval
if eventsFlushInterval < Constant.MINIMUM_FLUSH_INTERVAL_MILLIS {
logger?.warn(message: "eventsFlushInterval: \(eventsFlushInterval) is set but must be above \(Constant.MINIMUM_FLUSH_INTERVAL_MILLIS)")
eventsFlushInterval = Constant.DEFAULT_FLUSH_INTERVAL_MILLIS
}
self.apiKey = apiKey
self.apiEndpoint = apiEndpointURL
self.featureTag = featureTag
self.eventsFlushInterval = eventsFlushInterval
self.eventsMaxQueueSize = eventsMaxQueueSize
self.pollingInterval = pollingInterval
self.backgroundPollingInterval = backgroundPollingInterval
self.sdkVersion = Version.current
self.appVersion = appVersion
self.logger = logger
}

private init(with builder: Builder) throws {
// Nil check
guard let apiKeyForSDK = builder.apiKey, apiKeyForSDK.isNotEmpty() else {
throw BKTError.illegalArgument(message: "apiKey is required")
}
guard let endpoint = builder.apiEndpoint else {
throw BKTError.illegalArgument(message: "endpoint is required")
}
guard let featureTag = builder.featureTag, featureTag.isNotEmpty() else {
throw BKTError.illegalArgument(message: "featureTag is required")
}
guard let appVersion = builder.appVersion, appVersion.isNotEmpty() else {
throw BKTError.illegalArgument(message: "appVersion is required")
}

// Set default intervals if needed
let pollingInterval : Int64 = builder.pollingInterval ?? Constant.MINIMUM_POLLING_INTERVAL_MILLIS
let backgroundPollingInterval : Int64 = builder.backgroundPollingInterval ?? Constant.MINIMUM_BACKGROUND_POLLING_INTERVAL_MILLIS
let eventsFlushInterval: Int64 = builder.eventsFlushInterval ?? Constant.DEFAULT_FLUSH_INTERVAL_MILLIS
let eventsMaxQueueSize = builder.eventsMaxQueueSize ?? Constant.DEFAULT_MAX_QUEUE_SIZE

// Use the current init method
try self.init(apiKey: apiKeyForSDK,
apiEndpoint: endpoint,
featureTag: featureTag,
eventsFlushInterval: eventsFlushInterval,
eventsMaxQueueSize: eventsMaxQueueSize,
pollingInterval: pollingInterval,
backgroundPollingInterval: backgroundPollingInterval,
appVersion: appVersion,
logger: builder.logger)
}
}

fileprivate extension String {
func isNotEmpty() -> Bool {
// We will not check all case
Expand Down
3 changes: 2 additions & 1 deletion BucketeerTests/BKTConfigTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ final class BKTConfigTests: XCTestCase {
func testCreateConfig() {
let logger = MockLogger()
// Not set interval values
var builder = BKTConfig.Builder(apiKey: "api_key_value")
var builder = BKTConfig.Builder()
.with(apiKey: "api_key_value")
.with(apiEndpoint: "https://test.bucketeer.io")
.with(featureTag: "featureTag1")
.with(appVersion: "1.2.3")
Expand Down
3 changes: 2 additions & 1 deletion BucketeerTests/E2E/E2ETestHelpers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ extension BKTConfig {
static func e2e() throws -> BKTConfig {
let apiKey = ProcessInfo.processInfo.environment["E2E_API_KEY"]!
let apiEndpoint = ProcessInfo.processInfo.environment["E2E_API_ENDPOINT"]!
let builder = BKTConfig.Builder(apiKey: apiKey)
let builder = BKTConfig.Builder()
.with(apiKey: apiKey)
.with(apiEndpoint: apiEndpoint)
.with(featureTag: FEATURE_TAG)
.with(appVersion: "1.2.3")
Expand Down
2 changes: 2 additions & 0 deletions BucketeerTests/Mock/MockBKTConfig.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ extension BKTConfig {
eventsMaxQueueSize: Int = Constant.DEFAULT_MAX_QUEUE_SIZE,
pollingInterval: Int64 = Constant.DEFAULT_POLLING_INTERVAL_MILLIS,
backgroundPollingInterval: Int64 = Constant.DEFAULT_BACKGROUND_POLLING_INTERVAL_MILLIS) -> BKTConfig {
// Direct init BKTConfig and bypass all validations
// It could only happen with internal access
return BKTConfig(
apiKey: "api_key_value",
apiEndpoint: URL(string: "https://test.bucketeer.io")!,
Expand Down
22 changes: 19 additions & 3 deletions Example/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,34 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}

private func makeConfig() -> BKTConfig {
private func makeConfigUsingBuilder() -> BKTConfig {
let bundle = Bundle(for: type(of: self))
let apiKey = ProcessInfo.processInfo.environment["API_KEY"]!
let apiEndpoint = ProcessInfo.processInfo.environment["API_ENDPOINT"]!
let builder = BKTConfig.Builder(apiKey: apiKey)
let builder = BKTConfig.Builder()
.with(apiKey: apiKey)
.with(apiEndpoint: apiEndpoint)
.with(featureTag: "ios")
.with(pollingInterval: 5_000)
.with(appVersion: bundle.infoDictionary?["CFBundleShortVersionString"] as! String)

return try! builder.build()
}

private func makeConfig() -> BKTConfig {
let bundle = Bundle(for: type(of: self))
let apiKey = ProcessInfo.processInfo.environment["API_KEY"]!
let apiEndpoint = ProcessInfo.processInfo.environment["API_ENDPOINT"]!

return try! BKTConfig(
apiKey: apiKey,
apiEndpoint: apiEndpoint,
featureTag: "ios",
pollingInterval: 5_000,
appVersion: bundle.infoDictionary?["CFBundleShortVersionString"] as! String,
logger: nil
)
}

private func setSingleViewController() {
guard self.window?.rootViewController is SplashViewController else { return }
Expand Down
22 changes: 20 additions & 2 deletions ExampleTVOS/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,33 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

return true
}

private func makeConfig() -> BKTConfig {
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "Info", ofType: "plist")!
let dic = NSDictionary(contentsOfFile: path) as! [String: Any]
let apiKey = dic["apiKey"] as! String
let apiEndpoint = dic["apiEndpoint"] as! String

return try! BKTConfig(
apiKey: apiKey,
apiEndpoint: apiEndpoint,
featureTag: "ios",
pollingInterval: 5_000,
appVersion: bundle.infoDictionary?["CFBundleShortVersionString"] as! String,
logger: nil
)
}

private func makeConfigUsingBuilder() -> BKTConfig {
let bundle = Bundle(for: type(of: self))
let path = bundle.path(forResource: "Info", ofType: "plist")!
let dic = NSDictionary(contentsOfFile: path) as! [String: Any]
let apiKey = dic["apiKey"] as! String
let apiEndpoint = dic["apiEndpoint"] as! String

let builder = BKTConfig.Builder(apiKey: apiKey)
let builder = BKTConfig.Builder()
.with(apiKey: apiKey)
.with(apiEndpoint: apiEndpoint)
.with(featureTag: "ios")
.with(pollingInterval: 5_000)
Expand Down

0 comments on commit a4212d4

Please sign in to comment.