Rewrite license code to avoid async* (#95130)
This commit is contained in:
parent
126ee23a5a
commit
fc1d17d35c
@ -2,6 +2,8 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:meta/meta.dart' show visibleForTesting;
|
import 'package:meta/meta.dart' show visibleForTesting;
|
||||||
|
|
||||||
/// Signature for callbacks passed to [LicenseRegistry.addLicense].
|
/// Signature for callbacks passed to [LicenseRegistry.addLicense].
|
||||||
@ -70,8 +72,8 @@ enum _LicenseEntryWithLineBreaksParserState {
|
|||||||
///
|
///
|
||||||
/// ```dart
|
/// ```dart
|
||||||
/// void initMyLibrary() {
|
/// void initMyLibrary() {
|
||||||
/// LicenseRegistry.addLicense(() async* {
|
/// LicenseRegistry.addLicense(() => Stream<LicenseEntry>.value(
|
||||||
/// yield const LicenseEntryWithLineBreaks(<String>['my_library'], '''
|
/// const LicenseEntryWithLineBreaks(<String>['my_library'], '''
|
||||||
/// Copyright 2016 The Sample Authors. All rights reserved.
|
/// Copyright 2016 The Sample Authors. All rights reserved.
|
||||||
///
|
///
|
||||||
/// Redistribution and use in source and binary forms, with or without
|
/// Redistribution and use in source and binary forms, with or without
|
||||||
@ -98,8 +100,9 @@ enum _LicenseEntryWithLineBreaksParserState {
|
|||||||
/// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
/// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
/// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
/// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
/// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''');
|
/// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.''',
|
||||||
/// });
|
/// ),
|
||||||
|
/// ));
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
/// {@end-tool}
|
/// {@end-tool}
|
||||||
@ -309,14 +312,19 @@ class LicenseRegistry {
|
|||||||
/// Returns the licenses that have been registered.
|
/// Returns the licenses that have been registered.
|
||||||
///
|
///
|
||||||
/// Generating the list of licenses is expensive.
|
/// Generating the list of licenses is expensive.
|
||||||
// TODO(dnfield): Refactor the license logic.
|
static Stream<LicenseEntry> get licenses {
|
||||||
// https://github.com/flutter/flutter/issues/95043
|
|
||||||
// flutter_ignore: no_sync_async_star
|
|
||||||
static Stream<LicenseEntry> get licenses async* {
|
|
||||||
if (_collectors == null)
|
if (_collectors == null)
|
||||||
return;
|
return const Stream<LicenseEntry>.empty();
|
||||||
for (final LicenseEntryCollector collector in _collectors!)
|
|
||||||
yield* collector();
|
late final StreamController<LicenseEntry> controller;
|
||||||
|
controller = StreamController<LicenseEntry>(
|
||||||
|
onListen: () async {
|
||||||
|
for (final LicenseEntryCollector collector in _collectors!)
|
||||||
|
await controller.addStream(collector());
|
||||||
|
await controller.close();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
return controller.stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resets the internal state of [LicenseRegistry]. Intended for use in
|
/// Resets the internal state of [LicenseRegistry]. Intended for use in
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
import 'dart:typed_data';
|
||||||
import 'dart:ui' as ui;
|
import 'dart:ui' as ui;
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -144,45 +145,29 @@ mixin ServicesBinding on BindingBase, SchedulerBinding {
|
|||||||
LicenseRegistry.addLicense(_addLicenses);
|
LicenseRegistry.addLicense(_addLicenses);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(dnfield): Refactor the license logic.
|
Stream<LicenseEntry> _addLicenses() {
|
||||||
// https://github.com/flutter/flutter/issues/95043
|
late final StreamController<LicenseEntry> controller;
|
||||||
// flutter_ignore: no_sync_async_star
|
controller = StreamController<LicenseEntry>(
|
||||||
Stream<LicenseEntry> _addLicenses() async* {
|
onListen: () async {
|
||||||
// Using _something_ here to break
|
late final String rawLicenses;
|
||||||
// this into two parts is important because isolates take a while to copy
|
if (kIsWeb) {
|
||||||
// data at the moment, and if we receive the data in the same event loop
|
// NOTICES for web isn't compressed since we don't have access to
|
||||||
// iteration as we send the data to the next isolate, we are definitely
|
// dart:io on the client side and it's already compressed between
|
||||||
// going to miss frames. Another solution would be to have the work all
|
// the server and client.
|
||||||
// happen in one isolate, and we may go there eventually, but first we are
|
rawLicenses = await rootBundle.loadString('NOTICES', cache: false);
|
||||||
// going to see if isolate communication can be made cheaper.
|
} else {
|
||||||
// See: https://github.com/dart-lang/sdk/issues/31959
|
// The compressed version doesn't have a more common .gz extension
|
||||||
// https://github.com/dart-lang/sdk/issues/31960
|
// because gradle for Android non-transparently manipulates .gz files.
|
||||||
// TODO(ianh): Remove this complexity once these bugs are fixed.
|
final ByteData licenseBytes = await rootBundle.load('NOTICES.Z');
|
||||||
final Completer<String> rawLicenses = Completer<String>();
|
final List<int> unzippedBytes = await compute<List<int>, List<int>>(gzip.decode, licenseBytes.buffer.asUint8List(), debugLabel: 'decompressLicenses');
|
||||||
scheduleTask(() async {
|
rawLicenses = await compute<List<int>, String>(utf8.decode, unzippedBytes, debugLabel: 'utf8DecodeLicenses');
|
||||||
rawLicenses.complete(
|
}
|
||||||
kIsWeb
|
final List<LicenseEntry> licenses = await compute<String, List<LicenseEntry>>(_parseLicenses, rawLicenses, debugLabel: 'parseLicenses');
|
||||||
// NOTICES for web isn't compressed since we don't have access to
|
licenses.forEach(controller.add);
|
||||||
// dart:io on the client side and it's already compressed between
|
await controller.close();
|
||||||
// the server and client.
|
},
|
||||||
? rootBundle.loadString('NOTICES', cache: false)
|
);
|
||||||
: () async {
|
return controller.stream;
|
||||||
// The compressed version doesn't have a more common .gz extension
|
|
||||||
// because gradle for Android non-transparently manipulates .gz files.
|
|
||||||
final ByteData licenseBytes = await rootBundle.load('NOTICES.Z');
|
|
||||||
List<int> bytes = licenseBytes.buffer.asUint8List();
|
|
||||||
bytes = gzip.decode(bytes);
|
|
||||||
return utf8.decode(bytes);
|
|
||||||
}(),
|
|
||||||
);
|
|
||||||
}, Priority.animation);
|
|
||||||
await rawLicenses.future;
|
|
||||||
final Completer<List<LicenseEntry>> parsedLicenses = Completer<List<LicenseEntry>>();
|
|
||||||
scheduleTask(() async {
|
|
||||||
parsedLicenses.complete(compute<String, List<LicenseEntry>>(_parseLicenses, await rawLicenses.future, debugLabel: 'parseLicenses'));
|
|
||||||
}, Priority.animation);
|
|
||||||
await parsedLicenses.future;
|
|
||||||
yield* Stream<LicenseEntry>.fromIterable(await parsedLicenses.future);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is run in another isolate created by _addLicenses above.
|
// This is run in another isolate created by _addLicenses above.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user