From 0c3936d6022ab35450962e92ae5f630f29dee481 Mon Sep 17 00:00:00 2001 From: Tobe O Date: Thu, 7 Jun 2018 12:11:03 -0400 Subject: [PATCH] Fixed compatibility issues with 1.1.3 --- .idea/hot.iml | 1 + .idea/runConfigurations/main_dart.xml | 8 + .../main_dart__No_VM_service_.xml | 7 + .idea/runConfigurations/server_dart.xml | 8 - .../server_dart__No_VM_service_.xml | 7 - CHANGELOG.md | 4 + .analysis-options => analysis_options.yaml | 0 example/basic/{server.dart => main.dart} | 33 ++-- lib/angel_hot.dart | 143 ++++++++++-------- pubspec.yaml | 12 +- 10 files changed, 128 insertions(+), 95 deletions(-) create mode 100644 .idea/runConfigurations/main_dart.xml create mode 100644 .idea/runConfigurations/main_dart__No_VM_service_.xml delete mode 100644 .idea/runConfigurations/server_dart.xml delete mode 100644 .idea/runConfigurations/server_dart__No_VM_service_.xml create mode 100644 CHANGELOG.md rename .analysis-options => analysis_options.yaml (100%) rename example/basic/{server.dart => main.dart} (58%) diff --git a/.idea/hot.iml b/.idea/hot.iml index eae13016..954fa6c5 100644 --- a/.idea/hot.iml +++ b/.idea/hot.iml @@ -2,6 +2,7 @@ + diff --git a/.idea/runConfigurations/main_dart.xml b/.idea/runConfigurations/main_dart.xml new file mode 100644 index 00000000..0d20fe85 --- /dev/null +++ b/.idea/runConfigurations/main_dart.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/main_dart__No_VM_service_.xml b/.idea/runConfigurations/main_dart__No_VM_service_.xml new file mode 100644 index 00000000..08397143 --- /dev/null +++ b/.idea/runConfigurations/main_dart__No_VM_service_.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/.idea/runConfigurations/server_dart.xml b/.idea/runConfigurations/server_dart.xml deleted file mode 100644 index fb2c1fc1..00000000 --- a/.idea/runConfigurations/server_dart.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/runConfigurations/server_dart__No_VM_service_.xml b/.idea/runConfigurations/server_dart__No_VM_service_.xml deleted file mode 100644 index a1392790..00000000 --- a/.idea/runConfigurations/server_dart__No_VM_service_.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..7913b0e8 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +# 1.1.1 +* Disable the observatory from pausing the isolate +on exceptions, because Angel already handles +all exceptions by itself. \ No newline at end of file diff --git a/.analysis-options b/analysis_options.yaml similarity index 100% rename from .analysis-options rename to analysis_options.yaml diff --git a/example/basic/server.dart b/example/basic/main.dart similarity index 58% rename from example/basic/server.dart rename to example/basic/main.dart index cd4c8194..3815188c 100644 --- a/example/basic/server.dart +++ b/example/basic/main.dart @@ -1,8 +1,9 @@ import 'dart:async'; -import 'dart:convert'; -import 'dart:io'; +import 'dart:io' show Directory; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_hot/angel_hot.dart'; +import 'package:dart2_constant/convert.dart'; +import 'package:dart2_constant/io.dart'; import 'package:logging/logging.dart'; import 'src/foo.dart'; @@ -10,19 +11,19 @@ main() async { var hot = new HotReloader(createServer, [ new Directory('src'), new Directory('src'), - 'server.dart', + 'main.dart', Uri.parse('package:angel_hot/angel_hot.dart') ]); - var server = await hot.startServer(InternetAddress.LOOPBACK_IP_V4, 3000); - print( - 'Hot server listening at http://${server.address.address}:${server.port}'); + var server = await hot.startServer('127.0.0.1', 3000); + print('Hot server listening at http://${server.address.address}:${server + .port}'); } Future createServer() async { var app = new Angel(); app.lazyParseBodies = true; - app.injectSerializer(JSON.encode); + app.serializer = json.encode; // Edit this line, and then refresh the page in your browser! app.get('/', {'hello': 'hot world!'}); @@ -31,18 +32,18 @@ Future createServer() async { app.use(() => throw new AngelHttpException.notFound()); app.injectEncoders({ - 'gzip': GZIP.encoder, - 'deflate': ZLIB.encoder, + 'gzip': gzip.encoder, + 'deflate': zlib.encoder, }); app.logger = new Logger('angel') - ..onRecord.listen((rec) { - print(rec); - if (rec.error != null) { - print(rec.error); - print(rec.stackTrace); - } - }); + ..onRecord.listen((rec) { + print(rec); + if (rec.error != null) { + print(rec.error); + print(rec.stackTrace); + } + }); return app; } diff --git a/lib/angel_hot.dart b/lib/angel_hot.dart index 7e16f815..8cae376a 100644 --- a/lib/angel_hot.dart +++ b/lib/angel_hot.dart @@ -1,10 +1,25 @@ import 'dart:async'; import 'dart:collection'; -import 'dart:convert'; -import 'dart:io'; +import 'dart:io' + show + ContentType, + Directory, + File, + FileStat, + FileSystemEntity, + FileSystemException, + HttpHeaders, + HttpRequest, + HttpServer, + Link, + Platform, + exit, + stderr; import 'dart:isolate'; import 'package:angel_framework/angel_framework.dart'; import 'package:angel_websocket/server.dart'; +import 'package:dart2_constant/convert.dart'; +import 'package:dart2_constant/io.dart'; import 'package:glob/glob.dart'; import 'package:html_builder/elements.dart'; import 'package:html_builder/html_builder.dart'; @@ -15,13 +30,15 @@ import 'package:watcher/watcher.dart'; /// A utility class that watches the filesystem for changes, and starts new instances of an Angel server. class HotReloader { vm.VmService _client; + vm.IsolateRef _mainIsolate; final StreamController _onChange = new StreamController.broadcast(); final List _paths = []; final StringRenderer _renderer = new StringRenderer(pretty: false); final Queue _requestQueue = new Queue(); - Angel _server; + AngelHttp _server; Duration _timeout; + vm.VM _vmachine; /// Invoked to load a new instance of [Angel] on file changes. final FutureOr Function() generator; @@ -62,9 +79,44 @@ class HotReloader { _onChange.close(); } + void sendError(HttpRequest request, int status, String title_, e) { + var doc = html(lang: 'en', c: [ + head(c: [ + meta(name: 'viewport', content: 'width=device-width, initial-scale=1'), + title(c: [text(title_)]) + ]), + body(c: [ + h1(c: [text(title_)]), + i(c: [text(e.toString())]) + ]) + ]); + + var response = request.response; + response.statusCode = HttpStatus.badGateway; + response.headers + ..contentType = ContentType.HTML + ..set(HttpHeaders.SERVER, 'angel_hot'); + + if (request.headers + .value(HttpHeaders.ACCEPT_ENCODING) + ?.toLowerCase() + ?.contains('gzip') == + true) { + response + ..headers.set(HttpHeaders.CONTENT_ENCODING, 'gzip') + ..add(gzip.encode(utf8.encode(_renderer.render(doc)))); + } else + response.write(_renderer.render(doc)); + response.close(); + } + + Future _handle(HttpRequest request) { + return _server.handleRequest(request); + } + Future handleRequest(HttpRequest request) async { if (_server != null) - return await _server.handleRequest(request); + return await _handle(request); else if (timeout == null) _requestQueue.add(request); else { @@ -72,48 +124,18 @@ class HotReloader { new Timer(timeout, () { if (_requestQueue.remove(request)) { // Send 502 response - var doc = html(lang: 'en', c: [ - head(c: [ - meta( - name: 'viewport', - content: 'width=device-width, initial-scale=1'), - title(c: [text('502 Bad Gateway')]) - ]), - body(c: [ - h1(c: [text('502 Bad Gateway')]), - i(c: [ - text('Request timed out after ${timeout.inMilliseconds}ms.') - ]) - ]) - ]); - - var response = request.response; - response.statusCode = HttpStatus.BAD_GATEWAY; - response.headers - ..contentType = ContentType.HTML - ..set(HttpHeaders.SERVER, 'angel_hot'); - - if (request.headers - .value(HttpHeaders.ACCEPT_ENCODING) - ?.toLowerCase() - ?.contains('gzip') == - true) { - response - ..headers.set(HttpHeaders.CONTENT_ENCODING, 'gzip') - ..add(GZIP.encode(UTF8.encode(_renderer.render(doc)))); - } else - response.write(_renderer.render(doc)); - response.close(); + sendError(request, HttpStatus.badGateway, '502 Bad Gateway', + 'Request timed out after ${timeout.inMilliseconds}ms.'); } }); } } - Future _generateServer() async { - var s = await generator() as Angel; + Future _generateServer() async { + var s = await generator(); await Future.forEach(s.startupHooks, s.configure); s.optimizeForProduction(); - return s; + return new AngelHttp(s); } /// Starts listening to requests and filesystem events. @@ -122,17 +144,21 @@ class HotReloader { print( 'WARNING: You have instantiated a HotReloader without providing any filesystem paths to watch.'); - var s = _server = await _generateServer(); - while (!_requestQueue.isEmpty) - await s.handleRequest(_requestQueue.removeFirst()); + _client = await vm.vmServiceConnect( + vmServiceHost ?? 'localhost', vmServicePort ?? 8181); + _vmachine ??= await _client.getVM(); + _mainIsolate ??= _vmachine.isolates.first; + await _client.setExceptionPauseMode(_mainIsolate.id, 'None'); + + _server = await _generateServer(); + while (!_requestQueue.isEmpty) await _handle(_requestQueue.removeFirst()); _onChange.stream .transform(new _Debounce(new Duration(seconds: 1))) .listen(_handleWatchEvent); await _listenToFilesystem(); - var server = await HttpServer.bind( - address ?? InternetAddress.LOOPBACK_IP_V4, port ?? 0); + var server = await HttpServer.bind(address ?? '127.0.0.1', port ?? 0); server.listen(handleRequest); return server; } @@ -174,14 +200,14 @@ class HotReloader { _listen() async { try { var stat = await FileStat.stat(path); - if (stat.type == FileSystemEntityType.LINK) { + if (stat.type == FileSystemEntityType.link) { var lnk = new Link(path); var p = await lnk.resolveSymbolicLinks(); return await _listenToStat(p); - } else if (stat.type == FileSystemEntityType.FILE) { + } else if (stat.type == FileSystemEntityType.file) { var file = new File(path); if (!await file.exists()) return null; - } else if (stat.type == FileSystemEntityType.DIRECTORY) { + } else if (stat.type == FileSystemEntityType.directory) { var dir = new Directory(path); if (!await dir.exists()) return null; } else @@ -204,7 +230,8 @@ class HotReloader { if (r == null) { print( - 'WARNING: Unable to watch path "$path" from working directory "${Directory.current.path}". Please ensure that it exists.'); + 'WARNING: Unable to watch path "$path" from working directory "${Directory + .current.path}". Please ensure that it exists.'); } } @@ -216,27 +243,24 @@ class HotReloader { // Do this asynchronously, because we really don't care about the old server anymore. new Future(() async { // Disconnect active WebSockets - var ws = old.container.make(AngelWebSocket) as AngelWebSocket; + var ws = old.app.container.make(AngelWebSocket) as AngelWebSocket; for (var client in ws.clients) { try { - await client.close(WebSocketStatus.GOING_AWAY); + await client.close(WebSocketStatus.goingAway); } catch (e) { stderr.writeln( - 'Couldn\'t close WebSocket from session #${client.request.session.id}: $e'); + 'Couldn\'t close WebSocket from session #${client.request + .session.id}: $e'); } } - Future.forEach(old.shutdownHooks, old.configure); + Future.forEach(old.app.shutdownHooks, old.app.configure); }); } _server = null; - _client ??= await vm.vmServiceConnect( - vmServiceHost ?? 'localhost', vmServicePort ?? 8181); - var vmachine = await _client.getVM(); - var mainIsolate = vmachine.isolates.first; - var report = await _client.reloadSources(mainIsolate.id); + var report = await _client.reloadSources(_mainIsolate.id); if (!report.success) { stderr.writeln('Hot reload failed!!!'); @@ -246,12 +270,11 @@ class HotReloader { var s = await _generateServer(); _server = s; - while (!_requestQueue.isEmpty) - await s.handleRequest(_requestQueue.removeFirst()); + while (!_requestQueue.isEmpty) await _handle(_requestQueue.removeFirst()); } } -class _Debounce implements StreamTransformer { +class _Debounce extends StreamTransformerBase { final Duration _delay; const _Debounce(this._delay); diff --git a/pubspec.yaml b/pubspec.yaml index b0f302c0..a370a2e4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,16 +1,20 @@ name: angel_hot description: Supports hot reloading of Angel servers on file changes. -version: 1.1.0 +version: 1.1.1 author: Tobe O homepage: https://github.com/angel-dart/hot environment: - sdk: ">=1.19.0" + sdk: ">=1.19.0 <3.0.0" dependencies: - angel_framework: ^1.1.0-alpha + angel_framework: ^1.1.0 angel_websocket: ^1.1.0-alpha + dart2_constant: ^1.0.0 + glob: ^1.0.0 html_builder: ^1.0.0 - vm_service_lib: 0.3.5 + vm_service_lib: ^0.3.5 + watcher: ^0.9.0 dev_dependencies: angel_test: ^1.0.0 http: ^0.11.3 + logging: ^0.11.0 test: ^0.12.15 \ No newline at end of file