File tree Expand file tree Collapse file tree 4 files changed +82
-5
lines changed
packages/sqlite_async/lib/src/web Expand file tree Collapse file tree 4 files changed +82
-5
lines changed Original file line number Diff line number Diff line change @@ -5,6 +5,7 @@ import 'package:sqlite3/common.dart';
5
5
import 'package:sqlite3_web/sqlite3_web.dart' ;
6
6
import 'package:sqlite_async/sqlite_async.dart' ;
7
7
import 'package:sqlite_async/src/utils/shared_utils.dart' ;
8
+ import 'package:sqlite_async/src/web/database/broadcast_updates.dart' ;
8
9
import 'package:sqlite_async/web.dart' ;
9
10
import 'protocol.dart' ;
10
11
import 'web_mutex.dart' ;
@@ -15,10 +16,14 @@ class WebDatabase
15
16
final Database _database;
16
17
final Mutex ? _mutex;
17
18
19
+ /// For persistent databases that aren't backed by a shared worker, we use
20
+ /// web broadcast channels to forward local update events to other tabs.
21
+ final BroadcastUpdates ? broadcastUpdates;
22
+
18
23
@override
19
24
bool closed = false ;
20
25
21
- WebDatabase (this ._database, this ._mutex);
26
+ WebDatabase (this ._database, this ._mutex, { this .broadcastUpdates} );
22
27
23
28
@override
24
29
Future <void > close () async {
Original file line number Diff line number Diff line change
1
+ import 'dart:js_interop' ;
2
+
3
+ import 'package:sqlite_async/sqlite_async.dart' ;
4
+ import 'package:web/web.dart' as web;
5
+
6
+ /// Utility to share received [UpdateNotification] s with other tabs using
7
+ /// broadcast channels.
8
+ class BroadcastUpdates {
9
+ final web.BroadcastChannel _channel;
10
+
11
+ BroadcastUpdates ._(this ._channel);
12
+
13
+ BroadcastUpdates (String name)
14
+ : _channel = web.BroadcastChannel ('sqlite3_async_updates/$name ' );
15
+
16
+ Stream <UpdateNotification > get updates {
17
+ return web.EventStreamProviders .messageEvent
18
+ .forTarget (_channel)
19
+ .map ((event) {
20
+ final data = event.data as _BroadcastMessage ;
21
+ if (data.a == 0 ) {
22
+ final payload = data.b as JSArray <JSString >;
23
+ return UpdateNotification (
24
+ payload.toDart.map ((e) => e.toDart).toSet ());
25
+ } else {
26
+ return null ;
27
+ }
28
+ })
29
+ .where ((e) => e != null )
30
+ .cast ();
31
+ }
32
+
33
+ void send (UpdateNotification notification) {
34
+ _channel.postMessage (_BroadcastMessage .notifications (notification));
35
+ }
36
+ }
37
+
38
+ @JS ()
39
+ @anonymous
40
+ extension type _BroadcastMessage ._(JSObject _) implements JSObject {
41
+ external int get a;
42
+ external JSAny get b;
43
+
44
+ external factory _BroadcastMessage ({required int a, required JSAny b});
45
+
46
+ factory _BroadcastMessage .notifications (UpdateNotification notification) {
47
+ return _BroadcastMessage (
48
+ a: 0 ,
49
+ b: notification.tables.toList ().map ((e) => e.toJS).toList ().toJS,
50
+ );
51
+ }
52
+ }
Original file line number Diff line number Diff line change @@ -85,9 +85,20 @@ class SqliteDatabaseImpl
85
85
Future <void > _init () async {
86
86
_connection = await openFactory.openConnection (SqliteOpenOptions (
87
87
primaryConnection: true , readOnly: false , mutex: mutex)) as WebDatabase ;
88
- _connection.updates.forEach ((update) {
89
- updatesController.add (update);
90
- });
88
+
89
+ final broadcastUpdates = _connection.broadcastUpdates;
90
+ if (broadcastUpdates == null ) {
91
+ // We can use updates directly from the database.
92
+ _connection.updates.forEach ((update) {
93
+ updatesController.add (update);
94
+ });
95
+ } else {
96
+ // Share local updates with other tabs
97
+ _connection.updates.forEach (broadcastUpdates.send);
98
+
99
+ // Also add updates from other tabs
100
+ updatesController.addStream (broadcastUpdates.updates);
101
+ }
91
102
}
92
103
93
104
T _runZoned <T >(T Function () callback, {required String debugContext}) {
@@ -132,6 +143,7 @@ class SqliteDatabaseImpl
132
143
@override
133
144
Future <void > close () async {
134
145
await isInitialized;
146
+ updatesController.close ();
135
147
return _connection.close ();
136
148
}
137
149
Original file line number Diff line number Diff line change @@ -3,6 +3,7 @@ import 'dart:async';
3
3
import 'package:sqlite3/wasm.dart' ;
4
4
import 'package:sqlite3_web/sqlite3_web.dart' ;
5
5
import 'package:sqlite_async/sqlite_async.dart' ;
6
+ import 'package:sqlite_async/src/web/database/broadcast_updates.dart' ;
6
7
import 'package:sqlite_async/src/web/web_mutex.dart' ;
7
8
8
9
import 'database.dart' ;
@@ -57,7 +58,14 @@ class DefaultSqliteOpenFactory
57
58
? null
58
59
: MutexImpl (identifier: path); // Use the DB path as a mutex identifier
59
60
60
- return WebDatabase (connection.database, options.mutex ?? mutex);
61
+ BroadcastUpdates ? updates;
62
+ if (connection.access != AccessMode .throughSharedWorker &&
63
+ connection.storage != StorageMode .inMemory) {
64
+ updates = BroadcastUpdates (path);
65
+ }
66
+
67
+ return WebDatabase (connection.database, options.mutex ?? mutex,
68
+ broadcastUpdates: updates);
61
69
}
62
70
63
71
@override
You can’t perform that action at this time.
0 commit comments