forked from dart-lang/webdev
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathshared.dart
126 lines (113 loc) · 3.94 KB
/
shared.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:io';
import 'package:http_multi_server/http_multi_server.dart';
import 'package:logging/logging.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:stack_trace/stack_trace.dart';
import 'package:vm_service/vm_service.dart';
import 'package:webkit_inspection_protocol/webkit_inspection_protocol.dart'
as wip;
import 'package:dwds/src/services/chrome_debug_exception.dart';
VMRef toVMRef(VM vm) => VMRef(name: vm.name);
int _nextId = 0;
String createId() {
_nextId++;
return '$_nextId';
}
final _logger = Logger('Utilities');
/// Returns `true` if [hostname] is bound to an IPv6 address.
Future<bool> useIPv6ForHost(String hostname) async {
final addresses = await InternetAddress.lookup(hostname);
if (addresses.isEmpty) return false;
final address = addresses.firstWhere(
(a) => a.type == InternetAddressType.IPv6,
orElse: () => addresses.first,
);
return address.type == InternetAddressType.IPv6;
}
/// Returns a port that is probably, but not definitely, not in use.
///
/// This has a built-in race condition: another process may bind this port at
/// any time after this call has returned.
Future<int> findUnusedPort() async {
int port;
ServerSocket socket;
try {
socket =
await ServerSocket.bind(InternetAddress.loopbackIPv6, 0, v6Only: true);
} on SocketException {
socket = await ServerSocket.bind(InternetAddress.loopbackIPv4, 0);
}
port = socket.port;
await socket.close();
return port;
}
/// Finds unused port and binds a new http server to it.
///
/// Retries a few times to recover from errors due to
/// another thread or process opening the same port.
/// Starts by trying to bind to [port] if specified.
Future<HttpServer> startHttpServer(String hostname, {int? port}) async {
HttpServer? httpServer;
final retries = 5;
var i = 0;
var foundPort = port ?? await findUnusedPort();
while (i < retries) {
i++;
try {
httpServer = await HttpMultiServer.bind(hostname, foundPort);
} on SocketException {
if (i == retries) rethrow;
}
if (httpServer != null || i == retries) return httpServer!;
foundPort = await findUnusedPort();
await Future<void>.delayed(const Duration(milliseconds: 100));
}
return httpServer!;
}
/// Handles [requests] using [handler].
///
/// Captures all sync and async stack error traces and passes
/// them to the [onError] handler.
void serveHttpRequests(Stream<HttpRequest> requests, Handler handler,
void Function(Object, StackTrace) onError) {
return Chain.capture(() {
serveRequests(requests, handler);
}, onError: onError);
}
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the
/// result.
void handleErrorIfPresent(wip.WipResponse? response, {String? evalContents}) {
final result = response?.result;
if (result == null) return;
if (result.containsKey('exceptionDetails')) {
throw ChromeDebugException(
result['exceptionDetails'] as Map<String, dynamic>,
evalContents: evalContents,
);
}
}
/// Returns result contained in the response.
/// Throws an [wip.ExceptionDetails] object if `exceptionDetails` is present on the
/// result or the result is null.
Map<String, dynamic> getResultOrHandleError(wip.WipResponse? response,
{String? evalContents}) {
handleErrorIfPresent(response, evalContents: evalContents);
final result = response?.result?['result'];
if (result == null) {
throw ChromeDebugException(
{'text': 'null result from Chrome Devtools'},
evalContents: evalContents,
);
}
return result;
}
void safeUnawaited(Future<void> future) {
unawaited(future.catchError((error, stackTrace) {
_logger.warning('Error in unawaited Future:', error, stackTrace);
}));
}