diff --git a/app/lib/backend/http/api/messages.dart b/app/lib/backend/http/api/messages.dart index 0a8674956..bd602aaf5 100644 --- a/app/lib/backend/http/api/messages.dart +++ b/app/lib/backend/http/api/messages.dart @@ -6,6 +6,7 @@ import 'package:friend_private/backend/http/shared.dart'; import 'package:friend_private/backend/schema/message.dart'; import 'package:friend_private/env/env.dart'; import 'package:friend_private/utils/logger.dart'; +import 'package:friend_private/utils/other/string_utils.dart'; import 'package:http/http.dart' as http; import 'package:instabug_flutter/instabug_flutter.dart'; import 'package:path/path.dart'; @@ -99,10 +100,25 @@ Stream sendMessageStreamServer(String text, {String? appId}) return; } - var messageId = "1000"; // default new message + var buffers = []; + var messageId = "1000"; // Default new message await for (var data in response.transform(utf8.decoder)) { var lines = data.split('\n\n'); for (var line in lines.where((line) => line.isNotEmpty)) { + // Dealing w/ the package spliting by 1024 bytes in dart + // Waiting for the next package + if (line.length >= 1024) { + buffers.add(line); + continue; + } + + // Merge package if needed + if (buffers.isNotEmpty) { + buffers.add(line); + line = buffers.join(); + buffers.clear(); + } + if (line.startsWith('think: ')) { yield ServerMessageChunk(messageId, line.substring(7).replaceAll("__CRLF__", "\n"), MessageChunkType.think); continue; @@ -114,8 +130,7 @@ Stream sendMessageStreamServer(String text, {String? appId}) } if (line.startsWith('done: ')) { - var text = utf8.decode(base64.decode(line.substring(6))); - debugPrint(text); + var text = decodeBase64(line.substring(6)); yield ServerMessageChunk(messageId, text, MessageChunkType.done, message: ServerMessage.fromJson(json.decode(text))); continue; @@ -162,10 +177,25 @@ Stream sendVoiceMessageStreamServer(List files) async* return; } - var messageId = "1000"; // default new message + var buffers = []; + var messageId = "1000"; // Default new message await for (var data in response.stream.transform(utf8.decoder)) { var lines = data.split('\n\n'); for (var line in lines.where((line) => line.isNotEmpty)) { + // Dealing w/ the package spliting by 1024 bytes in dart + // Waiting for the next package + if (line.length >= 1024) { + buffers.add(line); + continue; + } + + // Merge package if needed + if (buffers.isNotEmpty) { + buffers.add(line); + line = buffers.join(); + buffers.clear(); + } + if (line.startsWith('think: ')) { yield ServerMessageChunk(messageId, line.substring(7).replaceAll("__CRLF__", "\n"), MessageChunkType.think); continue; @@ -177,14 +207,14 @@ Stream sendVoiceMessageStreamServer(List files) async* } if (line.startsWith('done: ')) { - var text = utf8.decode(base64.decode(line.substring(6))); + var text = decodeBase64(line.substring(6)); yield ServerMessageChunk(messageId, text, MessageChunkType.done, message: ServerMessage.fromJson(json.decode(text))); continue; } if (line.startsWith('message: ')) { - var text = utf8.decode(base64.decode(line.substring(9))); + var text = decodeBase64(line.substring(9)); yield ServerMessageChunk(messageId, text, MessageChunkType.message, message: ServerMessage.fromJson(json.decode(text))); continue; diff --git a/app/lib/utils/other/string_utils.dart b/app/lib/utils/other/string_utils.dart index 0b9f68c49..7e5697eac 100644 --- a/app/lib/utils/other/string_utils.dart +++ b/app/lib/utils/other/string_utils.dart @@ -1,5 +1,7 @@ // string_utils.dart +import 'dart:convert'; + String extractJson(String input) { int braceCount = 0; int startIndex = -1; @@ -34,12 +36,19 @@ String extractJson(String input) { } String convertToHHMMSS(int seconds) { - int hours = seconds ~/ 3600; - int minutes = (seconds % 3600) ~/ 60; - int remainingSeconds = seconds % 60; + int hours = seconds ~/ 3600; + int minutes = (seconds % 3600) ~/ 60; + int remainingSeconds = seconds % 60; + + String twoDigits(int n) => n.toString().padLeft(2, '0'); - String twoDigits(int n) => n.toString().padLeft(2, '0'); + return '${twoDigits(hours)}:${twoDigits(minutes)}:${twoDigits(remainingSeconds)}'; +} - return '${twoDigits(hours)}:${twoDigits(minutes)}:${twoDigits(remainingSeconds)}'; +String padBase64(String rawBase64) { + return (rawBase64.length % 4 > 0) ? rawBase64 += List.filled(4 - (rawBase64.length % 4), "_").join("") : rawBase64; } +String decodeBase64(String data) { + return utf8.decode(base64.decode(padBase64(data))); +}