Skip to content

Commit

Permalink
[flutter_tools] Forward app.webLaunchUrl event from Flutter to DAP cl…
Browse files Browse the repository at this point in the history
…ients (#116275)

* [flutter_tools] Forward app.webLaunchUrl event from Flutter to DAP clients

Fixes Dart-Code/Dart-Code#4292.

* Update packages/flutter_tools/lib/src/debug_adapters/flutter_adapter.dart

Co-authored-by: Christopher Fujino <[email protected]>

* Another static const instead of final

Co-authored-by: Christopher Fujino <[email protected]>
  • Loading branch information
DanTup and christopherfujino authored Nov 30, 2022
1 parent fcc8ea1 commit a29796e
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
bool get supportsRestartRequest => true;

/// A list of reverse-requests from `flutter run --machine` that should be forwarded to the client.
final Set<String> _requestsToForwardToClient = <String>{
static const Set<String> _requestsToForwardToClient = <String>{
// The 'app.exposeUrl' request is sent by Flutter to request the client
// exposes a URL to the user and return the public version of that URL.
//
Expand All @@ -65,6 +65,14 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
'app.exposeUrl',
};

/// A list of events from `flutter run --machine` that should be forwarded to the client.
static const Set<String> _eventsToForwardToClient = <String>{
// The 'app.webLaunchUrl' event is sent to the client to tell it about a URL
// that should be launched (including a flag for whether it has been
// launched by the tool or needs launching by the editor).
'app.webLaunchUrl',
};

/// Completers for reverse requests from Flutter that may need to be handled by the client.
final Map<Object, Completer<Object?>> _reverseRequestCompleters = <Object, Completer<Object?>>{};

Expand Down Expand Up @@ -454,6 +462,17 @@ class FlutterDebugAdapter extends FlutterBaseDebugAdapter {
_handleAppStarted();
break;
}

if (_eventsToForwardToClient.contains(event)) {
// Forward the event to the client.
sendEvent(
RawEventBody(<String, Object?>{
'event': event,
'params': params,
}),
eventType: 'flutter.forwardedEvent',
);
}
}

/// Handles incoming reverse requests from `flutter run --machine`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ void main() {
await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete);
await terminateCompleter.future;

expect(adapter.flutterRequests, contains('app.stop'));
expect(adapter.dapToFlutterRequests, contains('app.stop'));
});

test('does not call "app.stop" on terminateRequest if app was not started', () async {
Expand All @@ -145,7 +145,7 @@ void main() {
await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete);
await terminateCompleter.future;

expect(adapter.flutterRequests, isNot(contains('app.stop')));
expect(adapter.dapToFlutterRequests, isNot(contains('app.stop')));
});
});

Expand Down Expand Up @@ -210,7 +210,39 @@ void main() {
await adapter.terminateRequest(MockRequest(), TerminateArguments(restart: false), terminateCompleter.complete);
await terminateCompleter.future;

expect(adapter.flutterRequests, contains('app.detach'));
expect(adapter.dapToFlutterRequests, contains('app.detach'));
});
});

group('forwards events', () {
test('app.webLaunchUrl', () async {
final MockFlutterDebugAdapter adapter = MockFlutterDebugAdapter(
fileSystem: MemoryFileSystem.test(style: fsStyle),
platform: platform,
);

// Simulate Flutter asking for a URL to be launched.
adapter.simulateStdoutMessage(<String, Object?>{
'event': 'app.webLaunchUrl',
'params': <String, Object?>{
'url': 'http://localhost:123/',
'launched': false,
}
});

// Allow the handler to be processed.
await pumpEventQueue(times: 5000);

// Find the forwarded event.
final Map<String, Object?> message = adapter.dapToClientMessages.singleWhere((Map<String, Object?> data) => data['event'] == 'flutter.forwardedEvent');
// Ensure the body of the event matches the original event sent by Flutter.
expect(message['body'], <String, Object?>{
'event': 'app.webLaunchUrl',
'params': <String, Object?>{
'url': 'http://localhost:123/',
'launched': false,
}
});
});
});

Expand Down Expand Up @@ -238,7 +270,7 @@ void main() {
// Allow the handler to be processed.
await pumpEventQueue(times: 5000);

final Map<String, Object?> message = adapter.flutterMessages.singleWhere((Map<String, Object?> data) => data['id'] == requestId);
final Map<String, Object?> message = adapter.dapToFlutterMessages.singleWhere((Map<String, Object?> data) => data['id'] == requestId);
expect(message['result'], 'http://mapped-host:123/');
});
});
Expand Down
16 changes: 11 additions & 5 deletions packages/flutter_tools/test/general.shard/dap/mocks.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,15 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {
late List<String> processArgs;
late Map<String, String>? env;

/// A list of all messages sent to the `flutter run` processes `stdin`.
final List<Map<String, Object?>> flutterMessages = <Map<String, Object?>>[];
/// A list of all messages sent from the adapter back to the client.
final List<Map<String, Object?>> dapToClientMessages = <Map<String, Object?>>[];

/// The `method`s of all requests send to the `flutter run` processes `stdin`.
List<String> get flutterRequests => flutterMessages
/// A list of all messages sent from the adapter to the `flutter run` processes `stdin`.
final List<Map<String, Object?>> dapToFlutterMessages = <Map<String, Object?>>[];

/// The `method`s of all mesages sent to the `flutter run` processes `stdin`
/// by the debug adapter.
List<String> get dapToFlutterRequests => dapToFlutterMessages
.map((Map<String, Object?> message) => message['method'] as String?)
.whereNotNull()
.toList();
Expand Down Expand Up @@ -92,6 +96,8 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {

/// Handles messages sent from the debug adapter back to the client.
void _handleDapToClientMessage(ProtocolMessage message) {
dapToClientMessages.add(message.toJson());

// Pretend to be the client, delegating any reverse-requests to the relevant
// handler that is provided by the test.
if (message is Event && message.event == 'flutter.forwardedRequest') {
Expand Down Expand Up @@ -133,7 +139,7 @@ class MockFlutterDebugAdapter extends FlutterDebugAdapter {

@override
void sendFlutterMessage(Map<String, Object?> message) {
flutterMessages.add(message);
dapToFlutterMessages.add(message);
// Don't call super because it will try to write to the process that we
// didn't actually spawn.
}
Expand Down

0 comments on commit a29796e

Please sign in to comment.