210 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Dart
		
	
	
			
		
		
	
	
			210 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Dart
		
	
	
| import 'dart:convert';
 | |
| import 'dart:io';
 | |
| 
 | |
| import 'package:firebase_remote_config/firebase_remote_config.dart';
 | |
| import 'package:guru_app/ads/core/ads_config.dart';
 | |
| import 'package:guru_app/analytics/data/analytics_model.dart';
 | |
| import 'package:guru_app/firebase/remoteconfig/reserved_remote_config_models.dart';
 | |
| import 'package:guru_app/guru_app.dart';
 | |
| import 'package:guru_utils/http/http_model.dart';
 | |
| import 'package:guru_utils/log/log.dart';
 | |
| import 'package:rxdart/rxdart.dart';
 | |
| import 'package:guru_utils/remote/remote_config.dart';
 | |
| 
 | |
| part "remote_config_interface.dart";
 | |
| 
 | |
| /// Created by Haoyi on 2020/4/22
 | |
| ///
 | |
| part "remote_config_reserved_constants.dart";
 | |
| 
 | |
| class RemoteConfigManager extends IRemoteConfig {
 | |
|   final BehaviorSubject<FirebaseRemoteConfig?> _subject =
 | |
|       BehaviorSubject.seeded(null);
 | |
|   static RemoteConfigManager? _instance;
 | |
| 
 | |
|   static RemoteConfigManager _getInstance() {
 | |
|     _instance ??= RemoteConfigManager._internal();
 | |
|     return _instance!;
 | |
|   }
 | |
| 
 | |
|   factory RemoteConfigManager() => _getInstance();
 | |
| 
 | |
|   static RemoteConfigManager get instance => _getInstance();
 | |
| 
 | |
|   static final RegExp _invalidABKey = RegExp('[^a-zA-Z0-9_-]');
 | |
| 
 | |
|   RemoteConfigManager._internal();
 | |
| 
 | |
|   Future<void> init(Map<String, dynamic> defaultConfigs) async {
 | |
|     final remoteConfig = FirebaseRemoteConfig.instance;
 | |
|     await remoteConfig.setConfigSettings(RemoteConfigSettings(
 | |
|       fetchTimeout: const Duration(seconds: 15),
 | |
|       minimumFetchInterval: const Duration(hours: 2),
 | |
|     ));
 | |
| 
 | |
|     _subject.add(remoteConfig);
 | |
| 
 | |
|     try {
 | |
|       await remoteConfig.setDefaults(defaultConfigs);
 | |
|       await remoteConfig.activate();
 | |
|     } catch (exception) {
 | |
|       Log.d(
 | |
|           "Unable to fetch remote config. Cached or default values will be used!",
 | |
|           error: exception);
 | |
|     } finally {
 | |
|       _subject.add(remoteConfig);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future fetchAndActivate() async {
 | |
|     final remoteConfig = FirebaseRemoteConfig.instance;
 | |
|     try {
 | |
|       await remoteConfig.fetchAndActivate();
 | |
|     } catch (exception) {
 | |
|       Log.d(
 | |
|           "Unable to fetch remote config. Cached or default values will be used!",
 | |
|           error: exception);
 | |
|     } finally {
 | |
|       _subject.add(remoteConfig);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Future<String> dumpString() async {
 | |
|     final config = FirebaseRemoteConfig.instance;
 | |
|     final data = config.getAll();
 | |
|     String result = "";
 | |
|     for (var entry in data.entries) {
 | |
|       result += "[${entry.key}] ==> (${entry.value.asString()})\n";
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   static String valueSourceToString(ValueSource source) {
 | |
|     switch (source) {
 | |
|       case ValueSource.valueRemote:
 | |
|         return "Remote";
 | |
|       case ValueSource.valueStatic:
 | |
|         return "Static";
 | |
|       default:
 | |
|         return "Default";
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Map<String, String> allData() {
 | |
|     final config = FirebaseRemoteConfig.instance;
 | |
|     final data = config.getAll();
 | |
|     final result = {
 | |
|       for (var entry in data.entries)
 | |
|         "${entry.key} [${valueSourceToString(entry.value.source)}]":
 | |
|             entry.value.asString()
 | |
|     };
 | |
|     result["last_fetch_remote_config_time"] = config.lastFetchTime.toString();
 | |
|     result["last_fetch_remote_config_status"] =
 | |
|         config.lastFetchStatus.toString();
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   Future forceFetch({bool debug = false}) async {
 | |
|     final remoteConfig = FirebaseRemoteConfig.instance;
 | |
|     try {
 | |
|       await remoteConfig.setConfigSettings(RemoteConfigSettings(
 | |
|         fetchTimeout: const Duration(seconds: 15),
 | |
|         minimumFetchInterval: const Duration(seconds: 0),
 | |
|       ));
 | |
|       await remoteConfig.fetchAndActivate();
 | |
|     } catch (exception) {
 | |
|       Log.d(
 | |
|           "Unable to fetch remote config. Cached or default values will be used $exception",
 | |
|           error: exception);
 | |
|       if (debug) {
 | |
|         rethrow;
 | |
|       }
 | |
|     } finally {
 | |
|       _subject.add(remoteConfig);
 | |
|       await remoteConfig.setConfigSettings(RemoteConfigSettings(
 | |
|         fetchTimeout: const Duration(seconds: 15),
 | |
|         minimumFetchInterval: const Duration(hours: 2),
 | |
|       ));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Map<String, String> getABProperties() {
 | |
|     final config = FirebaseRemoteConfig.instance;
 | |
|     final data = config.getAll();
 | |
|     final result = <String, String>{};
 | |
|     final invalidABKeys = <String>{};
 | |
|     dynamic cause;
 | |
|     for (var entry in data.entries) {
 | |
|       final valueStr = entry.value.asString();
 | |
|       if (valueStr.contains("guru_ab_")) {
 | |
|         try {
 | |
|           final jsonValue = json.decode(valueStr);
 | |
|           if (jsonValue is Map<String, dynamic>) {
 | |
|             for (var jsonEntry in jsonValue.entries) {
 | |
|               if (jsonEntry.key.contains("guru_ab_")) {
 | |
|                 String abName = jsonEntry.key.replaceFirst("guru_ab_", "");
 | |
|                 if (abName.contains(_invalidABKey)) {
 | |
|                   Log.w("abName($abName) length is invalid! $abName");
 | |
|                   invalidABKeys.add(abName);
 | |
|                 } else {
 | |
|                   if (abName.length > 20) {
 | |
|                     invalidABKeys.add(abName);
 | |
|                     abName = abName.substring(0, 20);
 | |
|                   }
 | |
|                   result["ab_$abName"] = jsonEntry.value.toString();
 | |
|                   Log.i("abName:ab_$abName value:${jsonEntry.value}");
 | |
|                 }
 | |
|               }
 | |
|             }
 | |
|           }
 | |
|         } catch (error, stacktrace) {
 | |
|           Log.w("decode json error! $error");
 | |
|           cause = error;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|     if (invalidABKeys.isNotEmpty) {
 | |
|       GuruAnalytics.instance.logException(
 | |
|           InvalidABPropertyKeysException(invalidABKeys, cause: cause));
 | |
|     }
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   @override
 | |
|   bool? getBool(String name, {bool? defaultValue}) =>
 | |
|       _subject.value?.getBool(name) ?? defaultValue;
 | |
| 
 | |
|   @override
 | |
|   String? getString(String name, {String? defaultValue}) =>
 | |
|       _subject.value?.getString(name) ??
 | |
|       defaultValue ??
 | |
|       RemoteConfigReservedConstants.getDefaultConfigString(name);
 | |
| 
 | |
|   @override
 | |
|   double? getDouble(String name, {double? defaultValue}) =>
 | |
|       _subject.value?.getDouble(name) ?? defaultValue;
 | |
| 
 | |
|   @override
 | |
|   int? getInt(String name, {int? defaultValue}) =>
 | |
|       _subject.value?.getInt(name) ?? defaultValue;
 | |
| 
 | |
|   Stream<FirebaseRemoteConfig> observeConfig() =>
 | |
|       _subject.stream.map((config) => config ?? FirebaseRemoteConfig.instance);
 | |
| 
 | |
|   @override
 | |
|   Stream<bool?> observeBool(String name, {bool? defaultValue}) =>
 | |
|       observeConfig().map((config) => config.getBool(name));
 | |
| 
 | |
|   @override
 | |
|   Stream<String?> observeString(String name, {String? defaultValue}) =>
 | |
|       observeConfig().map((config) => config.getString(name));
 | |
| 
 | |
|   @override
 | |
|   Stream<double?> observeDouble(String name, {double? defaultValue}) =>
 | |
|       observeConfig().map((config) => config.getDouble(name));
 | |
| 
 | |
|   @override
 | |
|   Stream<int?> observeInt(String name, {int? defaultValue}) =>
 | |
|       observeConfig().map((config) => config.getInt(name));
 | |
| }
 |