diff --git a/mobile/lib/services/messages_service.dart b/mobile/lib/services/messages_service.dart new file mode 100644 index 0000000..cf331f2 --- /dev/null +++ b/mobile/lib/services/messages_service.dart @@ -0,0 +1,175 @@ +import 'dart:convert'; +import 'dart:io'; + +import 'package:http/http.dart' as http; +import 'package:sqflite/sqflite.dart'; +import 'package:uuid/uuid.dart'; + +import '/database/models/messages.dart'; +import '/database/models/image_message.dart'; +import '/database/models/text_messages.dart'; +import '/database/models/conversation_users.dart'; +import '/database/models/conversations.dart'; +import '/database/models/my_profile.dart'; +import '/utils/storage/database.dart'; +import '/utils/storage/session_cookie.dart'; +import '/utils/storage/write_file.dart'; + + +class MessagesService { + static Future sendMessage(Conversation conversation, { + String? data, + List files = const [] + }) async { + + MyProfile profile = await MyProfile.getProfile(); + + var uuid = const Uuid(); + + ConversationUser currentUser = await getConversationUser(conversation, profile.id); + + List messages = []; + List> messagesToSend = []; + + final db = await getDatabaseConnection(); + + if (data != null) { + TextMessage message = TextMessage( + id: uuid.v4(), + symmetricKey: '', + userSymmetricKey: '', + senderId: currentUser.userId, + senderUsername: profile.username, + associationKey: currentUser.associationKey, + createdAt: DateTime.now().toIso8601String(), + failedToSend: false, + text: data, + ); + + messages.add(message); + messagesToSend.add(await message.payloadJson( + conversation, + )); + + await db.insert( + 'messages', + message.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + + for (File file in files) { + + String messageId = uuid.v4(); + + File writtenFile = await writeImage( + messageId, + file.readAsBytesSync(), + ); + + ImageMessage message = ImageMessage( + id: messageId, + symmetricKey: '', + userSymmetricKey: '', + senderId: currentUser.userId, + senderUsername: profile.username, + associationKey: currentUser.associationKey, + createdAt: DateTime.now().toIso8601String(), + failedToSend: false, + file: writtenFile, + ); + + messages.add(message); + messagesToSend.add(await message.payloadJson( + conversation, + )); + + await db.insert( + 'messages', + message.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + + String sessionCookie = await getSessionCookie(); + + return http.post( + await MyProfile.getServerUrl('api/v1/auth/message'), + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'cookie': sessionCookie, + }, + body: jsonEncode(messagesToSend), + ) + .then((resp) { + if (resp.statusCode != 204) { + throw Exception('Unable to send message'); + } + }) + .catchError((exception) { + for (Message message in messages) { + message.failedToSend = true; + db.update( + 'messages', + message.toMap(), + where: 'id = ?', + whereArgs: [message.id], + ); + } + throw exception; + }); + } + + static Future updateMessageThread(Conversation conversation, {MyProfile? profile}) async { + profile ??= await MyProfile.getProfile(); + ConversationUser currentUser = await getConversationUser(conversation, profile.id); + + var resp = await http.get( + await MyProfile.getServerUrl('api/v1/auth/messages/${currentUser.associationKey}'), + headers: { + 'cookie': await getSessionCookie(), + } + ); + + if (resp.statusCode != 200) { + throw Exception(resp.body); + } + + List messageThreadJson = jsonDecode(resp.body); + + final db = await getDatabaseConnection(); + + for (var i = 0; i < messageThreadJson.length; i++) { + var messageJson = messageThreadJson[i] as Map; + + var message = messageJson['message_data']['attachment_id'] != null ? + await ImageMessage.fromJson( + messageJson, + profile.privateKey!, + ) : + TextMessage.fromJson( + messageJson, + profile.privateKey!, + ); + + ConversationUser messageUser = await getConversationUser(conversation, message.senderId); + message.senderUsername = messageUser.username; + + await db.insert( + 'messages', + message.toMap(), + conflictAlgorithm: ConflictAlgorithm.replace, + ); + } + } + + static Future updateMessageThreads({List? conversations}) async { + MyProfile profile = await MyProfile.getProfile(); + + conversations ??= await getConversations(); + + for (var i = 0; i < conversations.length; i++) { + await updateMessageThread(conversations[i], profile: profile); + } + } +} diff --git a/mobile/lib/utils/storage/messages.dart b/mobile/lib/utils/storage/messages.dart deleted file mode 100644 index 4372fa3..0000000 --- a/mobile/lib/utils/storage/messages.dart +++ /dev/null @@ -1,176 +0,0 @@ -import 'dart:convert'; -import 'dart:io'; - -import 'package:Envelope/utils/storage/write_file.dart'; -import 'package:http/http.dart' as http; -import 'package:sqflite/sqflite.dart'; -import 'package:uuid/uuid.dart'; - -import '/database/models/messages.dart'; -import '/database/models/image_message.dart'; -import '/database/models/text_messages.dart'; -import '/database/models/conversation_users.dart'; -import '/database/models/conversations.dart'; -import '/database/models/my_profile.dart'; -import '/utils/storage/database.dart'; -import '/utils/storage/session_cookie.dart'; - -Future sendMessage(Conversation conversation, { - String? data, - List files = const [] -}) async { - - MyProfile profile = await MyProfile.getProfile(); - - var uuid = const Uuid(); - - ConversationUser currentUser = await getConversationUser(conversation, profile.id); - - List messages = []; - List> messagesToSend = []; - - final db = await getDatabaseConnection(); - - if (data != null) { - TextMessage message = TextMessage( - id: uuid.v4(), - symmetricKey: '', - userSymmetricKey: '', - senderId: currentUser.userId, - senderUsername: profile.username, - associationKey: currentUser.associationKey, - createdAt: DateTime.now().toIso8601String(), - failedToSend: false, - text: data, - ); - - messages.add(message); - messagesToSend.add(await message.payloadJson( - conversation, - )); - - await db.insert( - 'messages', - message.toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - } - - for (File file in files) { - - String messageId = uuid.v4(); - - File writtenFile = await writeImage( - messageId, - file.readAsBytesSync(), - ); - - ImageMessage message = ImageMessage( - id: messageId, - symmetricKey: '', - userSymmetricKey: '', - senderId: currentUser.userId, - senderUsername: profile.username, - associationKey: currentUser.associationKey, - createdAt: DateTime.now().toIso8601String(), - failedToSend: false, - file: writtenFile, - ); - - messages.add(message); - messagesToSend.add(await message.payloadJson( - conversation, - )); - - await db.insert( - 'messages', - message.toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - } - - String sessionCookie = await getSessionCookie(); - - return http.post( - await MyProfile.getServerUrl('api/v1/auth/message'), - headers: { - 'Content-Type': 'application/json; charset=UTF-8', - 'cookie': sessionCookie, - }, - body: jsonEncode(messagesToSend), - ) - .then((resp) { - if (resp.statusCode != 204) { - throw Exception('Unable to send message'); - } - }) - .catchError((exception) { - for (Message message in messages) { - message.failedToSend = true; - db.update( - 'messages', - message.toMap(), - where: 'id = ?', - whereArgs: [message.id], - ); - } - throw exception; - }); -} - -Future updateMessageThread(Conversation conversation, {MyProfile? profile}) async { - profile ??= await MyProfile.getProfile(); - ConversationUser currentUser = await getConversationUser(conversation, profile.id); - - var resp = await http.get( - await MyProfile.getServerUrl('api/v1/auth/messages/${currentUser.associationKey}'), - headers: { - 'cookie': await getSessionCookie(), - } - ); - - if (resp.statusCode != 200) { - throw Exception(resp.body); - } - - List messageThreadJson = jsonDecode(resp.body); - - final db = await getDatabaseConnection(); - - for (var i = 0; i < messageThreadJson.length; i++) { - var messageJson = messageThreadJson[i] as Map; - - var message = messageJson['message_data']['attachment_id'] != null ? - await ImageMessage.fromJson( - messageJson, - profile.privateKey!, - ) : - TextMessage.fromJson( - messageJson, - profile.privateKey!, - ); - - ConversationUser messageUser = await getConversationUser(conversation, message.senderId); - message.senderUsername = messageUser.username; - - await db.insert( - 'messages', - message.toMap(), - conflictAlgorithm: ConflictAlgorithm.replace, - ); - } -} - -Future updateMessageThreads({List? conversations}) async { - // try { - MyProfile profile = await MyProfile.getProfile(); - - conversations ??= await getConversations(); - - for (var i = 0; i < conversations.length; i++) { - await updateMessageThread(conversations[i], profile: profile); - } - // } catch(SocketException) { - // return; - // } -} diff --git a/mobile/lib/views/main/conversation/detail.dart b/mobile/lib/views/main/conversation/detail.dart index 7f1dd30..3fa1ec0 100644 --- a/mobile/lib/views/main/conversation/detail.dart +++ b/mobile/lib/views/main/conversation/detail.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:Envelope/services/messages_service.dart'; import 'package:Envelope/views/main/conversation/message.dart'; import 'package:flutter/material.dart'; import 'package:image_picker/image_picker.dart'; @@ -9,7 +10,6 @@ import '/components/file_picker.dart'; import '/database/models/conversations.dart'; import '/database/models/messages.dart'; import '/database/models/my_profile.dart'; -import '/utils/storage/messages.dart'; import '/views/main/conversation/settings.dart'; class ConversationDetail extends StatefulWidget{ @@ -258,7 +258,7 @@ class _ConversationDetailState extends State { if ((msgController.text == '' && selectedImages.isEmpty) || sendDisabled) { return; } - await sendMessage( + await MessagesService.sendMessage( widget.conversation, data: msgController.text != '' ? msgController.text : null, files: selectedImages, diff --git a/mobile/lib/views/main/home.dart b/mobile/lib/views/main/home.dart index 2b8a2b3..857b859 100644 --- a/mobile/lib/views/main/home.dart +++ b/mobile/lib/views/main/home.dart @@ -6,7 +6,7 @@ import '/database/models/friends.dart'; import '/database/models/my_profile.dart'; import '/services/conversations_service.dart'; import '/services/friends_service.dart'; -import '/utils/storage/messages.dart'; +import '/services/messages_service.dart'; import '/utils/storage/session_cookie.dart'; import '/views/main/conversation/list.dart'; import '/views/main/friend/list.dart'; @@ -155,7 +155,7 @@ class _HomeState extends State { await FriendsService.updateFriends(); await ConversationsService.updateConversations(); - await updateMessageThreads(); + await MessagesService.updateMessageThreads(); conversations = await getConversations(); friends = await getFriends(accepted: true);