Implement online-status keep-alive

This commit is contained in:
Nutcake 2023-05-06 18:34:14 +02:00
parent ab21717829
commit 59cd6bc07f
5 changed files with 32 additions and 18 deletions

View file

@ -28,6 +28,11 @@ class UserApi {
final data = jsonDecode(response.body); final data = jsonDecode(response.body);
return UserStatus.fromMap(data); return UserStatus.fromMap(data);
} }
static Future<void> notifyOnlineInstance(ApiClient client) async {
final response = await client.post("/stats/instanceOnline/${client.authenticationData.secretMachineId.hashCode}");
ApiClient.checkResponse(response);
}
static Future<void> setStatus(ApiClient client, {required UserStatus status}) async { static Future<void> setStatus(ApiClient client, {required UserStatus status}) async {
final pkginfo = await PackageInfo.fromPlatform(); final pkginfo = await PackageInfo.fromPlatform();

View file

@ -1,8 +1,5 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:contacts_plus_plus/clients/messaging_client.dart';
import 'package:contacts_plus_plus/clients/notification_client.dart';
import 'package:contacts_plus_plus/clients/settings_client.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_phoenix/flutter_phoenix.dart'; import 'package:flutter_phoenix/flutter_phoenix.dart';

View file

@ -1,9 +1,9 @@
import 'dart:async'; import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'dart:io'; import 'dart:io';
import 'package:collection/collection.dart';
import 'package:contacts_plus_plus/apis/friend_api.dart'; import 'package:contacts_plus_plus/apis/friend_api.dart';
import 'package:contacts_plus_plus/apis/message_api.dart'; import 'package:contacts_plus_plus/apis/message_api.dart';
import 'package:contacts_plus_plus/apis/user_api.dart';
import 'package:contacts_plus_plus/clients/notification_client.dart'; import 'package:contacts_plus_plus/clients/notification_client.dart';
import 'package:contacts_plus_plus/models/authentication_data.dart'; import 'package:contacts_plus_plus/models/authentication_data.dart';
import 'package:contacts_plus_plus/models/friend.dart'; import 'package:contacts_plus_plus/models/friend.dart';
@ -57,6 +57,7 @@ class MessagingClient extends ChangeNotifier {
final Workmanager _workmanager = Workmanager(); final Workmanager _workmanager = Workmanager();
final NotificationClient _notificationClient; final NotificationClient _notificationClient;
Friend? selectedFriend; Friend? selectedFriend;
Timer? _notifyOnlineTimer;
Timer? _autoRefresh; Timer? _autoRefresh;
Timer? _refreshTimeout; Timer? _refreshTimeout;
int _attempts = 0; int _attempts = 0;
@ -66,16 +67,24 @@ class MessagingClient extends ChangeNotifier {
String? get initStatus => _initStatus; String? get initStatus => _initStatus;
bool get websocketConnected => _wsChannel != null;
MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient}) MessagingClient({required ApiClient apiClient, required NotificationClient notificationClient})
: _apiClient = apiClient, _notificationClient = notificationClient { : _apiClient = apiClient, _notificationClient = notificationClient {
refreshFriendsListWithErrorHandler(); refreshFriendsListWithErrorHandler();
start(); startWebsocket();
_notifyOnlineTimer = Timer.periodic(const Duration(seconds: 60), (timer) async {
// We should probably let the MessagingClient handle the entire state of USerStatus instead of mirroring like this
// but I don't feel like implementing that right now.
UserApi.setStatus(apiClient, status: await UserApi.getUserStatus(apiClient, userId: apiClient.userId));
});
} }
@override @override
void dispose() { void dispose() {
_autoRefresh?.cancel(); _autoRefresh?.cancel();
_refreshTimeout?.cancel(); _refreshTimeout?.cancel();
_notifyOnlineTimer?.cancel();
_wsChannel?.close(); _wsChannel?.close();
super.dispose(); super.dispose();
} }
@ -116,16 +125,21 @@ class MessagingClient extends ChangeNotifier {
_friendsCache[friend.id] = friend; _friendsCache[friend.id] = friend;
} }
_sortedFriendsCache.clear(); _sortedFriendsCache.clear();
_sortedFriendsCache.addAll(friends.sorted((a, b) { _sortedFriendsCache.addAll(friends);
_sortFriendsCache();
_initStatus = "";
notifyListeners();
}
void _sortFriendsCache() {
_sortedFriendsCache.sort((a, b) {
var aVal = friendHasUnreads(a) ? -3 : 0; var aVal = friendHasUnreads(a) ? -3 : 0;
var bVal = friendHasUnreads(b) ? -3 : 0; var bVal = friendHasUnreads(b) ? -3 : 0;
aVal -= a.userStatus.lastStatusChange.compareTo(b.userStatus.lastStatusChange); aVal -= a.userStatus.lastStatusChange.compareTo(b.userStatus.lastStatusChange);
aVal += a.userStatus.onlineStatus.compareTo(b.userStatus.onlineStatus) * 2; aVal += a.userStatus.onlineStatus.compareTo(b.userStatus.onlineStatus) * 2;
return aVal.compareTo(bVal); return aVal.compareTo(bVal);
})); });
_initStatus = "";
notifyListeners();
} }
void updateAllUnreads(List<Message> messages) { void updateAllUnreads(List<Message> messages) {
@ -151,6 +165,7 @@ class MessagingClient extends ChangeNotifier {
messages.add(message); messages.add(message);
} }
messages.sort(); messages.sort();
_sortFriendsCache();
_notificationClient.showUnreadMessagesNotification(messages.reversed); _notificationClient.showUnreadMessagesNotification(messages.reversed);
notifyListeners(); notifyListeners();
} }
@ -205,11 +220,12 @@ class MessagingClient extends ChangeNotifier {
} }
void _onDisconnected(error) async { void _onDisconnected(error) async {
_wsChannel = null;
_logger.warning("Neos Hub connection died with error '$error', reconnecting..."); _logger.warning("Neos Hub connection died with error '$error', reconnecting...");
await start(); await startWebsocket();
} }
Future<void> start() async { Future<void> startWebsocket() async {
if (!_apiClient.isAuthenticated) { if (!_apiClient.isAuthenticated) {
_logger.info("Tried to connect to Neos Hub without authentication, this is probably fine for now."); _logger.info("Tried to connect to Neos Hub without authentication, this is probably fine for now.");
return; return;
@ -352,9 +368,4 @@ class MessagingClient extends ChangeNotifier {
}; };
_sendData(data); _sendData(data);
} }
}
class MessagesProvider extends ChangeNotifier {
} }

View file

@ -72,7 +72,9 @@ class _ContactsPlusPlusState extends State<ContactsPlusPlus> {
ChangeNotifierProvider( // This doesn't need to be a proxy provider since the arguments should never change during it's lifetime. ChangeNotifierProvider( // This doesn't need to be a proxy provider since the arguments should never change during it's lifetime.
create: (context) => create: (context) =>
MessagingClient( MessagingClient(
apiClient: clientHolder.apiClient, notificationClient: clientHolder.notificationClient), apiClient: clientHolder.apiClient,
notificationClient: clientHolder.notificationClient,
),
child: const FriendsList(), child: const FriendsList(),
) : ) :
LoginScreen( LoginScreen(

View file

@ -4,7 +4,6 @@ import 'package:contacts_plus_plus/apis/user_api.dart';
import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/client_holder.dart';
import 'package:contacts_plus_plus/clients/messaging_client.dart'; import 'package:contacts_plus_plus/clients/messaging_client.dart';
import 'package:contacts_plus_plus/models/friend.dart'; import 'package:contacts_plus_plus/models/friend.dart';
import 'package:contacts_plus_plus/models/message.dart';
import 'package:contacts_plus_plus/models/personal_profile.dart'; import 'package:contacts_plus_plus/models/personal_profile.dart';
import 'package:contacts_plus_plus/widgets/default_error_widget.dart'; import 'package:contacts_plus_plus/widgets/default_error_widget.dart';
import 'package:contacts_plus_plus/widgets/expanding_input_fab.dart'; import 'package:contacts_plus_plus/widgets/expanding_input_fab.dart';