Run startup sync in background isolate

This commit is contained in:
Ming Ming 2022-07-28 17:13:39 +08:00
parent 49b5901149
commit 3387378181
6 changed files with 127 additions and 16 deletions

View file

@ -39,7 +39,10 @@ import 'package:visibility_detector/visibility_detector.dart';
enum InitIsolateType {
main,
service,
/// Isolates with Flutter engine, e.g., those spawned by flutter_isolate or
/// flutter_background_service
flutterIsolate,
}
Future<void> init(InitIsolateType isolateType) async {
@ -200,7 +203,7 @@ Future<sql.SqliteDb> _createDb(InitIsolateType isolateType) async {
return sql_isolate.createDb();
}
case InitIsolateType.service:
case InitIsolateType.flutterIsolate:
// service already runs in an isolate
return sql.SqliteDb();
}

View file

@ -70,7 +70,7 @@ class _Service {
final service = FlutterBackgroundService();
service.setForegroundMode(true);
await app_init.init(app_init.InitIsolateType.service);
await app_init.init(app_init.InitIsolateType.flutterIsolate);
await _L10n().init();
_log.info("[call] Service started");

View file

@ -0,0 +1,104 @@
import 'dart:async';
import 'package:event_bus/event_bus.dart';
import 'package:flutter_isolate/flutter_isolate.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
import 'package:nc_photos/app_init.dart' as app_init;
import 'package:nc_photos/di_container.dart';
import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/platform/k.dart' as platform_k;
import 'package:nc_photos/type.dart';
import 'package:nc_photos/use_case/sync_favorite.dart';
/// Sync various properties with server during startup
class StartupSync {
StartupSync(this._c)
: assert(require(_c)),
assert(SyncFavorite.require(_c));
static bool require(DiContainer c) => true;
/// Sync in a background isolate
static Future<SyncResult> runInIsolate(Account account) async {
if (platform_k.isWeb) {
// not supported on web
final c = KiwiContainer().resolve<DiContainer>();
return await StartupSync(c)(account);
} else {
// we can't use regular isolate here because self-signed cert support
// requires native plugins
final resultJson =
await flutterCompute(_isolateMain, _IsolateMessage(account).toJson());
final result = SyncResult.fromJson(resultJson);
// events fired in background isolate won't be noticed by the main isolate,
// so we fire them again here
_broadcastResult(account, result);
return result;
}
}
Future<SyncResult> call(Account account) async {
_log.info("[_run] Begin sync");
late final int syncFavoriteCount;
try {
syncFavoriteCount = await SyncFavorite(_c)(account);
} catch (e, stackTrace) {
_log.shout("[_run] Failed while SyncFavorite", e, stackTrace);
syncFavoriteCount = -1;
}
return SyncResult(syncFavoriteCount);
}
static void _broadcastResult(Account account, SyncResult result) {
final eventBus = KiwiContainer().resolve<EventBus>();
if (result.syncFavoriteCount > 0) {
eventBus.fire(FavoriteResyncedEvent(account));
}
}
final DiContainer _c;
static final _log = Logger("use_case.startup_sync.StartupSync");
}
class SyncResult {
const SyncResult(this.syncFavoriteCount);
factory SyncResult.fromJson(JsonObj json) => SyncResult(
json["syncFavoriteCount"],
);
JsonObj toJson() => {
"syncFavoriteCount": syncFavoriteCount,
};
final int syncFavoriteCount;
}
class _IsolateMessage {
const _IsolateMessage(this.account);
factory _IsolateMessage.fromJson(JsonObj json) => _IsolateMessage(
Account.fromJson(
json["account"].cast<String, dynamic>(),
upgraderV1: const AccountUpgraderV1(),
)!,
);
JsonObj toJson() => {
"account": account.toJson(),
};
final Account account;
}
Future<JsonObj> _isolateMain(JsonObj messageJson) async {
final message = _IsolateMessage.fromJson(messageJson);
await app_init.init(app_init.InitIsolateType.flutterIsolate);
final c = KiwiContainer().resolve<DiContainer>();
final result = await StartupSync(c)(message.account);
return result.toJson();
}

View file

@ -21,7 +21,6 @@ import 'package:nc_photos/entity/album.dart';
import 'package:nc_photos/entity/file.dart';
import 'package:nc_photos/entity/file_util.dart' as file_util;
import 'package:nc_photos/event/event.dart';
import 'package:nc_photos/exception.dart';
import 'package:nc_photos/exception_util.dart' as exception_util;
import 'package:nc_photos/k.dart' as k;
import 'package:nc_photos/language_util.dart' as language_util;
@ -35,7 +34,7 @@ import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/use_case/sync_favorite.dart';
import 'package:nc_photos/use_case/startup_sync.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
import 'package:nc_photos/widget/handler/add_selection_to_album_handler.dart';
@ -381,7 +380,7 @@ class _HomePhotosState extends State<HomePhotos>
state is ScanAccountDirBlocLoading) {
_transformItems(state.files);
if (state is ScanAccountDirBlocSuccess) {
_syncFavorite();
_startupSync();
_tryStartMetadataTask();
}
} else if (state is ScanAccountDirBlocFailure) {
@ -536,18 +535,10 @@ class _HomePhotosState extends State<HomePhotos>
}
}
Future<void> _syncFavorite() async {
Future<void> _startupSync() async {
if (!_hasResyncedFavorites.value) {
final c = KiwiContainer().resolve<DiContainer>();
try {
await SyncFavorite(c)(widget.account);
} catch (e, stackTrace) {
if (e is! ApiException) {
_log.shout(
"[_syncFavorite] Failed while SyncFavorite", e, stackTrace);
}
}
_hasResyncedFavorites.value = true;
StartupSync.runInIsolate(widget.account);
}
}

View file

@ -490,6 +490,15 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.3.0"
flutter_isolate:
dependency: "direct main"
description:
path: "."
ref: "2.0.2-nc-photos-1"
resolved-ref: "8d8516b169860caba762baed43a7888798c5b7d7"
url: "https://gitlab.com/nc-photos/flutter_isolate.git"
source: git
version: "2.0.2"
flutter_keyboard_visibility:
dependency: transitive
description:

View file

@ -57,6 +57,10 @@ dependencies:
url: https://gitlab.com/nc-photos/flutter_background_service.git
ref: v0.2.6-nc-photos-2
flutter_bloc: ^8.0.0
flutter_isolate:
git:
url: https://gitlab.com/nc-photos/flutter_isolate.git
ref: 2.0.2-nc-photos-1
flutter_map: ^1.1.1
flutter_staggered_grid_view:
git: