Skip to content

Commit 0ea7099

Browse files
fix(storage, web): clean up stream handlers on "hot restart" (#12927)
* fix(storage, web): clean up stream handlers on "hot restart" * fix(storage, web): only create one stream for task, fix task.pause()
1 parent e298cb4 commit 0ea7099

File tree

2 files changed

+28
-6
lines changed

2 files changed

+28
-6
lines changed

packages/firebase_storage/firebase_storage_web/lib/src/interop/storage.dart

+15-1
Original file line numberDiff line numberDiff line change
@@ -343,8 +343,17 @@ class UploadTask extends JsObjectWrapper<storage_interop.UploadTaskJsImpl> {
343343
/// Returns [:true:] if it had an effect.
344344
bool cancel() => jsObject.cancel().toDart;
345345

346+
String _taskSnapshotWindowsKey(String appName, String bucket, String path) =>
347+
'flutterfire-${appName}_${bucket}_${path}_storageTask';
348+
346349
/// Stream for upload task state changed event.
347-
Stream<UploadTaskSnapshot> get onStateChanged {
350+
Stream<UploadTaskSnapshot> onStateChanged(
351+
String appName,
352+
String bucket,
353+
String path,
354+
) {
355+
final windowsKey = _taskSnapshotWindowsKey(appName, bucket, path);
356+
unsubscribeWindowsListener(windowsKey);
348357
late StreamController<UploadTaskSnapshot> changeController;
349358
late JSFunction onStateChangedUnsubscribe;
350359

@@ -367,11 +376,16 @@ class UploadTask extends JsObjectWrapper<storage_interop.UploadTaskJsImpl> {
367376
errorWrapper,
368377
onCompletion,
369378
);
379+
setWindowsListener(
380+
windowsKey,
381+
onStateChangedUnsubscribe,
382+
);
370383
}
371384

372385
void stopListen() {
373386
onStateChangedUnsubscribe.callAsFunction();
374387
changeController.close();
388+
removeWindowsListener(windowsKey);
375389
}
376390

377391
changeController = StreamController<UploadTaskSnapshot>.broadcast(

packages/firebase_storage/firebase_storage_web/lib/src/task_web.dart

+13-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ class TaskWeb extends TaskPlatform {
2828

2929
final storage_interop.UploadTask _task;
3030

31+
Stream<TaskSnapshotPlatform>? _stream;
32+
3133
/// Returns a [Stream] of [TaskSnapshot] events.
3234
///
3335
/// If the task is canceled or fails, the stream will send an error event.
@@ -37,7 +39,7 @@ class TaskWeb extends TaskPlatform {
3739
/// wait for the stream to complete via [onComplete].
3840
@override
3941
Stream<TaskSnapshotPlatform> get snapshotEvents {
40-
return guard(() {
42+
_stream ??= guard(() {
4143
// The mobile version of the plugin pushes a "success" snapshot to the
4244
// onStateChanged stream, but the Firebase JS SDK does *not*.
4345
// We use a StreamGroup + Future.asStream to simulate that feature:
@@ -46,8 +48,13 @@ class TaskWeb extends TaskPlatform {
4648

4749
// This stream converts the UploadTask Snapshots from JS to the plugins'
4850
// It can also throw a FirebaseError internally, so we handle it.
49-
final onStateChangedStream =
50-
_task.onStateChanged.map<TaskSnapshotPlatform>((snapshot) {
51+
final onStateChangedStream = _task
52+
.onStateChanged(
53+
_reference.storage.app.name,
54+
_reference.bucket,
55+
_reference.fullPath,
56+
)
57+
.map<TaskSnapshotPlatform>((snapshot) {
5158
return fbUploadTaskSnapshotToTaskSnapshot(_reference, snapshot);
5259
});
5360

@@ -66,6 +73,8 @@ class TaskWeb extends TaskPlatform {
6673

6774
return group.stream;
6875
});
76+
77+
return _stream!;
6978
}
7079

7180
/// Returns a [Future] once the task has completed.
@@ -101,8 +110,7 @@ class TaskWeb extends TaskPlatform {
101110
final paused = _task.pause();
102111
// Wait until the snapshot is paused, then return the value of paused...
103112
return snapshotEvents
104-
.takeWhile((snapshot) => snapshot.state != TaskState.paused)
105-
.last
113+
.firstWhere((snapshot) => snapshot.state == TaskState.paused)
106114
.then<bool>((_) => paused);
107115
}
108116

0 commit comments

Comments
 (0)