Skip to content

Commit 8a0b75d

Browse files
committed
sqlite web: Support requests to client
1 parent 95d01bd commit 8a0b75d

File tree

7 files changed

+63
-19
lines changed

7 files changed

+63
-19
lines changed

sqlite3_web/lib/src/client.dart

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import 'dart:js_interop_unsafe';
44
import 'dart:typed_data';
55

66
import 'package:sqlite3/wasm.dart' hide WorkerOptions;
7+
import 'package:stream_channel/stream_channel.dart';
78
import 'package:web/web.dart'
89
hide Response, Request, FileSystem, Notification, Lock;
910

@@ -257,15 +258,21 @@ final class RemoteFileSystem implements FileSystem {
257258
final class WorkerConnection extends ProtocolChannel {
258259
final StreamController<Notification> notifications =
259260
StreamController.broadcast();
261+
final Future<JSAny?> Function(JSAny?) handleCustomRequest;
260262

261-
WorkerConnection(super.channel) {
263+
WorkerConnection(super.channel, this.handleCustomRequest) {
262264
closed.whenComplete(notifications.close);
263265
}
264266

265267
@override
266-
Future<Response> handleRequest(Request request) {
267-
// TODO: implement handleRequest
268-
throw UnimplementedError();
268+
Future<Response> handleRequest(Request request) async {
269+
switch (request) {
270+
case CustomRequest(requestId: final id, :final payload):
271+
final response = await handleCustomRequest(payload);
272+
return SimpleSuccessResponse(response: response, requestId: id);
273+
default:
274+
throw UnimplementedError();
275+
}
269276
}
270277

271278
@override
@@ -278,6 +285,7 @@ final class DatabaseClient implements WebSqlite {
278285
final Uri workerUri;
279286
final Uri wasmUri;
280287
final DatabaseController _localController;
288+
final Future<JSAny?> Function(JSAny?) _handleCustomRequest;
281289

282290
final Lock _startWorkersLock = Lock();
283291
bool _startedWorkers = false;
@@ -289,7 +297,12 @@ final class DatabaseClient implements WebSqlite {
289297

290298
final Set<MissingBrowserFeature> _missingFeatures = {};
291299

292-
DatabaseClient(this.workerUri, this.wasmUri, this._localController);
300+
DatabaseClient(this.workerUri, this.wasmUri, this._localController,
301+
Future<JSAny?> Function(JSAny?)? handleCustomRequest)
302+
: _handleCustomRequest = handleCustomRequest ??
303+
((_) async {
304+
throw StateError('No custom request handler installed');
305+
});
293306

294307
Future<void> startWorkers() {
295308
return _startWorkersLock.synchronized(() async {
@@ -303,6 +316,10 @@ final class DatabaseClient implements WebSqlite {
303316
});
304317
}
305318

319+
WorkerConnection _connection(StreamChannel<Message> channel) {
320+
return WorkerConnection(channel, _handleCustomRequest);
321+
}
322+
306323
Future<void> _startDedicated() async {
307324
if (globalContext.has('Worker')) {
308325
final Worker dedicated;
@@ -319,8 +336,7 @@ final class DatabaseClient implements WebSqlite {
319336
final (endpoint, channel) = await createChannel();
320337
ConnectRequest(endpoint: endpoint, requestId: 0).sendToWorker(dedicated);
321338

322-
_connectionToDedicated =
323-
WorkerConnection(channel.injectErrorsFrom(dedicated));
339+
_connectionToDedicated = _connection(channel.injectErrorsFrom(dedicated));
324340
} else {
325341
_missingFeatures.add(MissingBrowserFeature.dedicatedWorkers);
326342
}
@@ -341,7 +357,7 @@ final class DatabaseClient implements WebSqlite {
341357
final (endpoint, channel) = await createChannel();
342358
ConnectRequest(endpoint: endpoint, requestId: 0).sendToPort(shared.port);
343359

344-
_connectionToShared = WorkerConnection(channel.injectErrorsFrom(shared));
360+
_connectionToShared = _connection(channel.injectErrorsFrom(shared));
345361
} else {
346362
_missingFeatures.add(MissingBrowserFeature.sharedWorkers);
347363
}
@@ -358,7 +374,7 @@ final class DatabaseClient implements WebSqlite {
358374
ConnectRequest(requestId: 0, endpoint: endpoint),
359375
MessageType.simpleSuccessResponse);
360376

361-
return _connectionToDedicatedInShared = WorkerConnection(channel);
377+
return _connectionToDedicatedInShared = _connection(channel);
362378
});
363379
}
364380

@@ -374,7 +390,7 @@ final class DatabaseClient implements WebSqlite {
374390
local
375391
.addTopLevelMessage(ConnectRequest(requestId: 0, endpoint: endpoint));
376392

377-
return _connectionToLocal = WorkerConnection(channel);
393+
return _connectionToLocal = _connection(channel);
378394
});
379395
}
380396

@@ -512,7 +528,7 @@ final class DatabaseClient implements WebSqlite {
512528
}
513529

514530
Future<Database> connectToExisting(SqliteWebEndpoint endpoint) async {
515-
final channel = WorkerConnection(
531+
final channel = _connection(
516532
WebEndpoint(port: endpoint.$1, lockName: endpoint.$2).connect());
517533

518534
return RemoteDatabase(

sqlite3_web/lib/src/database.dart

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ abstract class ClientConnection {
123123
/// because the owning tab is closed.
124124
Future<void> get closed;
125125

126-
/// Sends a custom request __towards the client__. This is not currently
127-
/// implemented.
126+
/// Sends a custom request __towards the client__.
128127
Future<JSAny?> customRequest(JSAny? request);
129128
}
130129

@@ -230,15 +229,21 @@ abstract class WebSqlite {
230229
/// The [controller] is used when connecting to a sqlite3 database without
231230
/// using workers. It should typically be the same implementation as the one
232231
/// passed to [workerEntrypoint].
232+
///
233+
/// The optional [handleCustomRequest] function is invoked when the controller
234+
/// sends a custom request to the client (via [ClientConnection.customRequest]).
235+
/// If it's absent, the default is to throw an exception when called.
233236
static WebSqlite open({
234237
required Uri worker,
235238
required Uri wasmModule,
236239
DatabaseController? controller,
240+
Future<JSAny?> Function(JSAny?)? handleCustomRequest,
237241
}) {
238242
return DatabaseClient(
239243
worker,
240244
wasmModule,
241245
controller ?? const _DefaultDatabaseController(),
246+
handleCustomRequest,
242247
);
243248
}
244249

@@ -253,9 +258,16 @@ abstract class WebSqlite {
253258
/// be valid as long as the original [Database] where [Database.additionalConnection]
254259
/// was called. This limitation does not exist for databases hosted by shared
255260
/// workers.
256-
static Future<Database> connectToPort(SqliteWebEndpoint endpoint) {
257-
final client =
258-
DatabaseClient(Uri.base, Uri.base, const _DefaultDatabaseController());
261+
///
262+
/// The optional [handleCustomRequest] function is invoked when the controller
263+
/// sends a custom request to the client (via [ClientConnection.customRequest]).
264+
/// If it's absent, the default is to throw an exception when called.
265+
static Future<Database> connectToPort(
266+
SqliteWebEndpoint endpoint, {
267+
Future<JSAny?> Function(JSAny?)? handleCustomRequest,
268+
}) {
269+
final client = DatabaseClient(Uri.base, Uri.base,
270+
const _DefaultDatabaseController(), handleCustomRequest);
259271
return client.connectToExisting(endpoint);
260272
}
261273
}

sqlite3_web/lib/src/worker.dart

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,6 @@ final class _ClientConnection extends ProtocolChannel
354354
return SimpleSuccessResponse(response: null, requestId: request.requestId);
355355
}
356356

357-
void handleStreamCancelRequest() {}
358-
359357
@override
360358
void handleNotification(Notification notification) {
361359
// There aren't supposed to be any notifications from the client.

sqlite3_web/test/integration_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,8 @@ final class _TestConfiguration {
209209
);
210210
await driver.assertFile(false);
211211

212+
expect(await driver.customRequest(), 42);
213+
212214
await driver.execute('CREATE TABLE foo (bar TEXT);');
213215
var events = await driver.countEvents();
214216
expect(events.updates, 0);

sqlite3_web/tool/server.dart

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,13 @@ class TestWebDriver {
210210
}
211211
}
212212

213+
Future<int> customRequest() async {
214+
final res =
215+
await driver.executeAsync('custom_request("", arguments[0])', []);
216+
217+
return res as int;
218+
}
219+
213220
Future<void> flush() async {
214221
final result = await driver.executeAsync('flush("", arguments[0])', []);
215222
if (result != true) {

sqlite3_web/web/controller.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ final class ExampleDatabase extends WorkerDatabase {
4343
@override
4444
Future<JSAny?> handleCustomRequest(
4545
ClientConnection connection, JSAny? request) async {
46-
return null;
46+
final response =
47+
((await connection.customRequest(null)) as JSNumber).toDartInt;
48+
49+
return (2 * response).toJS;
4750
}
4851
}

sqlite3_web/web/main.dart

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,9 @@ void main() {
133133

134134
return null;
135135
});
136+
_addCallbackForWebDriver('custom_request', (arg) async {
137+
return database!.customRequest(null);
138+
});
136139

137140
document.getElementById('selfcheck')?.onClick.listen((event) async {
138141
print('starting');
@@ -173,6 +176,9 @@ WebSqlite initializeSqlite() {
173176
worker: workerUri,
174177
wasmModule: sqlite3WasmUri,
175178
controller: ExampleController(isInWorker: false),
179+
handleCustomRequest: (request) async {
180+
return 21.toJS;
181+
},
176182
);
177183
}
178184

0 commit comments

Comments
 (0)