1
0
mirror of https://gitlab.com/comunic/comunicmobile synced 2024-11-22 21:09:21 +00:00

Use WebSocket to update likes

This commit is contained in:
Pierre HUBERT 2020-04-18 15:24:57 +02:00
parent 526f698bf4
commit 469e1e1f92
4 changed files with 76 additions and 17 deletions

View File

@ -1,5 +1,5 @@
import 'package:comunic/enums/likes_type.dart'; import 'package:comunic/enums/likes_type.dart';
import 'package:comunic/models/api_request.dart'; import 'package:comunic/helpers/websocket_helper.dart';
import 'package:meta/meta.dart'; import 'package:meta/meta.dart';
/// Likes helper /// Likes helper
@ -15,21 +15,15 @@ const LikesAPIMap = {
class LikesHelper { class LikesHelper {
/// Update liking status of an element /// Update liking status of an element
Future<bool> setLiking({ Future<void> setLiking({
@required LikesType type, @required LikesType type,
@required bool like, @required bool like,
@required int id, @required int id,
}) async { }) async {
return (await APIRequest( return (await ws("likes/update", {
uri: "likes/update",
needLogin: true,
args: {
"type": LikesAPIMap[type], "type": LikesAPIMap[type],
"like": like.toString(), "like": like.toString(),
"id": id.toString(), "id": id.toString(),
}, }));
).exec())
.code ==
200;
} }
} }

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert'; import 'dart:convert';
import 'package:comunic/helpers/events_helper.dart'; import 'package:comunic/helpers/events_helper.dart';
@ -13,6 +14,10 @@ import 'package:web_socket_channel/web_socket_channel.dart';
class WebSocketHelper { class WebSocketHelper {
static WebSocketChannel _ws; static WebSocketChannel _ws;
static int _counter = 0;
static final _requests = Map<String, Completer<dynamic>>();
/// Check out whether we are currently connected to WebSocket or not /// Check out whether we are currently connected to WebSocket or not
static bool isConnected() { static bool isConnected() {
return _ws != null && _ws.closeCode == null; return _ws != null && _ws.closeCode == null;
@ -57,11 +62,36 @@ class WebSocketHelper {
// Notify when the channel is closed // Notify when the channel is closed
onDone: () { onDone: () {
print("WS Channel closed"); print("WS Channel closed");
// Clear Futures queue
_requests.clear();
EventsHelper.emit(WSClosedEvent()); EventsHelper.emit(WSClosedEvent());
}, },
); );
} }
/// Send a new message
///
/// This method might throw an [Exception] in case of failure
static Future<dynamic> sendMessage(String title, dynamic data) {
if (!isConnected())
throw Exception("WS: Trying to send message but websocket is closed!");
final completer = Completer();
final id = "freq-${_counter++}";
final msg = WsMessage(id: id, title: title, data: data).toJSON();
print("WS Send message: $msg");
_ws.sink.add(msg);
_requests[id] = completer;
return completer.future;
}
/// Process incoming message /// Process incoming message
static _processMessage(String msgStr) { static _processMessage(String msgStr) {
try { try {
@ -70,7 +100,7 @@ class WebSocketHelper {
if (!msg.hasId) if (!msg.hasId)
_processUnattendedMessage(msg); _processUnattendedMessage(msg);
else else
throw Exception("Do not know how to process attended message!"); _respondRequests(msg);
} catch (e, stack) { } catch (e, stack) {
print("WS could not process message: $e"); print("WS could not process message: $e");
print(stack); print(stack);
@ -94,4 +124,25 @@ class WebSocketHelper {
throw Exception("Unknown message type: ${msg.title}"); throw Exception("Unknown message type: ${msg.title}");
} }
} }
/// Process responses to requests
static _respondRequests(WsMessage msg) {
if (!_requests.containsKey(msg.id))
throw Exception(
"Could not find request ${msg.id} in the requests queue!");
final completer = _requests.remove(msg.id);
// Handles errors
if (msg.title != "success") {
completer.completeError(Exception("Could not process request!"));
return;
} }
completer.complete(msg.data);
}
}
/// Helper function
Future<dynamic> ws(String title, dynamic data) =>
WebSocketHelper.sendMessage(title, data);

View File

@ -1,3 +1,5 @@
import 'dart:convert';
import 'package:flutter/widgets.dart'; import 'package:flutter/widgets.dart';
/// WebSocket message /// WebSocket message
@ -14,12 +16,21 @@ class WsMessage {
@required this.title, @required this.title,
@required this.data, @required this.data,
}) : assert(id != null), }) : assert(id != null),
assert(title != null); assert(title != null),
assert(title.length > 0);
/// Construct a message from a JSON document (messages coming from the server) /// Construct a message from a JSON document (messages coming from the server)
static WsMessage fromJSON(final Map<dynamic, dynamic> m) { static WsMessage fromJSON(final Map<dynamic, dynamic> m) {
return WsMessage(id: m["id"], title: m["title"], data: m["data"]); return WsMessage(id: m["id"], title: m["title"], data: m["data"]);
} }
/// Turn a message into a JSON object to send it to the API
String toJSON() =>
jsonEncode({
"id": id,
"title": title,
"data": data,
});
bool get hasId => this.id != null && this.id.isNotEmpty; bool get hasId => this.id != null && this.id.isNotEmpty;
} }

View File

@ -71,13 +71,16 @@ class _LikeWidgetState extends SafeState<LikeWidget> {
/// Toggle like status /// Toggle like status
void _toggleLike() async { void _toggleLike() async {
// As like are not really important, we ignore failures // As like are not really important, we ignore failures
if (await LikesHelper() try {
.setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id)) { await LikesHelper()
.setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id);
setState(() { setState(() {
elem.userLike = !elem.userLike; elem.userLike = !elem.userLike;
elem.likes += elem.userLike ? 1 : -1; elem.likes += elem.userLike ? 1 : -1;
}); });
} catch (e, stack) {
print("$e\n$stack");
} }
} }
} }