mirror of https://github.com/AMT-Cheif/drift.git
Send serve messages in wasm setup
This commit is contained in:
parent
54b1b707a9
commit
0060e0ea44
|
@ -11,15 +11,21 @@ import 'dart:async';
|
|||
import 'dart:html';
|
||||
|
||||
import 'package:async/async.dart';
|
||||
import 'package:drift/remote.dart';
|
||||
import 'package:drift/wasm.dart';
|
||||
import 'package:js/js.dart';
|
||||
import 'package:js/js_util.dart';
|
||||
import 'package:sqlite3/wasm.dart';
|
||||
|
||||
import 'channel.dart';
|
||||
import 'wasm_setup/protocol.dart';
|
||||
|
||||
/// Whether the `crossOriginIsolated` JavaScript property is true in the current
|
||||
/// context.
|
||||
@JS()
|
||||
external bool get crossOriginIsolated;
|
||||
|
||||
/// Whether shared workers can be constructed in the current context.
|
||||
bool get supportsSharedWorkers => hasProperty(globalThis, 'SharedWorker');
|
||||
|
||||
Future<WasmDatabaseResult> openWasmDatabase({
|
||||
|
@ -27,6 +33,24 @@ Future<WasmDatabaseResult> openWasmDatabase({
|
|||
required Uri driftWorkerUri,
|
||||
required String databaseName,
|
||||
}) async {
|
||||
final missingFeatures = <MissingBrowserFeature>{};
|
||||
|
||||
Future<WasmDatabaseResult> connect(WasmStorageImplementation impl,
|
||||
void Function(WasmInitializationMessage) send) async {
|
||||
final channel = MessageChannel();
|
||||
final local = channel.port1.channel();
|
||||
final message = ServeDriftDatabase(
|
||||
sqlite3WasmUri: sqlite3WasmUri,
|
||||
port: channel.port2,
|
||||
storage: impl,
|
||||
databaseName: databaseName,
|
||||
);
|
||||
send(message);
|
||||
|
||||
final connection = await connectToRemoteAndInitialize(local);
|
||||
return WasmDatabaseResult(connection, impl, missingFeatures);
|
||||
}
|
||||
|
||||
// First, let's see if we can spawn dedicated workers in shared workers, which
|
||||
// would enable us to efficiently share a OPFS database.
|
||||
if (supportsSharedWorkers) {
|
||||
|
@ -39,17 +63,47 @@ Future<WasmDatabaseResult> openWasmDatabase({
|
|||
|
||||
// First, the shared worker will tell us which features it supports.
|
||||
final sharedFeatures = await sharedMessages.next as SharedWorkerStatus;
|
||||
|
||||
// Can we use the shared OPFS implementation?
|
||||
if (sharedFeatures.canSpawnDedicatedWorkers &&
|
||||
sharedFeatures.dedicatedWorkersCanUseOpfs) {
|
||||
return connect(
|
||||
WasmStorageImplementation.opfsShared, (msg) => msg.sendToPort(port));
|
||||
} else {
|
||||
missingFeatures.addAll(sharedFeatures.missingFeatures);
|
||||
await sharedMessages.cancel();
|
||||
port.close();
|
||||
}
|
||||
} else {
|
||||
// If we don't support shared workers, we might still have support for
|
||||
// OPFS in dedicated workers.
|
||||
final dedicatedWorker = Worker(driftWorkerUri.toString());
|
||||
DedicatedWorkerCompatibilityCheck().sendToWorker(dedicatedWorker);
|
||||
missingFeatures.add(MissingBrowserFeature.sharedWorkers);
|
||||
}
|
||||
|
||||
final workerMessages = StreamQueue(
|
||||
dedicatedWorker.onMessage.map(WasmInitializationMessage.fromJs));
|
||||
final dedicatedWorker = Worker(driftWorkerUri.toString());
|
||||
DedicatedWorkerCompatibilityCheck().sendToWorker(dedicatedWorker);
|
||||
|
||||
final status =
|
||||
await workerMessages.next as DedicatedWorkerCompatibilityResult;
|
||||
final workerMessages = StreamQueue(
|
||||
dedicatedWorker.onMessage.map(WasmInitializationMessage.fromJs));
|
||||
|
||||
final status =
|
||||
await workerMessages.next as DedicatedWorkerCompatibilityResult;
|
||||
missingFeatures.addAll(status.missingFeatures);
|
||||
|
||||
if (status.canAccessOpfs && status.supportsSharedArrayBuffers) {
|
||||
// todo send second worker to first one
|
||||
} else if (status.supportsIndexedDb) {
|
||||
return connect(WasmStorageImplementation.unsafeIndexedDb,
|
||||
(msg) => msg.sendToWorker(dedicatedWorker));
|
||||
} else {
|
||||
// Nothing works on this browser, so we'll fall back to an in-memory
|
||||
// database.
|
||||
final sqlite3 = await WasmSqlite3.loadFromUrl(sqlite3WasmUri);
|
||||
sqlite3.registerVirtualFileSystem(InMemoryFileSystem());
|
||||
|
||||
return WasmDatabaseResult(
|
||||
WasmDatabase(sqlite3: sqlite3, path: '/app.db'),
|
||||
WasmStorageImplementation.inMemory,
|
||||
missingFeatures,
|
||||
);
|
||||
}
|
||||
|
||||
throw 'todo';
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'dart:html';
|
|||
import 'package:drift/drift.dart';
|
||||
import 'package:drift/remote.dart';
|
||||
import 'package:drift/wasm.dart';
|
||||
import 'package:js/js_util.dart';
|
||||
import 'package:sqlite3/wasm.dart';
|
||||
|
||||
import '../channel.dart';
|
||||
|
@ -36,6 +37,8 @@ class DedicatedDriftWorker {
|
|||
DedicatedWorkerCompatibilityResult(
|
||||
canAccessOpfs: supportsOpfs,
|
||||
supportsIndexedDb: supportsIndexedDb,
|
||||
supportsSharedArrayBuffers:
|
||||
hasProperty(globalThis, 'SharedArrayBuffer'),
|
||||
).sendToClient(self);
|
||||
case ServeDriftDatabase():
|
||||
final server = _servers.putIfAbsent(message.databaseName, () {
|
||||
|
|
|
@ -62,12 +62,10 @@ final class SharedWorkerStatus extends WasmInitializationMessage {
|
|||
|
||||
final bool canSpawnDedicatedWorkers;
|
||||
final bool dedicatedWorkersCanUseOpfs;
|
||||
final bool canUseIndexedDb;
|
||||
|
||||
SharedWorkerStatus({
|
||||
required this.canSpawnDedicatedWorkers,
|
||||
required this.dedicatedWorkersCanUseOpfs,
|
||||
required this.canUseIndexedDb,
|
||||
});
|
||||
|
||||
factory SharedWorkerStatus.fromJsPayload(Object payload) {
|
||||
|
@ -76,7 +74,6 @@ final class SharedWorkerStatus extends WasmInitializationMessage {
|
|||
return SharedWorkerStatus(
|
||||
canSpawnDedicatedWorkers: data[0],
|
||||
dedicatedWorkersCanUseOpfs: data[1],
|
||||
canUseIndexedDb: data[2],
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -85,9 +82,18 @@ final class SharedWorkerStatus extends WasmInitializationMessage {
|
|||
sender.sendTyped(type, [
|
||||
canSpawnDedicatedWorkers,
|
||||
dedicatedWorkersCanUseOpfs,
|
||||
canUseIndexedDb
|
||||
]);
|
||||
}
|
||||
|
||||
Iterable<MissingBrowserFeature> get missingFeatures sync* {
|
||||
if (!canSpawnDedicatedWorkers) {
|
||||
yield MissingBrowserFeature.dedicatedWorkersInSharedWorkers;
|
||||
}
|
||||
|
||||
if (!dedicatedWorkersCanUseOpfs) {
|
||||
yield MissingBrowserFeature.fileSystemAccess;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A message sent by a worker when an error occurred.
|
||||
|
@ -168,16 +174,20 @@ final class DedicatedWorkerCompatibilityResult
|
|||
static const type = 'DedicatedWorkerCompatibilityResult';
|
||||
|
||||
final bool canAccessOpfs;
|
||||
final bool supportsSharedArrayBuffers;
|
||||
final bool supportsIndexedDb;
|
||||
|
||||
DedicatedWorkerCompatibilityResult({
|
||||
required this.canAccessOpfs,
|
||||
required this.supportsSharedArrayBuffers,
|
||||
required this.supportsIndexedDb,
|
||||
});
|
||||
|
||||
factory DedicatedWorkerCompatibilityResult.fromJsPayload(Object payload) {
|
||||
return DedicatedWorkerCompatibilityResult(
|
||||
canAccessOpfs: getProperty(payload, 'canAccessOpfs'),
|
||||
supportsSharedArrayBuffers:
|
||||
getProperty(payload, 'supportsSharedArrayBuffers'),
|
||||
supportsIndexedDb: getProperty(payload, 'supportsIndexedDb'),
|
||||
);
|
||||
}
|
||||
|
@ -187,9 +197,23 @@ final class DedicatedWorkerCompatibilityResult
|
|||
final object = newObject<Object>();
|
||||
setProperty(object, 'canAccessOpfs', canAccessOpfs);
|
||||
setProperty(object, 'supportsIndexedDb', supportsIndexedDb);
|
||||
setProperty(
|
||||
object, 'supportsSharedArrayBuffers', supportsSharedArrayBuffers);
|
||||
|
||||
sender.sendTyped(type, object);
|
||||
}
|
||||
|
||||
Iterable<MissingBrowserFeature> get missingFeatures sync* {
|
||||
if (!canAccessOpfs) {
|
||||
yield MissingBrowserFeature.fileSystemAccess;
|
||||
}
|
||||
if (!supportsSharedArrayBuffers) {
|
||||
yield MissingBrowserFeature.sharedArrayBuffers;
|
||||
}
|
||||
if (!supportsIndexedDb) {
|
||||
yield MissingBrowserFeature.indexedDb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final class StartFileSystemServer extends WasmInitializationMessage {
|
||||
|
|
|
@ -61,13 +61,11 @@ class SharedDriftWorker {
|
|||
Future<SharedWorkerStatus> _startFeatureDetection() async {
|
||||
// First, let's see if this shared worker can spawn dedicated workers.
|
||||
final hasWorker = hasProperty(self, 'Worker');
|
||||
final canUseIndexedDb = await checkIndexedDbSupport();
|
||||
|
||||
if (!hasWorker) {
|
||||
return SharedWorkerStatus(
|
||||
canSpawnDedicatedWorkers: false,
|
||||
dedicatedWorkersCanUseOpfs: false,
|
||||
canUseIndexedDb: canUseIndexedDb,
|
||||
);
|
||||
} else {
|
||||
final worker = _dedicatedWorker = Worker(Uri.base.toString());
|
||||
|
@ -83,7 +81,6 @@ class SharedDriftWorker {
|
|||
completer.complete(SharedWorkerStatus(
|
||||
canSpawnDedicatedWorkers: true,
|
||||
dedicatedWorkersCanUseOpfs: result,
|
||||
canUseIndexedDb: canUseIndexedDb,
|
||||
));
|
||||
|
||||
messageSubscription?.cancel();
|
||||
|
|
Loading…
Reference in New Issue