@@ -126,8 +126,25 @@ export class CoreMetricsSync {
126126 }
127127
128128 initialize ( ) : void {
129- this . initializeClientId ( ) ;
130- this . initializeFirstRunDate ( ) ;
129+ // If the client had used previous versions of Glean.js before we moved
130+ // to LocalStorage as the data store, then we need to move important
131+ // user data from IndexedDB to LocalStorage.
132+ //
133+ // Currently we are interested in migrating two things
134+ // 1. The client_id - consistent clientId across all sessions.
135+ // 2. The first_run_date - the date when the client was first run.
136+
137+ // The migration is done only once per client. The flag is set in
138+ // LocalStorage to indicate that the migration has been completed.
139+ const migrationFlag = localStorage . getItem ( "GLEAN_MIGRATION_FLAG" ) ;
140+ if ( migrationFlag !== "1" ) {
141+ this . migrateCoreMetricsFromIdb ( ) ;
142+ localStorage . setItem ( "GLEAN_MIGRATION_FLAG" , "1" ) ;
143+ } else {
144+ // If we do not need to migrate anything, then we can set the metrics
145+ // for the first time.
146+ this . initializeUserLifetimeMetrics ( ) ;
147+ }
131148
132149 this . os . set ( ( Context . platform as PlatformSync ) . info . os ( ) ) ;
133150 this . osVersion . set ( ( Context . platform as PlatformSync ) . info . osVersion ( Context . config . osVersion ) ) ;
@@ -187,4 +204,80 @@ export class CoreMetricsSync {
187204 this . firstRunDate . set ( ) ;
188205 }
189206 }
207+
208+ /**
209+ * Initializes the Glean internal user-lifetime metrics.
210+ */
211+ private initializeUserLifetimeMetrics ( ) : void {
212+ this . initializeClientId ( ) ;
213+ this . initializeFirstRunDate ( ) ;
214+ }
215+
216+ /**
217+ * Migrates the core metrics from the old IDB storage to LocalStorage
218+ * on first launch IF the client had used previous versions of Glean.js -
219+ * pre LocalStorage.
220+ *
221+ * There is no way to access IDB data synchronously, so we rely on listeners
222+ * for when specific actions complete. This means that we need to be careful
223+ * and ensure that the clientId and firstRunDate are always set.
224+ *
225+ * Once the migration is complete, running the initialize functions for the
226+ * clientId and firstRunDate equate to no-ops. If there is an error anywhere
227+ * along the way and the migration is not complete, then the initialize the
228+ * two metrics as usual.
229+ */
230+ private migrateCoreMetricsFromIdb ( ) : void {
231+ const dbRequest = window . indexedDB . open ( "Glean" ) ;
232+ dbRequest . onerror = ( ) => {
233+ this . initializeUserLifetimeMetrics ( ) ;
234+ } ;
235+
236+ dbRequest . onsuccess = ( ) => {
237+ try {
238+ const db = dbRequest . result ;
239+ const transaction = db ?. transaction ( "Main" , "readwrite" ) ;
240+ const store = transaction . objectStore ( "Main" ) ;
241+
242+ // All the core metrics are stored in the userLifetimeMetrics object.
243+ const req = store . get ( "userLifetimeMetrics" ) ;
244+ req . onsuccess = ( ) => {
245+ // Pull and set the existing clientId.
246+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
247+ const clientId = req . result ?. [ "glean_client_info" ] ?. [ "uuid" ] ?. [ "client_id" ] as string ;
248+ if ( ! ! clientId ) {
249+ this . clientId . set ( clientId ) ;
250+ } else {
251+ this . initializeClientId ( ) ;
252+ }
253+
254+ // Pull and set the existing firstRunDate.
255+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
256+ const firstRunDate = req . result ?. [ "glean_client_info" ] ?. [ "datetime" ] ?. [
257+ "first_run_date"
258+ ] as {
259+ date : string ;
260+ timezone : number ;
261+ timeUnit : TimeUnit ;
262+ } ;
263+ if ( ! ! firstRunDate ) {
264+ this . firstRunDate . setSyncRaw (
265+ firstRunDate . date ,
266+ firstRunDate . timezone ,
267+ firstRunDate . timeUnit
268+ ) ;
269+ } else {
270+ this . initializeFirstRunDate ( ) ;
271+ }
272+ } ;
273+
274+ req . onerror = ( ) => {
275+ this . initializeUserLifetimeMetrics ( ) ;
276+ } ;
277+ } catch ( e ) {
278+ // Fail-safe in case any generic error occurs.
279+ this . initializeUserLifetimeMetrics ( ) ;
280+ }
281+ } ;
282+ }
190283}
0 commit comments