diff --git a/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift b/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift index 073efd95..07b0f0a0 100644 --- a/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift +++ b/ConfidenceDemoApp/ConfidenceDemoApp/ConfidenceDemoApp.swift @@ -20,7 +20,7 @@ struct ConfidenceDemoApp: App { WindowGroup { let secret = ProcessInfo.processInfo.environment["CLIENT_SECRET"] ?? "" let confidence = Confidence.Builder(clientSecret: secret, loggerLevel: .TRACE) - .withContext(initialContext: ["targeting_key": ConfidenceValue(string: UUID.init().uuidString)]) +// .withContext(initialContext: ["targeting_key": ConfidenceValue(string: UUID.init().uuidString)]) .build() let status = Status() @@ -42,6 +42,6 @@ struct ConfidenceDemoApp: App { extension ConfidenceDemoApp { func setup(confidence: Confidence) async throws { - try await confidence.fetchAndActivate() +// try await confidence.fetchAndActivate() } } diff --git a/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift b/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift index e1f99db4..278f0344 100644 --- a/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift +++ b/ConfidenceDemoApp/ConfidenceDemoApp/ContentView.swift @@ -6,6 +6,10 @@ struct ContentView: View { @ObservedObject var status: Status @StateObject var text = DisplayText() @StateObject var color = FlagColor() + @State private var user = "logged out" + @State private var logginIn = false + @State private var evaluationReason = "Last Reason: ---" + @State private var evaluationError = "Last Error: ---" private let confidence: Confidence @@ -17,26 +21,88 @@ struct ContentView: View { var body: some View { if case .ready = status.state { VStack { + Text("Current user:") + if (logginIn) { + ProgressView() + } else { + Text("\(user)") + .font(.title) + .bold() + } + Spacer() Image(systemName: "flag") .imageScale(.large) + .font(.title) .foregroundColor(color.color) .padding(10) Text(text.text) + Spacer() + Button("Login yellow user") { + confidence.putContext(key: "user_id", value: ConfidenceValue.init(string: "user1")) + Task { + logginIn = true + try await confidence.fetchAndActivate() + user = "yellow_user" + logginIn = false + } + } + Button("Login green user") { + confidence.putContext(key: "user_id", value: ConfidenceValue.init(string: "user2")) + Task { + logginIn = true + try await confidence.fetchAndActivate() + logginIn = false + user = "green_user" + } + } + .padding(.bottom) Button("Get remote flag value") { - let test = confidence.getEvaluation(key: "swift-demoapp.color", defaultValue: true) - print("\(test)") - text.text = confidence.getValue(key: "swift-demoapp.color", defaultValue: "ERROR") + let eval = confidence.getEvaluation(key: "swift-demoapp.color", defaultValue: "DefaultValue") + evaluationReason = "Last Reason: \(eval.reason)" + evaluationError = "Last Error: \(eval.errorCode?.description ?? .none ?? "None")" + text.text = eval.value if text.text == "Green" { color.color = .green } else if text.text == "Yellow" { color.color = .yellow } else { - color.color = .red + color.color = .gray } } + VStack(alignment: .leading) { + HStack { + Text(evaluationReason) + .padding(.horizontal) + Spacer() + } + HStack { + Text(evaluationError) + .padding(.horizontal) + Spacer() + } + } + .padding(.bottom) + Button("Get remote flag value with TypeMismatch ⚠️") { + let eval = confidence.getEvaluation(key: "swift-demoapp.color", defaultValue: true) + evaluationReason = "Last Reason: \(eval.reason)" + evaluationError = "Last Error: \(eval.errorCode?.description ?? .none ?? "None")" + if text.text == "Green" { + color.color = .green + } else if text.text == "Yellow" { + color.color = .yellow + } else { + color.color = .gray + } + } + .padding(.bottom) + Button("Generate event") { + try! confidence.track(eventName: "Test", data: [:]) + } + .padding(.top) Button("Flush 🚽") { confidence.flush() } + .padding(.bottom) } .padding() } else if case .error(let error) = status.state { @@ -53,6 +119,10 @@ struct ContentView: View { } } +class Model: ObservableObject { + +} + class DisplayText: ObservableObject { @Published var text = "Hello World!" } diff --git a/Sources/Confidence/FlagEvaluation.swift b/Sources/Confidence/FlagEvaluation.swift index 207eb878..cf3f278f 100644 --- a/Sources/Confidence/FlagEvaluation.swift +++ b/Sources/Confidence/FlagEvaluation.swift @@ -8,12 +8,27 @@ public struct Evaluation { public let errorMessage: String? } -public enum ErrorCode { +public enum ErrorCode: CustomStringConvertible { case providerNotReady case invalidContext case flagNotFound case evaluationError case typeMismatch + + public var description: String { + switch self { + case .providerNotReady: + return "Provider is not ready." + case .invalidContext: + return "Invalid context." + case .flagNotFound: + return "Flag not found." + case .evaluationError: + return "Evaluation error occurred." + case .typeMismatch: + return "Type mismatch encountered." + } + } } struct FlagResolution: Encodable, Decodable, Equatable { diff --git a/Sources/Confidence/Http/NetworkClient.swift b/Sources/Confidence/Http/NetworkClient.swift index ee29c409..5416297a 100644 --- a/Sources/Confidence/Http/NetworkClient.swift +++ b/Sources/Confidence/Http/NetworkClient.swift @@ -130,7 +130,20 @@ extension NetworkClient { } } // TMP - TESTING - print(">> \(request.allHTTPHeaderFields)") + if let headers = request.allHTTPHeaderFields, let metadata = headers["Confidence-Metadata"] { + if let data = metadata.data(using: .utf8) { + do { + let jsonObject = try JSONSerialization.jsonObject(with: data, options: []) + let prettyData = try JSONSerialization.data(withJSONObject: jsonObject, options: .prettyPrinted) + + if let prettyPrintedString = String(data: prettyData, encoding: .utf8) { + print(prettyPrintedString) + } + } catch { + print("Failed to pretty print JSON: \(error)") + } + } + } let jsonData = try encoder.encode(data) request.httpBody = jsonData diff --git a/Sources/Confidence/contextChanges.swift b/Sources/Confidence/contextChanges.swift new file mode 100644 index 00000000..e69de29b