Skip to content

Commit

Permalink
retry VMService connection; expect missing PRODUCT_BUNDLE_IDENTIFIER (f…
Browse files Browse the repository at this point in the history
  • Loading branch information
yjbanov authored and tvolkert committed Apr 20, 2018
1 parent e7cd5d3 commit 85473d0
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 10 deletions.
1 change: 1 addition & 0 deletions packages/flutter_tools/lib/src/base/io.dart
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ export 'dart:io'
SocketException,
SYSTEM_ENCODING,
WebSocket,
WebSocketException,
WebSocketTransformer;

/// Exits the process with the given [exitCode].
Expand Down
2 changes: 1 addition & 1 deletion packages/flutter_tools/lib/src/ios/mac.dart
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ Future<Null> diagnoseXcodeBuildFailure(XcodeBuildResult result) async {
}
if (result.xcodeBuildExecution != null &&
result.xcodeBuildExecution.buildForPhysicalDevice &&
result.xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER'].contains('com.example')) {
result.xcodeBuildExecution.buildSettings['PRODUCT_BUNDLE_IDENTIFIER']?.contains('com.example') == true) {
printError('');
printError('It appears that your application still contains the default signing identifier.');
printError("Try replacing 'com.example' with your signing id in Xcode:");
Expand Down
39 changes: 32 additions & 7 deletions packages/flutter_tools/lib/src/vmservice.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import 'package:web_socket_channel/web_socket_channel.dart';

import 'base/common.dart';
import 'base/file_system.dart';
import 'base/io.dart' as io;
import 'globals.dart';
import 'vmservice_record_replay.dart';

/// A function that opens a two-way communication channel to the specified [uri].
typedef StreamChannel<String> _OpenChannel(Uri uri);
typedef Future<StreamChannel<String>> _OpenChannel(Uri uri);

_OpenChannel _openChannel = _defaultOpenChannel;

Expand All @@ -43,8 +44,32 @@ typedef Future<Null> ReloadSources(

const String _kRecordingType = 'vmservice';

StreamChannel<String> _defaultOpenChannel(Uri uri) =>
new IOWebSocketChannel.connect(uri.toString()).cast();
Future<StreamChannel<String>> _defaultOpenChannel(Uri uri) async {
const int _kMaxAttempts = 5;
Duration delay = const Duration(milliseconds: 100);
int attempts = 0;
io.WebSocket socket;
while (attempts < _kMaxAttempts && socket == null) {
attempts += 1;
try {
socket = await io.WebSocket.connect(uri.toString());
} on io.WebSocketException catch(e) {
printTrace('Exception attempting to connect to observatory: $e');
printTrace('This was attempt #$attempts. Will retry in $delay.');
await new Future<Null>.delayed(delay);
delay *= 2;
}
}

if (socket == null) {
throw new ToolExit(
'Attempted to connect to Dart observatory $_kMaxAttempts times, and '
'all attempts failed. Giving up. The URL was $uri'
);
}

return new IOWebSocketChannel(socket).cast<String>();
}

/// The default VM service request timeout.
const Duration kDefaultRequestTimeout = const Duration(seconds: 30);
Expand Down Expand Up @@ -113,8 +138,8 @@ class VMService {
/// `"vmservice"` subdirectory.
static void enableRecordingConnection(String location) {
final Directory dir = getRecordingSink(location, _kRecordingType);
_openChannel = (Uri uri) {
final StreamChannel<String> delegate = _defaultOpenChannel(uri);
_openChannel = (Uri uri) async {
final StreamChannel<String> delegate = await _defaultOpenChannel(uri);
return new RecordingVMServiceChannel(delegate, dir);
};
}
Expand All @@ -126,7 +151,7 @@ class VMService {
/// passed to [enableRecordingConnection]), or a [ToolExit] will be thrown.
static void enableReplayConnection(String location) {
final Directory dir = getReplaySource(location, _kRecordingType);
_openChannel = (Uri uri) => new ReplayVMServiceChannel(dir);
_openChannel = (Uri uri) async => new ReplayVMServiceChannel(dir);
}

/// Connect to a Dart VM Service at [httpUri].
Expand All @@ -146,7 +171,7 @@ class VMService {
ReloadSources reloadSources,
}) async {
final Uri wsUri = httpUri.replace(scheme: 'ws', path: fs.path.join(httpUri.path, 'ws'));
final StreamChannel<String> channel = _openChannel(wsUri);
final StreamChannel<String> channel = await _openChannel(wsUri);
final rpc.Peer peer = new rpc.Peer.withoutJson(jsonDocument.bind(channel));
final VMService service = new VMService._(peer, httpUri, wsUri, requestTimeout, reloadSources);
// This call is to ensure we are able to establish a connection instead of
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter_tools/test/vmservice_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:web_socket_channel/web_socket_channel.dart';
import 'package:test/test.dart';

import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/port_scanner.dart';
import 'package:flutter_tools/src/vmservice.dart';

Expand All @@ -14,7 +14,7 @@ void main() {
final int port = await const HostPortScanner().findAvailablePort();
expect(
VMService.connect(Uri.parse('http://localhost:$port')),
throwsA(const isInstanceOf<WebSocketChannelException>()),
throwsA(const isInstanceOf<SocketException>()),
);
});
});
Expand Down

0 comments on commit 85473d0

Please sign in to comment.