Save user+client in Prefs and only background-fetch them on startup

This commit is contained in:
Mike Schwörer 2024-06-17 22:53:03 +02:00
parent c8bc7665f7
commit 5b8a1e86e0
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
4 changed files with 121 additions and 28 deletions

View File

@ -101,20 +101,19 @@ void main() async {
final appAuth = AppAuth(); // ensure UserAccount is loaded final appAuth = AppAuth(); // ensure UserAccount is loaded
if (appAuth.isAuth()) { if (appAuth.isAuth()) {
// load user+client in background
() async {
try { try {
print('[INIT] Load User...');
await appAuth.loadUser(); await appAuth.loadUser();
//TODO fallback to cached user (perhaps event use cached client (if exists) directly and only update/load in background)
} catch (exc, trace) { } catch (exc, trace) {
ApplicationLog.error('Failed to load user (on startup): ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to load user (background load on startup): ' + exc.toString(), trace: trace);
} }
try { try {
print('[INIT] Load Client...');
await appAuth.loadClient(); await appAuth.loadClient();
//TODO fallback to cached client (perhaps event use cached client (if exists) directly and only update/load in background)
} catch (exc, trace) { } catch (exc, trace) {
ApplicationLog.error('Failed to load user (on startup): ' + exc.toString(), trace: trace); ApplicationLog.error('Failed to load user (background load on startup): ' + exc.toString(), trace: trace);
} }
}();
} }
if (!Platform.isLinux) { if (!Platform.isLinux) {

View File

@ -32,6 +32,19 @@ class Client {
); );
} }
Map<String, dynamic> toJson() {
return {
'client_id': clientID,
'user_id': userID,
'type': type,
'fcm_token': fcmToken,
'timestamp_created': timestampCreated,
'agent_model': agentModel,
'agent_version': agentVersion,
'name': name,
};
}
static List<Client> fromJsonArray(List<dynamic> jsonArr) { static List<Client> fromJsonArray(List<dynamic> jsonArr) {
return jsonArr.map<Client>((e) => Client.fromJson(e as Map<String, dynamic>)).toList(); return jsonArr.map<Client>((e) => Client.fromJson(e as Map<String, dynamic>)).toList();
} }

View File

@ -63,6 +63,29 @@ class User {
maxUserMessageIDLength: json['max_user_message_id_length'] as int, maxUserMessageIDLength: json['max_user_message_id_length'] as int,
); );
} }
Map<String, dynamic> toJson() {
return {
'user_id': userID,
'username': username,
'timestamp_created': timestampCreated,
'timestamp_lastread': timestampLastRead,
'timestamp_lastsent': timestampLastSent,
'messages_sent': messagesSent,
'quota_used': quotaUsed,
'quota_remaining': quotaRemaining,
'quota_max': quotaPerDay,
'is_pro': isPro,
'default_channel': defaultChannel,
'max_body_size': maxBodySize,
'max_title_length': maxTitleLength,
'default_priority': defaultPriority,
'max_channel_name_length': maxChannelNameLength,
'max_channel_description_length': maxChannelDescriptionLength,
'max_sender_name_length': maxSenderNameLength,
'max_user_message_id_length': maxUserMessageIDLength,
};
}
} }
class UserWithClientsAndKeys { class UserWithClientsAndKeys {

View File

@ -1,8 +1,11 @@
import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:simplecloudnotifier/api/api_client.dart'; import 'package:simplecloudnotifier/api/api_client.dart';
import 'package:simplecloudnotifier/api/api_exception.dart'; import 'package:simplecloudnotifier/api/api_exception.dart';
import 'package:simplecloudnotifier/models/client.dart'; import 'package:simplecloudnotifier/models/client.dart';
import 'package:simplecloudnotifier/models/user.dart'; import 'package:simplecloudnotifier/models/user.dart';
import 'package:simplecloudnotifier/state/application_log.dart';
import 'package:simplecloudnotifier/state/globals.dart'; import 'package:simplecloudnotifier/state/globals.dart';
import 'package:simplecloudnotifier/state/token_source.dart'; import 'package:simplecloudnotifier/state/token_source.dart';
@ -12,9 +15,9 @@ class AppAuth extends ChangeNotifier implements TokenSource {
String? _tokenAdmin; String? _tokenAdmin;
String? _tokenSend; String? _tokenSend;
User? _user; (User, DateTime)? _user;
Client? _client;
DateTime? _clientQueryTime; (Client, DateTime)? _client;
String? get userID => _userID; String? get userID => _userID;
String? get tokenAdmin => _tokenAdmin; String? get tokenAdmin => _tokenAdmin;
@ -35,17 +38,21 @@ class AppAuth extends ChangeNotifier implements TokenSource {
} }
void set(User user, Client client, String tokenAdmin, String tokenSend) { void set(User user, Client client, String tokenAdmin, String tokenSend) {
_client = client; _client = (client, DateTime.now());
_user = user;
_user = (user, DateTime.now());
_userID = user.userID; _userID = user.userID;
_clientID = client.clientID; _clientID = client.clientID;
_tokenAdmin = tokenAdmin; _tokenAdmin = tokenAdmin;
_tokenSend = tokenSend; _tokenSend = tokenSend;
notifyListeners(); notifyListeners();
} }
void setClientAndClientID(Client client) { void setClientAndClientID(Client client) {
_client = client; _client = (client, DateTime.now());
_clientID = client.clientID; _clientID = client.clientID;
notifyListeners(); notifyListeners();
} }
@ -83,6 +90,33 @@ class AppAuth extends ChangeNotifier implements TokenSource {
_client = null; _client = null;
_user = null; _user = null;
final userjson = Globals().sharedPrefs.getString('auth.user.obj');
final userqdate = Globals().sharedPrefs.getString('auth.user.qdate');
final clientjson = Globals().sharedPrefs.getString('auth.client.obj');
final clientqdate = Globals().sharedPrefs.getString('auth.client.qdate');
if (userjson != null && userqdate != null) {
try {
final ts = DateTime.parse(userqdate);
final obj = User.fromJson(jsonDecode(userjson) as Map<String, dynamic>);
_user = (obj, ts);
} catch (exc, trace) {
ApplicationLog.error('failed to parse user object from shared-prefs (auth.user.obj): ' + exc.toString(), additional: 'Data:\n${userjson}\nQDate:\n${userqdate}', trace: trace);
_user = null;
}
}
if (clientjson != null && clientqdate != null) {
try {
final ts = DateTime.parse(clientqdate);
final obj = Client.fromJson(jsonDecode(clientjson) as Map<String, dynamic>);
_client = (obj, ts);
} catch (exc, trace) {
ApplicationLog.error('failed to parse user object from shared-prefs (auth.client.obj): ' + exc.toString(), additional: 'Data:\n${clientjson}\nQDate:\n${clientqdate}', trace: trace);
_client = null;
}
}
notifyListeners(); notifyListeners();
} }
@ -94,6 +128,10 @@ class AppAuth extends ChangeNotifier implements TokenSource {
await Globals().sharedPrefs.remove('auth.tokensend'); await Globals().sharedPrefs.remove('auth.tokensend');
await Globals().sharedPrefs.setString('auth.cdate', ""); await Globals().sharedPrefs.setString('auth.cdate', "");
await Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String()); await Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String());
await Globals().sharedPrefs.remove('auth.user.obj');
await Globals().sharedPrefs.remove('auth.user.qdate');
await Globals().sharedPrefs.remove('auth.client.obj');
await Globals().sharedPrefs.remove('auth.client.qdate');
} else { } else {
await Globals().sharedPrefs.setString('auth.userid', _userID!); await Globals().sharedPrefs.setString('auth.userid', _userID!);
await Globals().sharedPrefs.setString('auth.clientid', _clientID!); await Globals().sharedPrefs.setString('auth.clientid', _clientID!);
@ -101,14 +139,34 @@ class AppAuth extends ChangeNotifier implements TokenSource {
await Globals().sharedPrefs.setString('auth.tokensend', _tokenSend!); await Globals().sharedPrefs.setString('auth.tokensend', _tokenSend!);
if (Globals().sharedPrefs.getString('auth.cdate') == null) await Globals().sharedPrefs.setString('auth.cdate', DateTime.now().toIso8601String()); if (Globals().sharedPrefs.getString('auth.cdate') == null) await Globals().sharedPrefs.setString('auth.cdate', DateTime.now().toIso8601String());
await Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String()); await Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String());
if (_user != null) {
await Globals().sharedPrefs.setString('auth.user.obj', jsonEncode(_user!.$1.toJson()));
await Globals().sharedPrefs.setString('auth.user.qdate', _user!.$2.toIso8601String());
} else {
await Globals().sharedPrefs.remove('auth.user.obj');
await Globals().sharedPrefs.remove('auth.user.qdate');
}
if (_client != null) {
await Globals().sharedPrefs.setString('auth.client.obj', jsonEncode(_client!.$1.toJson()));
await Globals().sharedPrefs.setString('auth.client.qdate', _client!.$2.toIso8601String());
} else {
await Globals().sharedPrefs.remove('auth.client.obj');
await Globals().sharedPrefs.remove('auth.client.qdate');
}
} }
Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String()); Globals().sharedPrefs.setString('auth.mdate', DateTime.now().toIso8601String());
} }
Future<User> loadUser({bool force = false}) async { Future<User> loadUser({bool force = false, Duration? forceIfOlder = null}) async {
if (!force && _user != null && _user!.userID == _userID) { if (forceIfOlder != null && _user != null && _user!.$2.difference(DateTime.now()) > forceIfOlder) {
return _user!; force = true;
}
if (!force && _user != null && _user!.$1.userID == _userID) {
return _user!.$1;
} }
if (_userID == null || _tokenAdmin == null) { if (_userID == null || _tokenAdmin == null) {
@ -117,7 +175,7 @@ class AppAuth extends ChangeNotifier implements TokenSource {
final user = await APIClient.getUser(this, _userID!); final user = await APIClient.getUser(this, _userID!);
_user = user; _user = (user, DateTime.now());
await save(); await save();
@ -125,12 +183,12 @@ class AppAuth extends ChangeNotifier implements TokenSource {
} }
Future<Client?> loadClient({bool force = false, Duration? forceIfOlder = null}) async { Future<Client?> loadClient({bool force = false, Duration? forceIfOlder = null}) async {
if (forceIfOlder != null && _clientQueryTime != null && _clientQueryTime!.difference(DateTime.now()) > forceIfOlder) { if (forceIfOlder != null && _client != null && _client!.$2.difference(DateTime.now()) > forceIfOlder) {
force = true; force = true;
} }
if (!force && _client != null && _client!.clientID == _clientID) { if (!force && _client != null && _client!.$1.clientID == _clientID) {
return _client!; return _client!.$1;
} }
if (_clientID == null || _tokenAdmin == null) { if (_clientID == null || _tokenAdmin == null) {
@ -140,7 +198,7 @@ class AppAuth extends ChangeNotifier implements TokenSource {
try { try {
final client = await APIClient.getClient(this, _clientID!); final client = await APIClient.getClient(this, _clientID!);
_client = client; _client = (client, DateTime.now());
await save(); await save();