Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

⚡️[Feature] Add remote config [deconflicted] #265

Merged
merged 4 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
}
}
}