Skip to content

Commit

Permalink
feat(remote_config, web): migrate web to js_interop to be compatible …
Browse files Browse the repository at this point in the history
…with WASM (#12489)

* feat(analytics, web): migrate web to js_interop to be compatible with WASM

* fix version
  • Loading branch information
Lyokone committed Mar 19, 2024
1 parent 363f88a commit 85a9b18
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 46 deletions.
Expand Up @@ -3,8 +3,11 @@
// BSD-style license that can be found in the LICENSE file.

import 'dart:convert' show utf8;
import 'dart:js_interop';

import 'package:firebase_core_web/firebase_core_web_interop.dart';
import 'package:firebase_remote_config_platform_interface/firebase_remote_config_platform_interface.dart';

import 'firebase_remote_config_interop.dart' as remote_config_interop;

/// Given an AppJSImp, return the Remote Config instance.
Expand Down Expand Up @@ -55,12 +58,14 @@ class RemoteConfig

/// Returns the timestamp of the last *successful* fetch.
DateTime get fetchTime {
return DateTime.fromMillisecondsSinceEpoch(jsObject.fetchTimeMillis);
return DateTime.fromMillisecondsSinceEpoch(
jsObject.fetchTimeMillis.toDartInt,
);
}

/// The status of the last fetch attempt.
RemoteConfigFetchStatus get lastFetchStatus {
switch (jsObject.lastFetchStatus) {
switch (jsObject.lastFetchStatus.toDart) {
case 'no-fetch-yet':
return RemoteConfigFetchStatus.notFetchedYet;
case 'success':
Expand All @@ -70,29 +75,33 @@ class RemoteConfig
case 'throttle':
return RemoteConfigFetchStatus.throttle;
default:
throw UnimplementedError(jsObject.lastFetchStatus);
throw UnimplementedError(jsObject.lastFetchStatus.toDart);
}
}

/// Makes the last fetched config available to the getters.
/// Returns a future which resolves to `true` if the current call activated the fetched configs.
/// If the fetched configs were already activated, the promise will resolve to `false`.
Future<bool> activate() async =>
handleThenable(remote_config_interop.activate(jsObject));
Future<bool> activate() async => remote_config_interop
.activate(jsObject)
.toDart
.then((value) => value! as bool);

/// Ensures the last activated config are available to the getters.
Future<void> ensureInitialized() async =>
handleThenable(remote_config_interop.ensureInitialized(jsObject));
remote_config_interop.ensureInitialized(jsObject).toDart;

/// Fetches and caches configuration from the Remote Config service.
Future<void> fetch() async =>
handleThenable(remote_config_interop.fetchConfig(jsObject));
remote_config_interop.fetchConfig(jsObject).toDart;

/// Performs fetch and activate operations, as a convenience.
/// Returns a promise which resolves to true if the current call activated the fetched configs.
/// If the fetched configs were already activated, the promise will resolve to false.
Future<bool> fetchAndActivate() async =>
handleThenable(remote_config_interop.fetchAndActivate(jsObject));
remote_config_interop.fetchAndActivate(jsObject).toDart.then(
(value) => value! as bool,
);

/// Returns all config values.
Map<String, RemoteConfigValue> getAll() {
Expand All @@ -104,23 +113,28 @@ class RemoteConfig
}

RemoteConfigValue getValue(String key) => RemoteConfigValue(
utf8.encode(remote_config_interop.getValue(jsObject, key).asString()),
getSource(remote_config_interop.getValue(jsObject, key).getSource()),
utf8.encode(
remote_config_interop.getValue(jsObject, key.toJS).asString().toDart,
),
getSource(
remote_config_interop.getValue(jsObject, key.toJS).getSource().toDart,
),
);

/// Gets the value for the given key as a boolean.
/// Convenience method for calling `remoteConfig.getValue(key).asString()`.
bool getBoolean(String key) =>
remote_config_interop.getBoolean(jsObject, key);
remote_config_interop.getBoolean(jsObject, key.toJS).toDart;

/// Gets the value for the given key as a number.
/// Convenience method for calling `remoteConfig.getValue(key).asNumber()`.
num getNumber(String key) => remote_config_interop.getNumber(jsObject, key);
num getNumber(String key) =>
remote_config_interop.getNumber(jsObject, key.toJS).toDartDouble;

/// Gets the value for the given key as a string.
/// Convenience method for calling `remoteConfig.getValue(key).asString()`.
String getString(String key) =>
remote_config_interop.getString(jsObject, key);
remote_config_interop.getString(jsObject, key.toJS).toDart;

void setLogLevel(RemoteConfigLogLevel value) {
remote_config_interop.setLogLevel(
Expand All @@ -129,7 +143,8 @@ class RemoteConfig
RemoteConfigLogLevel.debug: 'debug',
RemoteConfigLogLevel.error: 'error',
RemoteConfigLogLevel.silent: 'silent',
}[value]!,
}[value]!
.toJS,
);
}
}
Expand Down Expand Up @@ -157,19 +172,19 @@ class RemoteConfigSettings
/// Defines the maximum age in milliseconds of an entry in the config cache before
/// it is considered stale. Defaults to twelve hours.
Duration get minimumFetchInterval =>
Duration(milliseconds: jsObject.minimumFetchIntervalMillis);
Duration(milliseconds: jsObject.minimumFetchIntervalMillis.toDartInt);

set minimumFetchInterval(Duration value) {
jsObject.minimumFetchIntervalMillis = value.inMilliseconds;
jsObject.minimumFetchIntervalMillis = value.inMilliseconds.toJS;
}

/// Defines the maximum amount of time to wait for a response when fetching
/// configuration from the Remote Config server. Defaults to one minute.
Duration get fetchTimeoutMillis =>
Duration(milliseconds: jsObject.fetchTimeoutMillis);
Duration(milliseconds: jsObject.fetchTimeoutMillis.toDartInt);

set fetchTimeoutMillis(Duration value) {
jsObject.fetchTimeoutMillis = value.inMilliseconds;
jsObject.fetchTimeoutMillis = value.inMilliseconds.toJS;
}
}

Expand Down
Expand Up @@ -7,71 +7,93 @@
@JS('firebase_remote_config')
library firebase.remote_config_interop;

import 'package:js/js.dart';
import 'dart:js_interop';

import 'package:firebase_core_web/firebase_core_web_interop.dart';

@JS()
@staticInterop
external RemoteConfigJsImpl getRemoteConfig([AppJsImpl? app]);

@JS()
external PromiseJsImpl<bool> activate(RemoteConfigJsImpl remoteConfig);
@staticInterop
external JSPromise /* bool */ activate(RemoteConfigJsImpl remoteConfig);

@JS()
external PromiseJsImpl<void> ensureInitialized(RemoteConfigJsImpl remoteConfig);
@staticInterop
external JSPromise ensureInitialized(RemoteConfigJsImpl remoteConfig);

@JS()
external PromiseJsImpl<bool> fetchAndActivate(RemoteConfigJsImpl remoteConfig);
@staticInterop
external JSPromise /* bool */ fetchAndActivate(RemoteConfigJsImpl remoteConfig);

@JS()
external PromiseJsImpl<void> fetchConfig(RemoteConfigJsImpl remoteConfig);
@staticInterop
external JSPromise fetchConfig(RemoteConfigJsImpl remoteConfig);

@JS()
external dynamic getAll(RemoteConfigJsImpl remoteConfig);
@staticInterop
external JSAny getAll(RemoteConfigJsImpl remoteConfig);

@JS()
external bool getBoolean(RemoteConfigJsImpl remoteConfig, String key);
@staticInterop
external JSBoolean getBoolean(RemoteConfigJsImpl remoteConfig, JSString key);

@JS()
external num getNumber(RemoteConfigJsImpl remoteConfig, String key);
@staticInterop
external JSNumber getNumber(RemoteConfigJsImpl remoteConfig, JSString key);

@JS()
external String getString(RemoteConfigJsImpl remoteConfig, String key);
@staticInterop
external JSString getString(RemoteConfigJsImpl remoteConfig, JSString key);

@JS()
external ValueJsImpl getValue(RemoteConfigJsImpl remoteConfig, String key);
@staticInterop
external ValueJsImpl getValue(RemoteConfigJsImpl remoteConfig, JSString key);

// TODO - api to be implemented
@JS()
external PromiseJsImpl<void> isSupported();
@staticInterop
external JSPromise isSupported();

@JS()
external void setLogLevel(RemoteConfigJsImpl remoteConfig, String logLevel);
@staticInterop
external void setLogLevel(RemoteConfigJsImpl remoteConfig, JSString logLevel);

@JS('RemoteConfig')
abstract class RemoteConfigJsImpl {
@staticInterop
abstract class RemoteConfigJsImpl {}

extension RemoteConfigJsImplExtension on RemoteConfigJsImpl {
external AppJsImpl get app;
external SettingsJsImpl get settings;
external set settings(SettingsJsImpl value);
external Object get defaultConfig;
external set defaultConfig(Object value);
external int get fetchTimeMillis;
external String get lastFetchStatus;
external JSObject get defaultConfig;
external set defaultConfig(JSObject value);
external JSNumber get fetchTimeMillis;
external JSString get lastFetchStatus;
}

@JS()
@staticInterop
@anonymous
abstract class ValueJsImpl {
external bool asBoolean();
external num asNumber();
external String asString();
external String getSource();
abstract class ValueJsImpl {}

extension ValueJsImplExtension on ValueJsImpl {
external JSBoolean asBoolean();
external JSNumber asNumber();
external JSString asString();
external JSString getSource();
}

@JS()
@staticInterop
@anonymous
abstract class SettingsJsImpl {
external int get minimumFetchIntervalMillis;
external set minimumFetchIntervalMillis(int value);
external int get fetchTimeoutMillis;
external set fetchTimeoutMillis(int value);
abstract class SettingsJsImpl {}

extension SettingsJsImplExtension on SettingsJsImpl {
external JSNumber get minimumFetchIntervalMillis;
external set minimumFetchIntervalMillis(JSNumber value);
external JSNumber get fetchTimeoutMillis;
external set fetchTimeoutMillis(JSNumber value);
}
Expand Up @@ -6,7 +6,7 @@ repository: https://github.com/firebase/flutterfire/tree/master/packages/firebas
version: 1.4.26

environment:
sdk: '>=2.18.0 <4.0.0'
sdk: '>=3.2.0 <4.0.0'
flutter: '>=3.3.0'

dependencies:
Expand All @@ -18,6 +18,7 @@ dependencies:
flutter_web_plugins:
sdk: flutter
js: ^0.6.3
web: ^0.5.1

dev_dependencies:
build_runner: ^2.3.3
Expand Down

0 comments on commit 85a9b18

Please sign in to comment.