Skip to content

Commit 4acc7de

Browse files
author
Experimenter Bot
committed
chore(nimbus): Update External Configs
1 parent 1201e6f commit 4acc7de

13 files changed

Lines changed: 11336 additions & 4 deletions

File tree

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
beta: 83e871927810f621bb3067b265649aa9505ad84f
2-
main: e374045fac6f19383a04d087d2930ced5c1551fe
2+
main: 6e32b4962597e60549f9fc289aa627cae508887c
33
release: 91d93ddd290c6fc70df44dbdc363fc5a0a6306c5

experimenter/experimenter/features/manifests/firefox-desktop/.ref-cache.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ beta: 83e871927810f621bb3067b265649aa9505ad84f
22
esr115: 84341e2725284f1e82f53127f28289454daee783
33
esr128: ed38f9209e39bd7ad247c81a7c20c99c874e0a62
44
esr140: ef9fef7a9928dfbea50e89a256d44492c2d28ca1
5-
main: e374045fac6f19383a04d087d2930ced5c1551fe
5+
main: 6e32b4962597e60549f9fc289aa627cae508887c
66
release: 91d93ddd290c6fc70df44dbdc363fc5a0a6306c5

experimenter/experimenter/features/manifests/ios/.ref-cache.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ firefox-v150.0: a931ff36e4b0152c6a0e9d98a5106fa849a5c1d3
9090
firefox-v150.1: 341e96bda4dd657970d3c0db7f71b08f9eadb395
9191
firefox-v150.2: e50ecad2a9ff5721f95e66419b3c025aaa4b951c
9292
firefox-v150.3: f8f596bfd2b5ca83a77d8bf54eb3d2cbec395671
93-
main: a1f774839a3023e070a74b13f1773af661872e77
93+
firefox-v151.0: c5f54f750bc1c32c555647aee66f17820eaac86b
94+
main: 17dfdbb56f39d99c4214d49dd3566dbeb167d606
9495
release/v117: 43b690c450066d4dde1b2ccb93ed3714d244d502
9596
release/v118: 89a7ea3c3372e5a4ef5b3c5b85499d26198d0524
9697
release/v119: 7dc381f991c6d2a983c3ba7f0cffd880e8c29e7b
@@ -150,7 +151,8 @@ release/v150.0: 251a757be907f072173c4173dae2804c79e0170d
150151
release/v150.1: 9998525d32525e507ad894bf734cc89d19f6ba62
151152
release/v150.2: 3105b1d8b15ad82a4794b15ba3e09ed0bd7801d6
152153
release/v150.3: a88b27cb23568f0b7e8f7e782e393a882e74fd6e
153-
release/v151.0: c5f54f750bc1c32c555647aee66f17820eaac86b
154+
release/v151.0: 86de6b1abdcd59e48dfa236ee323496583b24168
155+
release/v151.1: e5dd824f75bff304dbe19b8a08bb0777d9393f95
154156
v117.0: 3b275ab1e4ccef769d84437033c0c68acfd2df8a
155157
v117.1: 55ddcf473a65d106d43f6d2ae5af4076d6d03688
156158
v117.2: 5cc367aa8857199cd8a54d53e8faf6696c5614c3
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at http://mozilla.org/MPL/2.0/
4+
5+
import Common
6+
import Foundation
7+
import Glean
8+
import Shared
9+
10+
import class MozillaAppServices.NimbusGleanPings
11+
import func MozillaAppServices.getCalculatedAttributes
12+
import func MozillaAppServices.getLocaleTag
13+
import struct MozillaAppServices.JsonObject
14+
import protocol MozillaAppServices.RecordedContext
15+
import MozillaRustComponents
16+
17+
private extension Double? {
18+
func toInt64() -> Int64? {
19+
guard let self = self else { return nil }
20+
return Int64(self)
21+
}
22+
}
23+
24+
extension Int32? {
25+
func toInt64() -> Int64? {
26+
guard let self = self else { return nil }
27+
return Int64(self)
28+
}
29+
}
30+
31+
/// TODO(FXIOS-12942): Implement proper thread-safety
32+
final class RecordedNimbusContext: RecordedContext, @unchecked Sendable {
33+
/**
34+
* The following constants are string constants of the keys that appear in the [EVENT_QUERIES] map.
35+
*/
36+
static let DAYS_OPENED_IN_LAST_28 = "days_opened_in_last_28"
37+
38+
/**
39+
* [EVENT_QUERIES] is a map of keys to Nimbus SDK EventStore queries.
40+
*/
41+
static let EVENT_QUERIES = [
42+
DAYS_OPENED_IN_LAST_28: "'events.app_opened'|eventCountNonZero('Days', 28, 0)",
43+
]
44+
45+
var isFirstRun: Bool
46+
var isPhone: Bool
47+
var isDefaultBrowser: Bool
48+
var isBottomToolbarUser: Bool
49+
var hasEnabledTipsNotifications: Bool
50+
var hasAcceptedTermsOfUse: Bool
51+
var userDisabledAi: Bool
52+
var isAppleIntelligenceAvailable: Bool
53+
var cannotUseAppleIntelligence: Bool
54+
var appVersion: String?
55+
var region: String?
56+
var language: String?
57+
var locale: String
58+
var daysSinceInstall: Int32?
59+
var daysSinceUpdate: Int32?
60+
var touExperiencePoints: Int32?
61+
62+
private var eventQueries: [String: String]
63+
private var eventQueryValues: [String: Double] = [:]
64+
65+
private var logger: Logger
66+
67+
init(isFirstRun: Bool,
68+
isDefaultBrowser: Bool,
69+
isBottomToolbarUser: Bool,
70+
hasEnabledTipsNotifications: Bool,
71+
hasAcceptedTermsOfUse: Bool,
72+
userDisabledAi: Bool,
73+
isAppleIntelligenceAvailable: Bool,
74+
cannotUseAppleIntelligence: Bool,
75+
eventQueries: [String: String] = RecordedNimbusContext.EVENT_QUERIES,
76+
isPhone: Bool = UIDeviceDetails.userInterfaceIdiom == .phone,
77+
bundle: Bundle = Bundle.main,
78+
logger: Logger = DefaultLogger.shared) {
79+
self.logger = logger
80+
logger.log("init start", level: .debug, category: .experiments)
81+
self.eventQueries = eventQueries
82+
83+
self.isFirstRun = isFirstRun
84+
self.isPhone = isPhone
85+
self.isDefaultBrowser = isDefaultBrowser
86+
self.isBottomToolbarUser = isBottomToolbarUser
87+
self.hasEnabledTipsNotifications = hasEnabledTipsNotifications
88+
self.hasAcceptedTermsOfUse = hasAcceptedTermsOfUse
89+
self.userDisabledAi = userDisabledAi
90+
self.isAppleIntelligenceAvailable = isAppleIntelligenceAvailable
91+
self.cannotUseAppleIntelligence = cannotUseAppleIntelligence
92+
93+
let info = bundle.infoDictionary ?? [:]
94+
appVersion = info["CFBundleShortVersionString"] as? String
95+
96+
locale = getLocaleTag()
97+
var inferredDateInstalledOn: Date? {
98+
guard
99+
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).last,
100+
let attributes = try? FileManager.default.attributesOfItem(atPath: documentsURL.path)
101+
else { return nil }
102+
return attributes[.creationDate] as? Date
103+
}
104+
let installationDateSinceEpoch = inferredDateInstalledOn.map {
105+
Int64(($0.timeIntervalSince1970 * 1000).rounded())
106+
}
107+
guard let dbPath = Experiments.dbPath else {
108+
self.logger.log("Unable to obtain dbPath, skipping calculating attributes",
109+
level: .warning,
110+
category: .experiments)
111+
return
112+
}
113+
guard let calculatedAttributes = try? getCalculatedAttributes(installationDate: installationDateSinceEpoch,
114+
dbPath: dbPath,
115+
locale: locale)
116+
else { return }
117+
118+
daysSinceInstall = calculatedAttributes.daysSinceInstall
119+
daysSinceUpdate = calculatedAttributes.daysSinceUpdate
120+
language = calculatedAttributes.language
121+
region = calculatedAttributes.region
122+
touExperiencePoints = Experiments.touExperiencePoints(region: region)
123+
self.logger.log("init end", level: .debug, category: .experiments)
124+
}
125+
126+
/**
127+
* [getEventQueries] is called by the Nimbus SDK Rust code to retrieve the map of event
128+
* queries. The are then executed against the Nimbus SDK's EventStore to retrieve their values.
129+
*
130+
* @return Map<String, String>
131+
*/
132+
func getEventQueries() -> [String: String] {
133+
logger.log("getEventQueries", level: .debug, category: .experiments)
134+
return eventQueries
135+
}
136+
137+
/**
138+
* [record] is called when experiment enrollments are evolved. It should apply the
139+
* [RecordedNimbusContext]'s values to a [NimbusSystem.RecordedNimbusContextObject] instance,
140+
* and use that instance to record the values to Glean.
141+
*/
142+
func record() {
143+
logger.log("record start", level: .debug, category: .experiments)
144+
145+
// Bring the ping into scope so that Glean knows it exists and includes NimbusSystem.recordedNimbusContext
146+
_ = NimbusGleanPings.nimbusTargetingContext
147+
148+
let eventQueryValuesObject = GleanMetrics.NimbusSystem.RecordedNimbusContextObjectItemEventQueryValuesObject(
149+
daysOpenedInLast28: eventQueryValues[RecordedNimbusContext.DAYS_OPENED_IN_LAST_28].toInt64()
150+
)
151+
152+
GleanMetrics.NimbusSystem.recordedNimbusContext.set(
153+
GleanMetrics.NimbusSystem.RecordedNimbusContextObject(
154+
isFirstRun: isFirstRun,
155+
eventQueryValues: eventQueryValuesObject,
156+
isPhone: isPhone,
157+
appVersion: appVersion,
158+
locale: locale,
159+
daysSinceInstall: daysSinceInstall.toInt64(),
160+
daysSinceUpdate: daysSinceUpdate.toInt64(),
161+
language: language,
162+
region: region,
163+
isDefaultBrowser: isDefaultBrowser,
164+
isBottomToolbarUser: isBottomToolbarUser,
165+
hasEnabledTipsNotifications: hasEnabledTipsNotifications,
166+
hasAcceptedTermsOfUse: hasAcceptedTermsOfUse,
167+
userDisabledAi: userDisabledAi,
168+
isAppleIntelligenceAvailable: isAppleIntelligenceAvailable,
169+
cannotUseAppleIntelligence: cannotUseAppleIntelligence,
170+
touExperiencePoints: touExperiencePoints.toInt64()
171+
)
172+
)
173+
logger.log("record end", level: .debug, category: .experiments)
174+
}
175+
176+
/**
177+
* [setEventQueryValues] is called by the Nimbus SDK Rust code after the event queries have been
178+
* executed. The [eventQueryValues] should be written back to the Kotlin object.
179+
*
180+
* @param [eventQueryValues] The values for each query after they have been executed in the
181+
* Nimbus SDK Rust environment.
182+
*/
183+
func setEventQueryValues(eventQueryValues: [String: Double]) {
184+
logger.log("setEventQueryValues", level: .debug, category: .experiments)
185+
self.eventQueryValues = eventQueryValues
186+
}
187+
188+
/**
189+
* [toJson] is called by the Nimbus SDK Rust code after the event queries have been executed,
190+
* and before experiment enrollments have been evolved. The value returned from this method
191+
* will be applied directly to the Nimbus targeting context, and its keys/values take
192+
* precedence over those in the main Nimbus targeting context.
193+
*
194+
* @return JsonObject
195+
*/
196+
func toJson() -> JsonObject {
197+
logger.log("toJson start", level: .debug, category: .experiments)
198+
guard let data = try? JSONSerialization.data(withJSONObject: [
199+
"is_first_run": isFirstRun,
200+
"isFirstRun": "\(isFirstRun)",
201+
"is_phone": isPhone,
202+
"events": eventQueryValues,
203+
"app_version": appVersion as Any,
204+
"region": region as Any,
205+
"language": language as Any,
206+
"locale": locale as Any,
207+
"days_since_install": daysSinceInstall as Any,
208+
"days_since_update": daysSinceUpdate as Any,
209+
"is_default_browser": isDefaultBrowser,
210+
"is_bottom_toolbar_user": isBottomToolbarUser,
211+
"has_enabled_tips_notifications": hasEnabledTipsNotifications,
212+
"has_accepted_terms_of_use": hasAcceptedTermsOfUse,
213+
"user_disabled_ai": userDisabledAi,
214+
"is_apple_intelligence_available": isAppleIntelligenceAvailable,
215+
"cannot_use_apple_intelligence": cannotUseAppleIntelligence,
216+
"tou_experience_points": touExperiencePoints as Any
217+
]),
218+
let jsonString = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as? String
219+
else {
220+
logger.log("toJson error thrown while creating JSON string", level: .warning, category: .experiments)
221+
return "{}"
222+
}
223+
logger.log("toJson end", level: .debug, category: .experiments, extra: ["json": jsonString])
224+
return jsonString
225+
}
226+
}

0 commit comments

Comments
 (0)