diff --git a/app/lib/app_init.dart b/app/lib/app_init.dart index 29a4e6c7..60343963 100644 --- a/app/lib/app_init.dart +++ b/app/lib/app_init.dart @@ -46,6 +46,7 @@ import 'package:nc_photos/session_storage.dart'; import 'package:nc_photos/touch_manager.dart'; import 'package:np_db/np_db.dart'; import 'package:np_gps_map/np_gps_map.dart'; +import 'package:np_http/np_http.dart'; import 'package:np_log/np_log.dart' as np_log; import 'package:np_platform_util/np_platform_util.dart'; import 'package:visibility_detector/visibility_detector.dart'; @@ -70,6 +71,7 @@ Future init(InitIsolateType isolateType) async { await _initPref(); await _initAccountPrefs(); _initEquatable(); + await initHttp(k.versionStr); if (features.isSupportSelfSignedCert) { await _initSelfSignedCertManager(); } diff --git a/app/lib/cache_manager_util.dart b/app/lib/cache_manager_util.dart index 902315b6..512cb5a4 100644 --- a/app/lib/cache_manager_util.dart +++ b/app/lib/cache_manager_util.dart @@ -1,6 +1,7 @@ import 'package:flutter_cache_manager/flutter_cache_manager.dart'; // ignore: implementation_imports import 'package:flutter_cache_manager/src/cache_store.dart'; +import 'package:np_http/np_http.dart'; class CancelableGetFile { CancelableGetFile(this.store); @@ -41,6 +42,7 @@ class ThumbnailCacheManager { key, stalePeriod: const Duration(days: 30), maxNrOfCacheObjects: 50000, + fileService: HttpFileService(httpClient: makeHttpClient()), ), ); } @@ -58,6 +60,7 @@ class LargeImageCacheManager { key, stalePeriod: const Duration(days: 30), maxNrOfCacheObjects: 1000, + fileService: HttpFileService(httpClient: makeHttpClient()), ), ); } @@ -73,6 +76,7 @@ class CoverCacheManager { key, stalePeriod: const Duration(days: 30), maxNrOfCacheObjects: 300, + fileService: HttpFileService(httpClient: makeHttpClient()), ), ); } diff --git a/app/lib/mobile/download.dart b/app/lib/mobile/download.dart index 759813b7..515bbcfb 100644 --- a/app/lib/mobile/download.dart +++ b/app/lib/mobile/download.dart @@ -7,6 +7,7 @@ import 'package:nc_photos/exception.dart'; import 'package:nc_photos/platform/download.dart' as itf; import 'package:nc_photos_plugin/nc_photos_plugin.dart'; import 'package:np_codegen/np_codegen.dart'; +import 'package:np_http/np_http.dart'; import 'package:np_platform_util/np_platform_util.dart'; import 'package:path_provider/path_provider.dart'; import 'package:uuid/uuid.dart'; @@ -65,7 +66,7 @@ class _AndroidDownload extends itf.Download { try { final uri = Uri.parse(url); final req = http.Request("GET", uri)..headers.addAll(headers ?? {}); - final response = await http.Client().send(req); + final response = await makeHttpClient().send(req); bool isEnd = false; Object? error; final size = response.contentLength; diff --git a/app/lib/web/download.dart b/app/lib/web/download.dart index ce00cd19..7d708589 100644 --- a/app/lib/web/download.dart +++ b/app/lib/web/download.dart @@ -2,6 +2,7 @@ import 'package:http/http.dart' as http; import 'package:nc_photos/exception.dart'; import 'package:nc_photos/platform/download.dart' as itf; import 'package:nc_photos/web/file_saver.dart'; +import 'package:np_http/np_http.dart'; class DownloadBuilder extends itf.DownloadBuilder { @override @@ -33,7 +34,7 @@ class _WebDownload extends itf.Download { final uri = Uri.parse(url); final req = http.Request("GET", uri)..headers.addAll(headers ?? {}); final response = - await http.Response.fromStream(await http.Client().send(req)); + await http.Response.fromStream(await makeHttpClient().send(req)); if (response.statusCode ~/ 100 != 2) { throw DownloadException( "Failed downloading $filename (HTTP ${response.statusCode})"); diff --git a/app/pubspec.lock b/app/pubspec.lock index 821469f9..a92b38a3 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -284,6 +284,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.6.3" + cronet_http: + dependency: transitive + description: + name: cronet_http + sha256: "9b9f00ae48971bc8a8cbdd4528bd35511adce00fb79d1ebf9f9907667056640f" + url: "https://pub.dev" + source: hosted + version: "1.2.0" crypto: dependency: "direct main" description: @@ -805,6 +813,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + jni: + dependency: transitive + description: + name: jni + sha256: "499558e919997adfc45809a66caf0b95b91393e23289dd2826b152f8f04e6611" + url: "https://pub.dev" + source: hosted + version: "0.7.3" js: dependency: transitive description: @@ -1114,6 +1130,13 @@ packages: relative: true source: path version: "0.0.1" + np_http: + dependency: "direct main" + description: + path: "../np_http" + relative: true + source: path + version: "1.0.0" np_lints: dependency: "direct dev" description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index 6e2cbc5e..a1d91443 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -110,6 +110,8 @@ dependencies: path: ../np_geocoder np_gps_map: path: ../np_gps_map + np_http: + path: ../np_http np_log: path: ../np_log np_math: diff --git a/np_api/lib/src/api.dart b/np_api/lib/src/api.dart index a5d4d111..160ff4a5 100644 --- a/np_api/lib/src/api.dart +++ b/np_api/lib/src/api.dart @@ -4,6 +4,7 @@ import 'package:logging/logging.dart'; import 'package:np_api/src/type.dart'; import 'package:np_api/src/util.dart'; import 'package:np_codegen/np_codegen.dart'; +import 'package:np_http/np_http.dart'; import 'package:xml/xml.dart'; part 'api.g.dart'; @@ -65,7 +66,7 @@ class Api { } _log.finer(req.url); final response = - await http.Response.fromStream(await http.Client().send(req)); + await http.Response.fromStream(await makeHttpClient().send(req)); if (!isHttpStatusGood(response.statusCode)) { if (response.statusCode == 404) { _log.severe( diff --git a/np_api/pubspec.yaml b/np_api/pubspec.yaml index 0da6b993..03efe42f 100644 --- a/np_api/pubspec.yaml +++ b/np_api/pubspec.yaml @@ -18,6 +18,8 @@ dependencies: path: ../codegen np_common: path: ../np_common + np_http: + path: ../np_http np_log: path: ../np_log np_string: diff --git a/np_http/.gitignore b/np_http/.gitignore new file mode 100644 index 00000000..3cceda55 --- /dev/null +++ b/np_http/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/np_http/lib/np_http.dart b/np_http/lib/np_http.dart new file mode 100644 index 00000000..8120fd01 --- /dev/null +++ b/np_http/lib/np_http.dart @@ -0,0 +1,3 @@ +library np_http; + +export 'src/http.dart'; diff --git a/np_http/lib/src/http.dart b/np_http/lib/src/http.dart new file mode 100644 index 00000000..aaebed36 --- /dev/null +++ b/np_http/lib/src/http.dart @@ -0,0 +1,35 @@ +import 'package:cronet_http/cronet_http.dart'; +import 'package:http/http.dart'; +import 'package:logging/logging.dart'; +import 'package:np_platform_util/np_platform_util.dart'; + +import 'http_stub.dart' + if (dart.library.js_interop) 'http_browser.dart' + if (dart.library.io) 'http_io.dart'; + +Future initHttp(String appVersion) async { + _userAgent = "nc-photos $appVersion"; + if (getRawPlatform() == NpPlatform.android) { + try { + _cronetEngine = CronetEngine.build( + enableHttp2: true, + userAgent: _userAgent, + ); + } catch (e, stackTrace) { + _log.severe("Failed creating CronetEngine", e, stackTrace); + } + } +} + +Client makeHttpClient() { + if (getRawPlatform() == NpPlatform.android && _cronetEngine != null) { + return CronetClient.fromCronetEngine(_cronetEngine!); + } else { + return makeHttpClientImpl(userAgent: _userAgent); + } +} + +late final String _userAgent; +CronetEngine? _cronetEngine; + +final _log = Logger("np_http"); diff --git a/np_http/lib/src/http_browser.dart b/np_http/lib/src/http_browser.dart new file mode 100644 index 00000000..cd51f099 --- /dev/null +++ b/np_http/lib/src/http_browser.dart @@ -0,0 +1,8 @@ +import 'package:http/browser_client.dart'; +import 'package:http/http.dart'; + +Client makeHttpClientImpl({ + required String userAgent, +}) { + return BrowserClient(); +} diff --git a/np_http/lib/src/http_io.dart b/np_http/lib/src/http_io.dart new file mode 100644 index 00000000..332e1de8 --- /dev/null +++ b/np_http/lib/src/http_io.dart @@ -0,0 +1,10 @@ +import 'dart:io'; + +import 'package:http/http.dart'; +import 'package:http/io_client.dart'; + +Client makeHttpClientImpl({ + required String userAgent, +}) { + return IOClient(HttpClient()..userAgent = userAgent); +} diff --git a/np_http/lib/src/http_stub.dart b/np_http/lib/src/http_stub.dart new file mode 100644 index 00000000..f7c70ea3 --- /dev/null +++ b/np_http/lib/src/http_stub.dart @@ -0,0 +1,7 @@ +import 'package:http/http.dart'; + +Client makeHttpClientImpl({ + required String userAgent, +}) { + throw UnsupportedError("Unsupported"); +} diff --git a/np_http/pubspec.yaml b/np_http/pubspec.yaml new file mode 100644 index 00000000..a20c5ee1 --- /dev/null +++ b/np_http/pubspec.yaml @@ -0,0 +1,19 @@ +name: np_http +description: A starting point for Dart libraries or applications. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo +publish_to: none + +environment: + sdk: ">=3.2.0 <4.0.0" + +dependencies: + cronet_http: ^1.2.0 + http: ^1.1.2 + logging: ^1.2.0 + np_platform_util: + path: ../np_platform_util + +dev_dependencies: + np_lints: + path: ../np_lints