blob: b2b964cf6c5c0b443c1d3ed61ab0dcf8e69d6c2c [file] [log] [blame]
// Copyright 2019 The Chromium Authors. 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:convert';
import 'dart:io';
import 'dart:isolate';
import 'package:path/path.dart' as path;
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf.dart';
import 'package:shelf_proxy/shelf_proxy.dart';
import 'package:shelf_static/shelf_static.dart';
import 'package:sse/server/sse_handler.dart';
import 'client_manager.dart';
import 'server_api.dart';
// DO NOT IMPORT THIS FILE into any files other than `devtools_server.dart`.
// This file is overwritten for internal DevTools builds, so any file depending
// on `external_handlers.dart` would break internally.
/// Default [shelf.Handler] for serving DevTools files.
///
/// This serves files out from the build results of running a pub build of the
/// DevTools project.
Future<shelf.Handler> defaultHandler(
ClientManager clients, {
String customDevToolsPath,
bool debugMode = false,
}) async {
String buildDir = customDevToolsPath;
if (buildDir == null) {
final resourceUri = await Isolate.resolvePackageUri(
Uri(scheme: 'package', path: 'devtools/devtools.dart'));
final packageDir = path.dirname(path.dirname(resourceUri.toFilePath()));
buildDir = path.join(packageDir, 'build');
}
// Default static handler for all non-package requests.
Handler buildDirHandler;
if (!debugMode) {
buildDirHandler = createStaticHandler(
buildDir,
defaultDocument: 'index.html',
);
}
Handler debugProxyHandler;
if (debugMode) {
// Start up a flutter run -d web-server instance.
const webPort = 9101;
// ignore: unawaited_futures
Process.start(
'flutter',
[
'run',
'--dart-define=FLUTTER_WEB_USE_SKIA=true',
'-d',
'web-server',
'--web-port=$webPort',
],
workingDirectory: path.join('..', 'devtools_app'),
).then((Process process) {
// Write all flutter run process output to the server's output.
process
..stdout.transform(utf8.decoder).listen(stdout.write)
..stderr.transform(utf8.decoder).listen(stderr.write);
// Proxy all stdin to the flutter run process's input.
//stdin.pipe(process.stdin);
stdin
..lineMode = false
..listen((event) => process.stdin.add(event));
// Exit when the flutter run process exits.
process.exitCode.then(exit);
});
debugProxyHandler = proxyHandler(Uri.parse('http://localhost:$webPort/'));
}
final sseHandler = SseHandler(Uri.parse('/api/sse'))
..connections.rest.listen(clients.acceptClient);
// Make a handler that delegates based on path.
final handler = (shelf.Request request) {
if (request.url.path.startsWith('api/sse')) {
return sseHandler.handler(request);
}
if (request.url.path == 'api/ping') {
return shelf.Response(HttpStatus.ok, body: 'OK');
}
// The API handler takes all other calls to api/.
if (ServerApi.canHandle(request)) {
return ServerApi.handle(request);
}
if (debugMode) {
return debugProxyHandler(request);
} else {
return buildDirHandler(request);
}
};
return handler;
}