Skip to content

Commit

Permalink
⚡️[Feature] Add remote config [deconflicted] (#265)
Browse files Browse the repository at this point in the history
* Added the remote config components

- Testing  FB client
- Confirmed Firebase registered for remote config
- Checking all params

Signed-off-by: kcw-grunt <[email protected]>

* Added tests

Readd Remote

Signed-off-by: kcw-grunt <[email protected]>

* updated gitignore

Signed-off-by: kcw-grunt <[email protected]>

* update project

version bump

- Clean unused code
- Readded test class

Signed-off-by: kcw-grunt <[email protected]>

---------

Signed-off-by: kcw-grunt <[email protected]>
  • Loading branch information
kcw-grunt authored Dec 18, 2024
1 parent 74fd48f commit 2817dee
Show file tree
Hide file tree
Showing 11 changed files with 187 additions and 43 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ litewallet-partner-api-ios
partner-keys.plist
GoogleService-Info.plist
*.gpx
litewallet/remote-config-defaults.plist
remote-config-defaults.plist
50 changes: 37 additions & 13 deletions litewallet.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions litewallet/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
let applicationController = ApplicationController()
let pushNotifications = PushNotifications.shared
var remoteConfigurationHelper: RemoteConfigHelper?

var resourceRequest: NSBundleResourceRequest?

Expand All @@ -33,6 +34,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
AppsFlyerLib.shared().appsFlyerDevKey = Partner.partnerKeyPath(name: .devAF)
AppsFlyerLib.shared().appleAppID = "1119332592"

// Remote Config
self.remoteConfigurationHelper = RemoteConfigHelper.sharedInstance

// Pusher
self.pushNotifications.start(instanceId: Partner.partnerKeyPath(name: .pusher))
let generalInterest = String.preferredLanguageInterest(currentId: UserDefaults.selectedLanguage)
Expand Down
5 changes: 2 additions & 3 deletions litewallet/BRAPIClient+Wallet.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import Foundation

private let fallbackRatesURL = "https://api-dev.lite-wallet.org/v1/rates"

extension BRAPIClient {
func feePerKb(_ handler: @escaping (_ fees: Fees, _ error: String?) -> Void) {
let req = URLRequest(url: url("/fee-per-kb"))
Expand All @@ -13,7 +11,8 @@ extension BRAPIClient {
}

func exchangeRates(isFallback: Bool = false, _ handler: @escaping (_ rates: [Rate], _ error: String?) -> Void) {
let request = isFallback ? URLRequest(url: URL(string: fallbackRatesURL)!) : URLRequest(url: URL(string: APIServer.baseUrl + "v1/rates")!)
let request = isFallback ? URLRequest(url: URL(string: APIServer().devBaseUrl + "v1/rates")!) : URLRequest(url: URL(string: APIServer().baseUrl + "v1/rates")!)

dataTaskWithRequest(request) { data, _, error in
if error == nil, let data = data,
let parsedData = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
Expand Down
2 changes: 1 addition & 1 deletion litewallet/BuyView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ struct BuyView: View {
Button(action: {
if viewModel.receivingAddress != "" {
let timestamp = Int(Date().timeIntervalSince1970)
viewModel.urlString = APIServer.baseUrl + "moonpay/buy" + "?address=\(viewModel.receivingAddress)&idate=\(timestamp)&uid=\(viewModel.uuidString)&code=\(viewModel.selectedCode)"
viewModel.urlString = APIServer().baseUrl + "moonpay/buy" + "?address=\(viewModel.receivingAddress)&idate=\(timestamp)&uid=\(viewModel.uuidString)&code=\(viewModel.selectedCode)"
self.shouldShowSafariVC = true
}

Expand Down
2 changes: 1 addition & 1 deletion litewallet/BuyWKWebViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class BuyWKWebViewController: UIViewController, WKNavigationDelegate, WKScriptMe
}

func loadSimplexRequest() {
let urlString: String = APIServer.baseUrl + "?address=\(currentWalletAddress)&code=\(currencyCode)&idate=\(timestamp)&uid=\(uuidString)"
let urlString: String = APIServer().baseUrl + "?address=\(currentWalletAddress)&code=\(currencyCode)&idate=\(timestamp)&uid=\(uuidString)"

guard let url = URL(string: urlString)
else {
Expand Down
14 changes: 13 additions & 1 deletion litewallet/Constants/Constants+Events.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import SwiftUI
import UIKit

let π: CGFloat = .pi
Expand All @@ -10,7 +11,15 @@ struct FoundationSupport {
}

struct APIServer {
static let baseUrl = "https://api-prod.lite-wallet.org/"
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let baseUrl: String
let devBaseUrl: String
init() {
baseUrl = appDelegate.remoteConfigurationHelper?
.getString(key: RemoteConfigKeys.KEY_PROD_API_BASEURL.rawValue) ?? ""
devBaseUrl = appDelegate.remoteConfigurationHelper?
.getString(key: RemoteConfigKeys.KEY_DEV_API_BASEURL.rawValue) ?? ""
}
}

struct Padding {
Expand Down Expand Up @@ -240,4 +249,7 @@ enum CustomEvent: String {

/// Unsupported by Moonpay
case _20240527_UBM = "unsupported_by_moonpay"

/// Remote Config Changed
case _20241213_RCC = "remote_config_changed"
}
1 change: 1 addition & 0 deletions litewallet/Environment.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Foundation
import UIKit

/// 14 Languages
Expand Down
83 changes: 83 additions & 0 deletions litewallet/RemoteConfigHelper.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import FirebaseRemoteConfig
import Foundation
import KeychainAccess
import UIKit

enum RemoteConfigKeys: String {
case KEY_FEATURE_MENU_HIDDEN_EXAMPLE = "feature_menu_hidden_example"
case KEY_API_BASEURL_PROD_NEW_ENABLED = "key_api_baseurl_prod_new_enabled"
case KEY_API_BASEURL_DEV_NEW_ENABLED = "key_api_baseurl_dev_new_enabled"
case KEY_KEYSTORE_MANAGER_ENABLED = "key_keystore_manager_enabled"
case KEY_PROD_API_BASEURL = "key_prod_api_baseurl"
case KEY_DEV_API_BASEURL = "key_dev_api_baseurl"
}

class RemoteConfigHelper: NSObject {
static let sharedInstance = RemoteConfigHelper()

private var remoteConfig: RemoteConfig!
private let settings = RemoteConfigSettings()
private let keychainEnvironment = Keychain(service: "litewallet.environment")
private let debugFetchInterval: TimeInterval = 0 // seconds
private let productionFetchInterval: TimeInterval = 60 * 180 // seconds; Fetch every 3 hours in production mode
override init() {
super.init()
remoteConfig = RemoteConfig.remoteConfig()
setupRemoteConfig()
}

deinit {}

private func setupRemoteConfig() {
remoteConfig.setDefaults(fromPlist: "remote-config-defaults")
#if DEBUG
settings.minimumFetchInterval = debugFetchInterval
#else
settings.minimumFetchInterval = productionFetchInterval
#endif

remoteConfig.configSettings = settings

/// Call the first time
fetchAndActivateRemoteConfig()

/// Update based on remote changes
remoteConfig.addOnConfigUpdateListener { configUpdate, error in
guard let configUpdate, error == nil else {
let errorDict: [String: String] = ["error": error?.localizedDescription ?? ""]
LWAnalytics.logEventWithParameters(itemName: ._20200112_ERR, properties: errorDict)
return
}

self.fetchAndActivateRemoteConfig()
}
}

private func fetchAndActivateRemoteConfig() {
remoteConfig.fetch { status, error in
if status == .success {
self.remoteConfig.activate { _, error in
guard error == nil else { return }
DispatchQueue.main.async {
LWAnalytics.logEventWithParameters(itemName: ._20241213_RCC)
}
}
} else {
let errorDict: [String: String] = ["error": error?.localizedDescription ?? ""]
LWAnalytics.logEventWithParameters(itemName: ._20200112_ERR, properties: errorDict)
}
}
}

func getString(key: String) -> String {
return remoteConfig[key].stringValue ?? "value_not_found"
}

func getNumber(key: String) -> NSNumber {
return remoteConfig[key].numberValue
}

func getBool(key: String) -> Bool {
return remoteConfig[key].boolValue
}
}
24 changes: 0 additions & 24 deletions litewalletTests/APIManagerTests.swift

This file was deleted.

43 changes: 43 additions & 0 deletions litewalletTests/APITests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@testable import litewallet
import XCTest

class APITests: XCTestCase {
var apiServer: APIServer!
var apiClient: BRAPIClient!

override func setUpWithError() throws {
apiServer = APIServer()
apiClient = litewallet.BRAPIClient(authenticator: NoAuthAuthenticator())
}

override func tearDownWithError() throws {
apiServer = nil
}

func testfetchExchangeRates() throws {
apiClient.exchangeRates { rates, _ in
for rate in rates {
if rate.code == "AFN" {
XCTAssertEqual(rate.name, "Afghan Afghani")
}
if rate.code == "GBP" {
XCTAssertEqual(rate.name, "British Pound Sterling")
}
if rate.code == "EUR" {
XCTAssertEqual(rate.name, "Euro")
}
if rate.code == "USD" {
XCTAssertEqual(rate.name, "US Dollar")
}
}
}
}

func testfeePerKb() throws {
apiClient.feePerKb { fees, _ in
XCTAssertGreaterThan(fees.economy, 0)
XCTAssertGreaterThan(fees.regular, 0)
XCTAssertGreaterThan(fees.luxury, 0)
}
}
}

0 comments on commit 2817dee

Please sign in to comment.