diff --git a/lib/helpers/likes_helper.dart b/lib/helpers/likes_helper.dart index f1d5cae..c319660 100644 --- a/lib/helpers/likes_helper.dart +++ b/lib/helpers/likes_helper.dart @@ -1,5 +1,5 @@ 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'; /// Likes helper @@ -15,21 +15,15 @@ const LikesAPIMap = { class LikesHelper { /// Update liking status of an element - Future setLiking({ + Future setLiking({ @required LikesType type, @required bool like, @required int id, }) async { - return (await APIRequest( - uri: "likes/update", - needLogin: true, - args: { - "type": LikesAPIMap[type], - "like": like.toString(), - "id": id.toString(), - }, - ).exec()) - .code == - 200; + return (await ws("likes/update", { + "type": LikesAPIMap[type], + "like": like.toString(), + "id": id.toString(), + })); } } diff --git a/lib/helpers/websocket_helper.dart b/lib/helpers/websocket_helper.dart index 252ee9d..a43a665 100644 --- a/lib/helpers/websocket_helper.dart +++ b/lib/helpers/websocket_helper.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:convert'; import 'package:comunic/helpers/events_helper.dart'; @@ -13,6 +14,10 @@ import 'package:web_socket_channel/web_socket_channel.dart'; class WebSocketHelper { static WebSocketChannel _ws; + static int _counter = 0; + + static final _requests = Map>(); + /// Check out whether we are currently connected to WebSocket or not static bool isConnected() { return _ws != null && _ws.closeCode == null; @@ -57,11 +62,36 @@ class WebSocketHelper { // Notify when the channel is closed onDone: () { print("WS Channel closed"); + + // Clear Futures queue + _requests.clear(); + EventsHelper.emit(WSClosedEvent()); }, ); } + /// Send a new message + /// + /// This method might throw an [Exception] in case of failure + static Future 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 static _processMessage(String msgStr) { try { @@ -70,7 +100,7 @@ class WebSocketHelper { if (!msg.hasId) _processUnattendedMessage(msg); else - throw Exception("Do not know how to process attended message!"); + _respondRequests(msg); } catch (e, stack) { print("WS could not process message: $e"); print(stack); @@ -94,4 +124,25 @@ class WebSocketHelper { 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 ws(String title, dynamic data) => + WebSocketHelper.sendMessage(title, data); diff --git a/lib/models/ws_message.dart b/lib/models/ws_message.dart index a40896b..bc0d0f4 100644 --- a/lib/models/ws_message.dart +++ b/lib/models/ws_message.dart @@ -1,3 +1,5 @@ +import 'dart:convert'; + import 'package:flutter/widgets.dart'; /// WebSocket message @@ -14,12 +16,21 @@ class WsMessage { @required this.title, @required this.data, }) : 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) static WsMessage fromJSON(final Map m) { 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; } diff --git a/lib/ui/widgets/like_widget.dart b/lib/ui/widgets/like_widget.dart index d757689..c08b4ab 100644 --- a/lib/ui/widgets/like_widget.dart +++ b/lib/ui/widgets/like_widget.dart @@ -71,13 +71,16 @@ class _LikeWidgetState extends SafeState { /// Toggle like status void _toggleLike() async { // As like are not really important, we ignore failures - if (await LikesHelper() - .setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id)) { + try { + await LikesHelper() + .setLiking(type: elem.likeType, like: !elem.userLike, id: elem.id); setState(() { elem.userLike = !elem.userLike; elem.likes += elem.userLike ? 1 : -1; }); + } catch (e, stack) { + print("$e\n$stack"); } } }