Improve signalR protocol compatibility

This commit is contained in:
Nutcake 2023-09-29 13:17:17 +02:00
parent 04ae0687f8
commit f305fcd23c
5 changed files with 58 additions and 105 deletions

View file

@ -7,7 +7,7 @@ import 'package:contacts_plus_plus/models/users/user.dart';
import 'package:contacts_plus_plus/models/users/user_profile.dart'; import 'package:contacts_plus_plus/models/users/user_profile.dart';
import 'package:contacts_plus_plus/models/users/user_status.dart'; import 'package:contacts_plus_plus/models/users/user_status.dart';
class FriendApi { class ContactApi {
static Future<List<Friend>> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async { static Future<List<Friend>> getFriendsList(ApiClient client, {DateTime? lastStatusUpdate}) async {
final response = await client.get("/users/${client.userId}/contacts${lastStatusUpdate != null ? "?lastStatusUpdate=${lastStatusUpdate.toUtc().toIso8601String()}" : ""}"); final response = await client.get("/users/${client.userId}/contacts${lastStatusUpdate != null ? "?lastStatusUpdate=${lastStatusUpdate.toUtc().toIso8601String()}" : ""}");
client.checkResponse(response); client.checkResponse(response);

View file

@ -7,7 +7,7 @@ import 'package:flutter/widgets.dart';
import 'package:hive_flutter/hive_flutter.dart'; import 'package:hive_flutter/hive_flutter.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'package:contacts_plus_plus/apis/friend_api.dart'; import 'package:contacts_plus_plus/apis/contact_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/apis/user_api.dart';
import 'package:contacts_plus_plus/clients/notification_client.dart'; import 'package:contacts_plus_plus/clients/notification_client.dart';
@ -15,16 +15,17 @@ import 'package:contacts_plus_plus/models/users/friend.dart';
import 'package:contacts_plus_plus/clients/api_client.dart'; import 'package:contacts_plus_plus/clients/api_client.dart';
import 'package:contacts_plus_plus/config.dart'; import 'package:contacts_plus_plus/config.dart';
import 'package:contacts_plus_plus/models/message.dart'; import 'package:contacts_plus_plus/models/message.dart';
import 'package:uuid/uuid.dart';
enum EventType { enum EventType {
unknown, undefined,
message, invocation,
unknown1, streamItem,
unknown2, completion,
unknown3, streamInvocation,
unknown4, cancelInvocation,
keepAlive, ping,
error; close;
} }
enum EventTarget { enum EventTarget {
@ -32,7 +33,9 @@ enum EventTarget {
messageSent, messageSent,
receiveMessage, receiveMessage,
messagesRead, messagesRead,
receiveSessionUpdate; receiveSessionUpdate,
removeSession,
receiveStatusUpdate;
factory EventTarget.parse(String? text) { factory EventTarget.parse(String? text) {
if (text == null) return EventTarget.unknown; if (text == null) return EventTarget.unknown;
@ -127,7 +130,7 @@ class MessagingClient extends ChangeNotifier {
_autoRefresh?.cancel(); _autoRefresh?.cancel();
_autoRefresh = Timer(_autoRefreshDuration, () => refreshFriendsList()); _autoRefresh = Timer(_autoRefreshDuration, () => refreshFriendsList());
final friends = await FriendApi.getFriendsList(_apiClient, lastStatusUpdate: lastUpdateUtc); final friends = await ContactApi.getFriendsList(_apiClient, lastStatusUpdate: lastUpdateUtc);
for (final friend in friends) { for (final friend in friends) {
await _updateFriend(friend); await _updateFriend(friend);
} }
@ -136,16 +139,9 @@ class MessagingClient extends ChangeNotifier {
notifyListeners(); notifyListeners();
} }
void sendMessage(Message message) async { void sendMessage(Message message) {
final msgBody = message.toMap(); final msgBody = message.toMap();
final data = { _send("SendMessage", body: msgBody);
"type": EventType.message.index,
"target": "SendMessage",
"arguments": [
msgBody
],
};
_sendData(data);
final cache = getUserMessageCache(message.recipientId) ?? _createUserMessageCache(message.recipientId); final cache = getUserMessageCache(message.recipientId) ?? _createUserMessageCache(message.recipientId);
cache.addMessage(message); cache.addMessage(message);
notifyListeners(); notifyListeners();
@ -153,14 +149,7 @@ class MessagingClient extends ChangeNotifier {
void markMessagesRead(MarkReadBatch batch) { void markMessagesRead(MarkReadBatch batch) {
final msgBody = batch.toMap(); final msgBody = batch.toMap();
final data = { _send("MarkMessagesRead", body: msgBody);
"type": EventType.message.index,
"target": "MarkMessagesRead",
"arguments": [
msgBody
],
};
_sendData(data);
clearUnreadsForUser(batch.senderId); clearUnreadsForUser(batch.senderId);
} }
@ -281,6 +270,7 @@ class MessagingClient extends ChangeNotifier {
_wsChannel!.done.then((error) => _onDisconnected(error)); _wsChannel!.done.then((error) => _onDisconnected(error));
_wsChannel!.listen(_handleEvent, onDone: () => _onDisconnected("Connection closed."), onError: _onDisconnected); _wsChannel!.listen(_handleEvent, onDone: () => _onDisconnected("Connection closed."), onError: _onDisconnected);
_wsChannel!.add(_negotiationPacket); _wsChannel!.add(_negotiationPacket);
_send("InitializeStatus");
} }
Future<WebSocket> _tryConnect() async { Future<WebSocket> _tryConnect() async {
@ -301,34 +291,38 @@ class MessagingClient extends ChangeNotifier {
void _handleEvent(event) { void _handleEvent(event) {
final body = jsonDecode((event.toString().replaceAll(_eofChar, ""))); final body = jsonDecode((event.toString().replaceAll(_eofChar, "")));
final int rawType = body["type"] ?? 0; final int? rawType = body["type"];
if (rawType == null) {
_logger.warning("Received empty event, content was $event");
return;
}
if (rawType > EventType.values.length) { if (rawType > EventType.values.length) {
_logger.info("Unhandled event type $rawType: $body"); _logger.info("Unhandled event type $rawType: $body");
return; return;
} }
switch (EventType.values[rawType]) { switch (EventType.values[rawType]) {
case EventType.unknown1: case EventType.streamItem:
case EventType.unknown2: case EventType.completion:
case EventType.unknown3: case EventType.streamInvocation:
case EventType.unknown4: case EventType.cancelInvocation:
case EventType.unknown: case EventType.undefined:
_logger.info("Received unknown event: $rawType: $body"); _logger.info("Received unhandled event: $rawType: $body");
break; break;
case EventType.message: case EventType.invocation:
_logger.info("Received message-event."); _logger.info("Received invocation-event.");
_handleMessageEvent(body); _handleInvocation(body);
break; break;
case EventType.keepAlive: case EventType.ping:
_logger.info("Received keep-alive."); _logger.info("Received keep-alive.");
break; break;
case EventType.error: case EventType.close:
_logger.severe("Received error-event: ${body["error"]}"); _logger.severe("Received close-event: ${body["error"]}");
// Should we trigger a manual reconnect here or just let the remote service close the connection? // Should we trigger a manual reconnect here or just let the remote service close the connection?
break; break;
} }
} }
void _handleMessageEvent(body) async { void _handleInvocation(body) async {
final target = EventTarget.parse(body["target"]); final target = EventTarget.parse(body["target"]);
final args = body["arguments"]; final args = body["arguments"];
switch (target) { switch (target) {
@ -366,15 +360,31 @@ class MessagingClient extends ChangeNotifier {
} }
notifyListeners(); notifyListeners();
break; break;
case EventTarget.receiveStatusUpdate:
break;
case EventTarget.removeSession:
case EventTarget.receiveSessionUpdate: case EventTarget.receiveSessionUpdate:
// TODO: Handle session updates // TODO: Handle session updates
_logger.info("Received session update"); _logger.info("Received unhandled invocation event.");
break; break;
} }
} }
void _sendData(data) { String _send(String target, {Map? body}) {
final invocationId = const Uuid().v4();
final data = {
"type": EventType.invocation.index,
"invocationId": invocationId,
"target": target,
"arguments": [
if (body != null)
body
],
};
if (_wsChannel == null) throw "Neos Hub is not connected"; if (_wsChannel == null) throw "Neos Hub is not connected";
_wsChannel!.add(jsonEncode(data)+_eofChar); _wsChannel!.add(jsonEncode(data)+_eofChar);
return invocationId;
} }
} }

View file

@ -1,4 +1,4 @@
import 'package:contacts_plus_plus/apis/friend_api.dart'; import 'package:contacts_plus_plus/apis/contact_api.dart';
import 'package:contacts_plus_plus/auxiliary.dart'; import 'package:contacts_plus_plus/auxiliary.dart';
import 'package:contacts_plus_plus/client_holder.dart'; import 'package:contacts_plus_plus/client_holder.dart';
import 'package:contacts_plus_plus/models/users/user.dart'; import 'package:contacts_plus_plus/models/users/user.dart';
@ -55,11 +55,11 @@ class _UserListTileState extends State<UserListTile> {
}); });
try { try {
if (_localAdded) { if (_localAdded) {
await FriendApi.removeUserAsFriend(ClientHolder await ContactApi.removeUserAsFriend(ClientHolder
.of(context) .of(context)
.apiClient, user: widget.user); .apiClient, user: widget.user);
} else { } else {
await FriendApi.addUserAsFriend(ClientHolder await ContactApi.addUserAsFriend(ClientHolder
.of(context) .of(context)
.apiClient, user: widget.user); .apiClient, user: widget.user);
} }

View file

@ -504,14 +504,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.5.0" version: "0.5.0"
message_pack_dart:
dependency: transitive
description:
name: message_pack_dart
sha256: "71b9f0ff60e5896e60b337960bb535380d7dba3297b457ac763ccae807385b59"
url: "https://pub.dev"
source: hosted
version: "2.0.1"
meta: meta:
dependency: transitive dependency: transitive
description: description:
@ -688,14 +680,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.1.4"
pool:
dependency: transitive
description:
name: pool
sha256: "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a"
url: "https://pub.dev"
source: hosted
version: "1.5.1"
process: process:
dependency: transitive dependency: transitive
description: description:
@ -776,22 +760,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.27.7" version: "0.27.7"
shelf:
dependency: transitive
description:
name: shelf
sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4
url: "https://pub.dev"
source: hosted
version: "1.4.1"
signalr_netcore:
dependency: "direct main"
description:
name: signalr_netcore
sha256: "8f84b4b516c03f3a6872f94e9729d1441d5d223a77c81d0a7d7dae5dd0ce1f2f"
url: "https://pub.dev"
source: hosted
version: "1.3.6"
sky_engine: sky_engine:
dependency: transitive dependency: transitive
description: flutter description: flutter
@ -821,22 +789,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.4.5" version: "2.4.5"
sse:
dependency: transitive
description:
name: sse
sha256: "3ff9088cac3f45aa8b91336f1962e3ea6c81baaba0bbba361c05f8aa7fb59442"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
sse_channel:
dependency: transitive
description:
name: sse_channel
sha256: ba2b1382b9423c58fa83e1f01a3a40fbaa16a0594aa984870c88bad0b45d4ca4
url: "https://pub.dev"
source: hosted
version: "0.0.3"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
@ -901,14 +853,6 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.9.2" version: "0.9.2"
tuple:
dependency: transitive
description:
name: tuple
sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151
url: "https://pub.dev"
source: hosted
version: "2.0.2"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:

View file

@ -38,7 +38,6 @@ dependencies:
flutter_secure_storage: ^8.0.0 flutter_secure_storage: ^8.0.0
intl: ^0.18.1 intl: ^0.18.1
path: ^1.8.2 path: ^1.8.2
signalr_netcore: ^1.3.6
logging: ^1.1.1 logging: ^1.1.1
cached_network_image: ^3.2.3 cached_network_image: ^3.2.3
web_socket_channel: ^2.4.0 web_socket_channel: ^2.4.0