diff --git a/pkgs/web_socket_channel/.github/workflows/test-package.yml b/pkgs/web_socket_channel/.github/workflows/test-package.yml index d8fd949871..bf51a79bea 100644 --- a/pkgs/web_socket_channel/.github/workflows/test-package.yml +++ b/pkgs/web_socket_channel/.github/workflows/test-package.yml @@ -42,7 +42,7 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - sdk: [2.15.0, dev] + sdk: [3.2.0, dev] steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 - uses: dart-lang/setup-dart@b64355ae6ca0b5d484f0106a033dd1388965d06d diff --git a/pkgs/web_socket_channel/CHANGELOG.md b/pkgs/web_socket_channel/CHANGELOG.md index de523a5504..02e4630a22 100644 --- a/pkgs/web_socket_channel/CHANGELOG.md +++ b/pkgs/web_socket_channel/CHANGELOG.md @@ -1,5 +1,6 @@ ## 2.4.1-wip +- Bump minimum Dart version to 3.2.0 - Update the examples to use `WebSocketChannel.ready` and clarify that `WebSocketChannel.ready` should be awaited before sending data over the `WebSocketChannel`. diff --git a/pkgs/web_socket_channel/analysis_options.yaml b/pkgs/web_socket_channel/analysis_options.yaml index 30371c651b..b7d68c94b5 100644 --- a/pkgs/web_socket_channel/analysis_options.yaml +++ b/pkgs/web_socket_channel/analysis_options.yaml @@ -1,4 +1,4 @@ -include: package:pedantic/analysis_options.yaml +include: package:dart_flutter_team_lints/analysis_options.yaml analyzer: language: @@ -7,70 +7,24 @@ analyzer: linter: rules: - avoid_bool_literals_in_conditional_expressions - - avoid_catching_errors - avoid_classes_with_only_static_members - - avoid_function_literals_in_foreach_calls - avoid_private_typedef_functions - avoid_redundant_argument_values - - avoid_renaming_method_parameters - avoid_returning_null - avoid_returning_null_for_future - - avoid_returning_null_for_void - avoid_returning_this - - avoid_single_cascade_in_expression_statements - avoid_unused_constructor_parameters - avoid_void_async - - await_only_futures - - camel_case_types - cancel_subscriptions - - comment_references - - constant_identifier_names - - control_flow_in_finally - - directives_ordering - - empty_statements - - file_names - - hash_and_equals - - implementation_imports - - iterable_contains_unrelated_type - join_return_with_assignment - - lines_longer_than_80_chars - - list_remove_unrelated_type - literal_only_boolean_expressions - missing_whitespace_between_adjacent_strings - no_adjacent_strings_in_list - no_runtimeType_toString - - non_constant_identifier_names - - only_throw_errors - - overridden_fields - package_api_docs - - package_names - - package_prefixed_library_names - - prefer_asserts_in_initializer_lists - - prefer_const_constructors - prefer_const_declarations - prefer_expression_function_bodies - prefer_final_locals - - prefer_function_declarations_over_variables - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_interpolation_to_compose_strings - - prefer_is_not_operator - - prefer_null_aware_operators - - prefer_relative_imports - - prefer_typing_uninitialized_variables - prefer_void_to_null - - provide_deprecation_message - - sort_pub_dependencies - - test_types_in_equals - - throw_in_finally - unnecessary_await_in_return - - unnecessary_brace_in_string_interps - - unnecessary_getters_setters - - unnecessary_lambdas - - unnecessary_null_aware_assignments - - unnecessary_overrides - - unnecessary_parenthesis - - unnecessary_statements - - unnecessary_string_interpolations - use_string_buffers - - void_checks diff --git a/pkgs/web_socket_channel/lib/html.dart b/pkgs/web_socket_channel/lib/html.dart index 25b4175b22..0cb7ffdded 100644 --- a/pkgs/web_socket_channel/lib/html.dart +++ b/pkgs/web_socket_channel/lib/html.dart @@ -55,7 +55,7 @@ class HtmlWebSocketChannel extends StreamChannelMixin Stream get stream => _controller.foreign.stream; final _controller = - StreamChannelController(sync: true, allowForeignErrors: false); + StreamChannelController(sync: true, allowForeignErrors: false); @override late final WebSocketSink sink = _HtmlWebSocketSink(this); @@ -71,7 +71,7 @@ class HtmlWebSocketChannel extends StreamChannelMixin /// received by this socket. It defaults to [BinaryType.list], which causes /// binary messages to be delivered as [Uint8List]s. If it's /// [BinaryType.blob], they're delivered as [Blob]s instead. - HtmlWebSocketChannel.connect(url, + HtmlWebSocketChannel.connect(Object url, {Iterable? protocols, BinaryType? binaryType}) : this(WebSocket(url.toString(), protocols) ..binaryType = (binaryType ?? BinaryType.list).value); @@ -102,7 +102,9 @@ class HtmlWebSocketChannel extends StreamChannelMixin // Unfortunately, the underlying WebSocket API doesn't expose any // specific information about the error itself. final error = WebSocketChannelException('WebSocket connection failed.'); - _readyCompleter.completeError(error); + if (!_readyCompleter.isCompleted) { + _readyCompleter.completeError(error); + } _controller.local.sink.addError(error); _controller.local.sink.close(); }); diff --git a/pkgs/web_socket_channel/lib/io.dart b/pkgs/web_socket_channel/lib/io.dart index e39bc6738b..9f71d812f9 100644 --- a/pkgs/web_socket_channel/lib/io.dart +++ b/pkgs/web_socket_channel/lib/io.dart @@ -105,7 +105,7 @@ class IOWebSocketChannel extends StreamChannelMixin IOWebSocketChannel(WebSocket socket) : _webSocket = socket, stream = socket.handleError( - (error) => throw WebSocketChannelException.from(error)), + (Object? error) => throw WebSocketChannelException.from(error)), sink = _IOWebSocketSink(socket), _readyCompleter = Completer()..complete(); @@ -116,7 +116,7 @@ class IOWebSocketChannel extends StreamChannelMixin IOWebSocketChannel._withoutSocket(Stream stream, this.sink) : _webSocket = null, stream = stream.handleError( - (error) => throw WebSocketChannelException.from(error)), + (Object? error) => throw WebSocketChannelException.from(error)), _readyCompleter = Completer(); } @@ -125,9 +125,7 @@ class _IOWebSocketSink extends DelegatingStreamSink implements WebSocketSink { /// The underlying socket. final WebSocket _webSocket; - _IOWebSocketSink(WebSocket webSocket) - : _webSocket = webSocket, - super(webSocket); + _IOWebSocketSink(WebSocket super.webSocket) : _webSocket = webSocket; @override Future close([int? closeCode, String? closeReason]) => diff --git a/pkgs/web_socket_channel/lib/src/channel.dart b/pkgs/web_socket_channel/lib/src/channel.dart index 46d16b834e..4143128562 100644 --- a/pkgs/web_socket_channel/lib/src/channel.dart +++ b/pkgs/web_socket_channel/lib/src/channel.dart @@ -11,7 +11,7 @@ import 'package:stream_channel/stream_channel.dart'; import '_connect_api.dart' if (dart.library.io) '_connect_io.dart' - if (dart.library.html) '_connect_html.dart' as platform; + if (dart.library.js_interop) '_connect_html.dart' as platform; import 'copy/web_socket_impl.dart'; import 'exception.dart'; @@ -151,9 +151,7 @@ class WebSocketChannel extends StreamChannelMixin { class WebSocketSink extends DelegatingStreamSink { final WebSocketImpl _webSocket; - WebSocketSink._(WebSocketImpl webSocket) - : _webSocket = webSocket, - super(webSocket); + WebSocketSink._(WebSocketImpl super.webSocket) : _webSocket = webSocket; /// Closes the web socket connection. /// diff --git a/pkgs/web_socket_channel/lib/src/copy/io_sink.dart b/pkgs/web_socket_channel/lib/src/copy/io_sink.dart index 2abf9998df..6dfe7a06e8 100644 --- a/pkgs/web_socket_channel/lib/src/copy/io_sink.dart +++ b/pkgs/web_socket_channel/lib/src/copy/io_sink.dart @@ -36,7 +36,7 @@ class StreamSinkImpl implements StreamSink { } @override - void addError(error, [StackTrace? stackTrace]) { + void addError(Object error, [StackTrace? stackTrace]) { if (_isClosed) { return; } @@ -101,7 +101,7 @@ class StreamSinkImpl implements StreamSink { @override Future get done => _doneCompleter.future; - void _completeDoneValue(value) { + void _completeDoneValue(Object? value) { if (!_doneCompleter.isCompleted) { _doneCompleter.complete(value); } diff --git a/pkgs/web_socket_channel/lib/src/copy/web_socket_impl.dart b/pkgs/web_socket_channel/lib/src/copy/web_socket_impl.dart index 7c35134f6e..0616caa5df 100644 --- a/pkgs/web_socket_channel/lib/src/copy/web_socket_impl.dart +++ b/pkgs/web_socket_channel/lib/src/copy/web_socket_impl.dart @@ -408,7 +408,7 @@ class _WebSocketOutgoingTransformer }); @override - void add(message) { + void add(Object? message) { if (message is _WebSocketPong) { addFrame(_WebSocketOpcode.PONG, message.payload); return; @@ -619,7 +619,7 @@ class _WebSocketConsumer implements StreamConsumer { sink.addStream(stream).then((_) { _done(); _closeCompleter.complete(webSocket); - }, onError: (error, StackTrace stackTrace) { + }, onError: (Object error, StackTrace stackTrace) { _closed = true; _cancel(); if (error is ArgumentError) { @@ -645,7 +645,7 @@ class _WebSocketConsumer implements StreamConsumer { } @override - Future addStream(var stream) { + Future addStream(Stream stream) { if (_closed) { stream.listen(null).cancel(); return Future.value(webSocket); @@ -672,7 +672,7 @@ class _WebSocketConsumer implements StreamConsumer { return _closeCompleter.future.then((_) => closeSocket()); } - void add(data) { + void add(Object? data) { if (_closed) return; _ensureController(); _controller!.add(data); @@ -729,7 +729,7 @@ class WebSocketImpl extends Stream with _ServiceObject implements StreamSink { } else { _controller.add(data); } - }, onError: (error, stackTrace) { + }, onError: (Object error) { if (_closeTimer != null) _closeTimer!.cancel(); if (error is FormatException) { _close(WebSocketStatus.INVALID_FRAME_PAYLOAD_DATA); @@ -804,7 +804,7 @@ class WebSocketImpl extends Stream with _ServiceObject implements StreamSink { String? get closeReason => _closeReason; @override - void add(data) { + void add(Object? data) { _sink.add(data); } @@ -835,7 +835,7 @@ class WebSocketImpl extends Stream with _ServiceObject implements StreamSink { // 2) set a timer terminate the connection if a close frame is // not received. if (!_controller.hasListener && _subscription != null) { - _controller.stream.drain().catchError((_) => {}); + _controller.stream.drain().catchError((_) => {}); } // When closing the web-socket, we no longer accept data. _closeTimer ??= Timer(const Duration(seconds: 5), () { @@ -881,7 +881,7 @@ class WebSocketImpl extends Stream with _ServiceObject implements StreamSink { int _nextServiceId = 1; // TODO(ajohnsen): Use other way of getting a uniq id. -abstract class _ServiceObject { +mixin class _ServiceObject { int __serviceId = 0; int get _serviceId { diff --git a/pkgs/web_socket_channel/lib/src/sink_completer.dart b/pkgs/web_socket_channel/lib/src/sink_completer.dart index 9012d681bc..cea8c178a7 100644 --- a/pkgs/web_socket_channel/lib/src/sink_completer.dart +++ b/pkgs/web_socket_channel/lib/src/sink_completer.dart @@ -83,7 +83,7 @@ class _CompleterSink implements WebSocketSink { } @override - void add(event) { + void add(Object? event) { if (_canSendDirectly) { _destinationSink!.add(event); } else { diff --git a/pkgs/web_socket_channel/pubspec.yaml b/pkgs/web_socket_channel/pubspec.yaml index 1403492a50..c772f4d07f 100644 --- a/pkgs/web_socket_channel/pubspec.yaml +++ b/pkgs/web_socket_channel/pubspec.yaml @@ -8,7 +8,7 @@ description: >- repository: https://github.com/dart-lang/web_socket_channel environment: - sdk: ">=2.15.0 <3.0.0" + sdk: ^3.2.0 dependencies: async: ^2.5.0 @@ -16,5 +16,5 @@ dependencies: stream_channel: ^2.1.0 dev_dependencies: - pedantic: ^1.10.0 + dart_flutter_team_lints: ^2.0.0 test: ^1.16.0 diff --git a/pkgs/web_socket_channel/test/html_test.dart b/pkgs/web_socket_channel/test/html_test.dart index 54b34d7b5a..d444d7c702 100644 --- a/pkgs/web_socket_channel/test/html_test.dart +++ b/pkgs/web_socket_channel/test/html_test.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('browser') +library; + import 'dart:async'; import 'dart:html'; import 'dart:typed_data'; @@ -87,7 +89,14 @@ void main() { webSocket.close(); final channel = HtmlWebSocketChannel(webSocket); - expect(channel.ready, throwsA(isA())); + await expectLater( + channel.ready, + throwsA( + isA() + .having((p0) => p0.message, 'message', 'WebSocket state error: 2') + .having((p0) => p0.inner, 'inner', isNull), + ), + ); }); test('.connect defaults to binary lists', () async { diff --git a/pkgs/web_socket_channel/test/io_test.dart b/pkgs/web_socket_channel/test/io_test.dart index fde1a9f973..b2b7cbf38a 100644 --- a/pkgs/web_socket_channel/test/io_test.dart +++ b/pkgs/web_socket_channel/test/io_test.dart @@ -3,6 +3,8 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') +library; + import 'dart:async'; import 'dart:io'; @@ -106,7 +108,7 @@ void main() { server.transform(WebSocketTransformer()).listen((WebSocket webSocket) { expect(() async { final channel = IOWebSocketChannel(webSocket); - await channel.stream.drain(); + await channel.stream.drain(); expect(channel.closeCode, equals(5678)); expect(channel.closeReason, equals('raisin')); }(), completes); @@ -130,7 +132,8 @@ void main() { final channel = IOWebSocketChannel.connect('ws://localhost:${server.port}'); expect(channel.ready, throwsA(isA())); - expect(channel.stream.drain(), throwsA(isA())); + expect(channel.stream.drain(), + throwsA(isA())); }); test('.protocols fail', () async { @@ -153,7 +156,7 @@ void main() { ); expect(channel.ready, throwsA(isA())); expect( - channel.stream.drain(), + channel.stream.drain(), throwsA(isA()), ); }); @@ -178,7 +181,7 @@ void main() { expect(channel.ready, completes); - await channel.stream.drain(); + await channel.stream.drain(); expect(channel.protocol, passedProtocol); }); @@ -188,7 +191,7 @@ void main() { server.transform(WebSocketTransformer()).listen((webSocket) { expect(() async { final channel = IOWebSocketChannel(webSocket); - await channel.stream.drain(); + await channel.stream.drain(); expect(channel.closeCode, equals(5678)); expect(channel.closeReason, equals('raisin')); }(), completes); @@ -218,7 +221,7 @@ void main() { .transform(WebSocketTransformer()) .listen((webSocket) { final channel = IOWebSocketChannel(webSocket); - channel.stream.drain(); + channel.stream.drain(); }); final channel = IOWebSocketChannel.connect( @@ -227,7 +230,8 @@ void main() { ); expect(channel.ready, throwsA(isA())); - expect(channel.stream.drain(), throwsA(isA())); + expect(channel.stream.drain(), + throwsA(isA())); }); test('.custom client is passed through', () async { diff --git a/pkgs/web_socket_channel/test/web_socket_test.dart b/pkgs/web_socket_channel/test/web_socket_test.dart index 441c628cde..7aaabc7761 100644 --- a/pkgs/web_socket_channel/test/web_socket_test.dart +++ b/pkgs/web_socket_channel/test/web_socket_test.dart @@ -3,12 +3,12 @@ // BSD-style license that can be found in the LICENSE file. @TestOn('vm') +library; import 'dart:io'; import 'package:stream_channel/stream_channel.dart'; import 'package:test/test.dart'; - import 'package:web_socket_channel/web_socket_channel.dart'; void main() { @@ -51,7 +51,7 @@ void main() { fail('Only expected two messages.'); } n++; - }).asFuture(); + }).asFuture(); }); test('a server can communicate with a WebSocket client', () async { @@ -94,7 +94,7 @@ void main() { fail('Only expected two messages.'); } n++; - }).asFuture(); + }).asFuture(); }); }); }