Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/multi account #1443

Open
wants to merge 52 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
f618374
migrate signal.db to identity number folder
boyan01 Oct 13, 2023
23ba39c
Merge remote-tracking branch 'origin/main' into migrate_signal_db
boyan01 Oct 25, 2023
ede6c40
update
boyan01 Oct 25, 2023
b5d5393
add multi auth
boyan01 Oct 25, 2023
ee17496
refactor
boyan01 Oct 26, 2023
a150189
improve
boyan01 Oct 26, 2023
a62b567
refactor
boyan01 Oct 27, 2023
50d0ea3
fix
boyan01 Oct 30, 2023
9006677
fix network status
boyan01 Oct 30, 2023
ef306bb
fix swap account
boyan01 Oct 30, 2023
482516f
fix menu
boyan01 Oct 30, 2023
762552b
improve
boyan01 Oct 31, 2023
2c41399
move file
boyan01 Oct 31, 2023
ab67293
fix mention
boyan01 Oct 31, 2023
8f85ebf
refactor hive key values
boyan01 Oct 31, 2023
5534cfe
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 6, 2023
0a2b64d
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 7, 2023
77803bd
improve landing
boyan01 Nov 7, 2023
9472328
improve account server init
boyan01 Nov 7, 2023
32ce8cc
fix account server didn't stop
boyan01 Nov 8, 2023
eab8dde
fix conversation provider
boyan01 Nov 8, 2023
ad051eb
fix message font size setting
boyan01 Nov 9, 2023
f518fba
improve
boyan01 Nov 9, 2023
d27460b
improve landing
boyan01 Nov 9, 2023
10ca32d
fix hive cause logout error
boyan01 Nov 9, 2023
3fd11da
migrate hive crypto key value to db
boyan01 Nov 10, 2023
aab17f9
add migration test
boyan01 Nov 10, 2023
09d0783
add app database
boyan01 Nov 10, 2023
8529a06
refactor setting property to app setting key value
boyan01 Nov 11, 2023
cb6553e
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 13, 2023
15f8bb3
fix log
boyan01 Nov 13, 2023
d8f00e5
refactor key value
boyan01 Nov 13, 2023
7854ee9
refactor auth to database key value
boyan01 Nov 13, 2023
f052557
migrate setting to db key value
boyan01 Nov 13, 2023
f29c7cd
remove log
boyan01 Nov 13, 2023
1b3fb8b
fix test
boyan01 Nov 13, 2023
be236d8
fix conversation provider error
boyan01 Nov 13, 2023
9dfef43
refactor security key value
boyan01 Nov 14, 2023
d1a45c5
fix security lock
boyan01 Nov 14, 2023
3caa49e
clean security lock when all account logout
boyan01 Nov 14, 2023
7a80a3f
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 14, 2023
1ae368e
update pod
boyan01 Nov 14, 2023
caea7b1
fix legacy auth not removed.
boyan01 Nov 14, 2023
6002b9f
improve signal database and auth migration
boyan01 Nov 14, 2023
eba4fa2
fix format
boyan01 Nov 14, 2023
a88c457
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 17, 2023
84673a0
fix lint
boyan01 Nov 17, 2023
9071c81
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 20, 2023
5ffe354
improve migration
boyan01 Nov 24, 2023
3895ef2
Merge remote-tracking branch 'origin/main' into feat/multi_account
boyan01 Nov 24, 2023
b876e38
remove legacy auth and signal db
boyan01 Nov 24, 2023
5f10aab
fix format
boyan01 Nov 24, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 2 additions & 12 deletions lib/account/account_key_value.dart
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import '../utils/extension/extension.dart';
import '../utils/hive_key_values.dart';

class AccountKeyValue extends HiveKeyValue {
AccountKeyValue._() : super(_hiveAccount);

static AccountKeyValue? _instance;

static AccountKeyValue get instance => _instance ??= AccountKeyValue._();
class AccountKeyValue extends HiveKeyValue<dynamic> {
AccountKeyValue() : super(_hiveAccount);

static const _hiveAccount = 'account_box';
static const _hasSyncCircle = 'has_sync_circle';
Expand Down Expand Up @@ -65,10 +61,4 @@ class AccountKeyValue extends HiveKeyValue {
}
box.put(_keyRecentUsedEmoji, recentUsedEmoji);
}

@override
Future delete() {
_recentUsedEmoji = null;
return super.delete();
}
}
144 changes: 85 additions & 59 deletions lib/account/account_server.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:cross_file/cross_file.dart';
import 'package:dio/dio.dart';
import 'package:drift/drift.dart';
import 'package:flutter/services.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:mixin_bot_sdk_dart/mixin_bot_sdk_dart.dart';
import 'package:rxdart/rxdart.dart';
import 'package:stream_channel/isolate_channel.dart';
Expand All @@ -27,15 +28,14 @@ import '../db/extension/job.dart';
import '../db/mixin_database.dart' as db;
import '../enum/encrypt_category.dart';
import '../enum/message_category.dart';
import '../ui/provider/account_server_provider.dart';
import '../ui/provider/multi_auth_provider.dart';
import '../ui/provider/account/account_server_provider.dart';
import '../ui/provider/account/multi_auth_provider.dart';
import '../ui/provider/hive_key_value_provider.dart';
import '../ui/provider/setting_provider.dart';
import '../utils/app_lifecycle.dart';
import '../utils/attachment/attachment_util.dart';
import '../utils/attachment/download_key_value.dart';
import '../utils/extension/extension.dart';
import '../utils/file.dart';
import '../utils/hive_key_values.dart';
import '../utils/logger.dart';
import '../utils/mixin_api_client.dart';
import '../utils/proxy.dart';
Expand All @@ -46,33 +46,35 @@ import '../workers/isolate_event.dart';
import '../workers/message_worker_isolate.dart';
import 'account_key_value.dart';
import 'send_message_helper.dart';
import 'show_pin_message_key_value.dart';

class AccountServer {
AccountServer({
required this.multiAuthNotifier,
required this.settingChangeNotifier,
required this.database,
required this.currentConversationId,
this.userAgent,
this.deviceId,
required this.ref,
required this.hiveKeyValues,
});

static String? sid;

set language(String language) =>
client.dio.options.headers['Accept-Language'] = language;

final MultiAuthStateNotifier multiAuthNotifier;
final SettingChangeNotifier settingChangeNotifier;
final Database database;
final GetCurrentConversationId currentConversationId;

final HiveKeyValues hiveKeyValues;

PrivacyKeyValue get privacyKeyValue => hiveKeyValues.privacyKeyValue;

AccountKeyValue get accountKeyValue => hiveKeyValues.accountKeyValue;

Timer? checkSignalKeyTimer;

bool get _loginByPhoneNumber =>
AccountKeyValue.instance.primarySessionId == null;
bool get loginByPhoneNumber => accountKeyValue.primarySessionId == null;
String? userAgent;
String? deviceId;
SignalDatabase? signalDatabase;
final Ref ref;

Future<void> initServer(
String userId,
Expand All @@ -81,34 +83,40 @@ class AccountServer {
String privateKey,
) async {
if (sid == sessionId) return;

i('AccountServer init: $identityNumber');

sid = sessionId;

this.userId = userId;
this.sessionId = sessionId;
this.identityNumber = identityNumber;
this.privateKey = privateKey;

await initKeyValues(identityNumber);

await _initClient();

checkSignalKeyTimer = Timer.periodic(const Duration(days: 1), (timer) {
signalDatabase = await SignalDatabase.connect(
identityNumber: identityNumber,
fromMainIsolate: true,
);
checkSignalKeyTimer =
Timer.periodic(const Duration(days: 1), (timer) async {
i('refreshSignalKeys periodic');
checkSignalKey(client);
await checkSignalKey(client, signalDatabase!, database.cryptoKeyValue);
});

try {
await checkSignalKeys();
} catch (e, s) {
w('$e, $s');
} catch (error, stacktrace) {
e('checkSignalKeys failed: $error $stacktrace');
await signOutAndClear();
multiAuthNotifier.signOut();
multiAuthNotifier.signOut(userId);
rethrow;
}

unawaited(_start());

DownloadKeyValue.instance.messageIds.forEach((messageId) {
hiveKeyValues.downloadKeyValue.messageIds.forEach((messageId) {
attachmentUtil.downloadAttachment(messageId: messageId);
});
appActiveListener.addListener(onActive);
Expand All @@ -129,7 +137,7 @@ class AccountServer {
}
}
await signOutAndClear();
multiAuthNotifier.signOut();
multiAuthNotifier.signOut(userId);
}
}

Expand All @@ -144,7 +152,7 @@ class AccountServer {
userId: userId,
sessionId: sessionId,
privateKey: privateKey,
loginByPhoneNumber: _loginByPhoneNumber,
loginByPhoneNumber: loginByPhoneNumber,
interceptors: [
InterceptorsWrapper(
onError: (
Expand All @@ -156,9 +164,15 @@ class AccountServer {
},
),
],
)..configProxySetting(database.settingProperties);

attachmentUtil = AttachmentUtil.init(client, database, identityNumber);
)..configProxySetting(ref.read(settingProvider));

attachmentUtil = AttachmentUtil.init(
client,
database,
identityNumber,
hiveKeyValues.downloadKeyValue,
ref.read(settingProvider),
);
_sendMessageHelper =
SendMessageHelper(database, attachmentUtil, addSendingJob);

Expand Down Expand Up @@ -207,17 +221,18 @@ class AccountServer {
sessionId: sessionId,
privateKey: privateKey,
mixinDocumentDirectory: mixinDocumentsDirectory.path,
primarySessionId: AccountKeyValue.instance.primarySessionId,
loginByPhoneNumber: _loginByPhoneNumber,
primarySessionId: accountKeyValue.primarySessionId,
loginByPhoneNumber: loginByPhoneNumber,
rootIsolateToken: ServicesBinding.rootIsolateToken!,
),
errorsAreFatal: false,
onExit: exitReceivePort.sendPort,
onError: errorReceivePort.sendPort,
debugName: 'message_process_isolate_$identityNumber',
);
jobSubscribers
..add(exitReceivePort.listen((message) {
w('worker isolate service exited. $message');
w('worker isolate service exited($identityNumber). $message');
_connectedStateBehaviorSubject.add(ConnectedState.disconnected);
}))
..add(errorReceivePort.listen((error) {
Expand All @@ -241,6 +256,7 @@ class AccountServer {
case WorkerIsolateEventType.onIsolateReady:
d('message process service ready');
case WorkerIsolateEventType.onBlazeConnectStateChanged:
d('blaze connect state changed: ${event.argument}');
_connectedStateBehaviorSubject.add(event.argument as ConnectedState);
case WorkerIsolateEventType.onApiRequestedError:
_onClientRequestError(event.argument as DioException);
Expand All @@ -249,7 +265,7 @@ class AccountServer {
_onAttachmentDownloadRequest(request);
case WorkerIsolateEventType.showPinMessage:
final conversationId = event.argument as String;
unawaited(ShowPinMessageKeyValue.instance.show(conversationId));
unawaited(hiveKeyValues.showPinMessageKeyValue.show(conversationId));
}
}

Expand All @@ -258,12 +274,13 @@ class AccountServer {
AttachmentRequest request,
) async {
bool needDownload(String category) {
final settings = ref.read(settingProvider);
if (category.isImage) {
return settingChangeNotifier.photoAutoDownload;
return settings.photoAutoDownload;
} else if (category.isVideo) {
return settingChangeNotifier.videoAutoDownload;
return settings.videoAutoDownload;
} else if (category.isData) {
return settingChangeNotifier.fileAutoDownload;
return settings.fileAutoDownload;
}
return true;
}
Expand Down Expand Up @@ -301,16 +318,22 @@ class AccountServer {

Future<void> signOutAndClear() async {
_sendEventToWorkerIsolate(MainIsolateEventType.exit);
await client.accountApi.logout(LogoutRequest(sessionId));
try {
await client.accountApi.logout(LogoutRequest(sessionId));
} catch (error, stacktrace) {
e('signOutAndClear logout error: $error $stacktrace');
}
await Future.wait(jobSubscribers.map((s) => s.cancel()));
jobSubscribers.clear();

await clearKeyValues();
await hiveKeyValues.clearAll();
await database.cryptoKeyValue.clear();

try {
await SignalDatabase.get.clear();
} catch (_) {
// ignore closed database error
await signalDatabase?.clear();
await signalDatabase?.close();
} catch (error, stacktrace) {
e('signOutAndClear signalDatabase error: $error $stacktrace');
}

try {
Expand Down Expand Up @@ -693,7 +716,7 @@ class AccountServer {
List<String> messageIds,
Map<String, int?> messageExpireAt,
) async {
final primarySessionId = AccountKeyValue.instance.primarySessionId;
final primarySessionId = accountKeyValue.primarySessionId;
if (primarySessionId == null) {
return;
}
Expand All @@ -709,6 +732,7 @@ class AccountServer {
}

Future<void> stop() async {
i('stop account server');
appActiveListener.removeListener(onActive);
checkSignalKeyTimer?.cancel();
_sendEventToWorkerIsolate(MainIsolateEventType.exit);
Expand Down Expand Up @@ -745,18 +769,18 @@ class AccountServer {
}

Future<void> checkSignalKeys() async {
final hasPushSignalKeys = PrivacyKeyValue.instance.hasPushSignalKeys;
final hasPushSignalKeys = privacyKeyValue.hasPushSignalKeys;
if (hasPushSignalKeys) {
unawaited(checkSignalKey(client));
unawaited(
checkSignalKey(client, signalDatabase!, database.cryptoKeyValue));
} else {
await refreshSignalKeys(client);
PrivacyKeyValue.instance.hasPushSignalKeys = true;
await refreshSignalKeys(client, signalDatabase!, database.cryptoKeyValue);
privacyKeyValue.hasPushSignalKeys = true;
}
}

Future<void> refreshSticker({bool force = false}) async {
final refreshStickerLastTime =
AccountKeyValue.instance.refreshStickerLastTime;
final refreshStickerLastTime = accountKeyValue.refreshStickerLastTime;
final now = DateTime.now().millisecondsSinceEpoch;
if (!force && now - refreshStickerLastTime < hours24) {
return;
Expand Down Expand Up @@ -797,16 +821,16 @@ class AccountServer {
}

if (hasNewAlbum) {
AccountKeyValue.instance.hasNewAlbum = true;
accountKeyValue.hasNewAlbum = true;
}

AccountKeyValue.instance.refreshStickerLastTime = now;
accountKeyValue.refreshStickerLastTime = now;
}

final refreshUserIdSet = <dynamic>{};

Future<void> initCircles() async {
final hasSyncCircle = AccountKeyValue.instance.hasSyncCircle;
final hasSyncCircle = accountKeyValue.hasSyncCircle;
if (hasSyncCircle) {
return;
}
Expand All @@ -821,16 +845,16 @@ class AccountServer {
await handleCircle(circle);
});

AccountKeyValue.instance.hasSyncCircle = true;
accountKeyValue.hasSyncCircle = true;
}

Future<void> _cleanupQuoteContent() async {
final clean = AccountKeyValue.instance.alreadyCleanupQuoteContent;
final clean = accountKeyValue.alreadyCleanupQuoteContent;
if (clean) {
return;
}
await database.jobDao.insert(createCleanupQuoteContentJob());
AccountKeyValue.instance.alreadyCleanupQuoteContent = true;
accountKeyValue.alreadyCleanupQuoteContent = true;
}

Future<void> checkMigration() async {
Expand Down Expand Up @@ -1386,13 +1410,15 @@ class AccountServer {
Future<void> pinMessage({
required String conversationId,
required List<PinMessageMinimal> pinMessageMinimals,
}) =>
_sendMessageHelper.sendPinMessage(
conversationId: conversationId,
senderId: userId,
pinMessageMinimals: pinMessageMinimals,
pin: true,
);
}) async {
await _sendMessageHelper.sendPinMessage(
conversationId: conversationId,
senderId: userId,
pinMessageMinimals: pinMessageMinimals,
pin: true,
);
unawaited(hiveKeyValues.showPinMessageKeyValue.show(conversationId));
}

Future<void> unpinMessage({
required String conversationId,
Expand Down
Loading
Loading