perf: avoid duplicate bootstrap work on join

This commit is contained in:
Edison Jwa
2026-05-24 21:02:16 +09:00
parent b494f8902d
commit b8195acc9b
2 changed files with 129 additions and 9 deletions
@@ -1,6 +1,7 @@
import 'dart:io' show File;
import 'dart:io' show Directory, File;
import 'package:connectivity_plus/connectivity_plus.dart';
import 'package:flutter/foundation.dart' show visibleForTesting;
import 'package:flutter/services.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:path_provider/path_provider.dart';
@@ -9,7 +10,19 @@ import '../src/rust/api.dart' as rust;
const String appSemverBaseline = 'v0.1.0';
const String _sileroVadAsset = 'assets/models/silero_vad.onnx';
const String _tenVadAsset = 'assets/models/ten_vad.onnx';
typedef StorageDirectoryProvider = Future<Directory> Function();
typedef StorageInitializer = Future<void> Function(String dir);
Future<void>? _storageInitFuture;
Future<void>? _vadBootstrapFuture;
StorageDirectoryProvider _storageDirectoryProvider =
getApplicationSupportDirectory;
StorageInitializer _storageInitializer = _defaultStorageInitializer;
Future<void> _defaultStorageInitializer(String dir) {
return rust.initStorage(dir: dir);
}
Future<File> _copyBundledAssetToDocuments({
required String assetPath,
@@ -29,16 +42,28 @@ Future<File> _copyBundledAssetToDocuments({
}
Future<void> configureBundledVadModels() async {
final existing = _vadBootstrapFuture;
if (existing != null) {
await existing;
return;
}
final bootstrap = _configureBundledVadModelsImpl();
_vadBootstrapFuture = bootstrap;
try {
await bootstrap;
} catch (_) {
_vadBootstrapFuture = null;
rethrow;
}
}
Future<void> _configureBundledVadModelsImpl() async {
final silero = await _copyBundledAssetToDocuments(
assetPath: _sileroVadAsset,
fileName: 'silero_vad.onnx',
);
final ten = await _copyBundledAssetToDocuments(
assetPath: _tenVadAsset,
fileName: 'ten_vad.onnx',
);
await rust.setVadModelPath(path: silero.path);
await rust.setTenVadModelPath(path: ten.path);
}
/// Resolve the human-readable app version displayed in About.
@@ -69,15 +94,45 @@ String appVersionFromBuildNumber({
}
Future<void> wireStorage() async {
final existing = _storageInitFuture;
if (existing != null) {
await existing;
return;
}
final initFuture = _wireStorageImpl();
_storageInitFuture = initFuture;
await initFuture;
}
Future<void> _wireStorageImpl() async {
var initialized = false;
try {
final dir = await getApplicationSupportDirectory();
await rust.initStorage(dir: dir.path);
final dir = await _storageDirectoryProvider();
await _storageInitializer(dir.path);
initialized = true;
} catch (_) {
// Best-effort; missing storage just means no identity persistence
// and no bookmark list this session.
} finally {
if (!initialized) {
_storageInitFuture = null;
}
}
}
@visibleForTesting
void debugResetStorageBootstrap({
StorageDirectoryProvider? storageDirectoryProvider,
StorageInitializer? storageInitializer,
}) {
_storageInitFuture = null;
_vadBootstrapFuture = null;
_storageDirectoryProvider =
storageDirectoryProvider ?? getApplicationSupportDirectory;
_storageInitializer = storageInitializer ?? _defaultStorageInitializer;
}
rust.BridgeNetworkState _mapConnectivity(List<ConnectivityResult> results) {
if (results.isEmpty) return rust.BridgeNetworkState.unknown;
final allNone = results.every((r) => r == ConnectivityResult.none);
@@ -1,8 +1,19 @@
import 'dart:async';
import 'dart:io';
import 'package:flutter_test/flutter_test.dart';
import 'package:chanora_flutter/services/app_bootstrap.dart';
void main() {
setUp(() {
debugResetStorageBootstrap();
});
tearDown(() {
debugResetStorageBootstrap();
});
test('app version appends platform build number', () {
expect(
appVersionFromBuildNumber(
@@ -19,4 +30,58 @@ void main() {
'v1.2.3-rc.4',
);
});
test('wireStorage reuses the in-flight initialization future', () async {
final completer = Completer<void>();
final tempDir = await Directory.systemTemp.createTemp(
'chanora-app-bootstrap-test',
);
addTearDown(() => tempDir.delete(recursive: true));
var initCalls = 0;
debugResetStorageBootstrap(
storageDirectoryProvider: () async => tempDir,
storageInitializer: (dir) async {
initCalls += 1;
await completer.future;
},
);
final first = wireStorage();
final second = wireStorage();
var secondCompleted = false;
second.then((_) => secondCompleted = true);
await Future<void>.delayed(Duration.zero);
expect(initCalls, 1);
expect(secondCompleted, isFalse);
completer.complete();
await Future.wait([first, second]);
expect(initCalls, 1);
expect(secondCompleted, isTrue);
});
test('wireStorage retries after a failed initialization attempt', () async {
final tempDir = await Directory.systemTemp.createTemp(
'chanora-app-bootstrap-test',
);
addTearDown(() => tempDir.delete(recursive: true));
var initCalls = 0;
debugResetStorageBootstrap(
storageDirectoryProvider: () async => tempDir,
storageInitializer: (dir) async {
initCalls += 1;
if (initCalls == 1) {
throw const FileSystemException('boom');
}
},
);
await wireStorage();
await wireStorage();
expect(initCalls, 2);
});
}