Skip to content

Commit 91dab55

Browse files
committed
Added gRPC streaming for large file uploads
1 parent 3f7352c commit 91dab55

File tree

13 files changed

+1424
-1045
lines changed

13 files changed

+1424
-1045
lines changed

.fvmrc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
"flutter": "3.32.8"
2+
"flutter": "3.35.0"
33
}

lib/view_model/app_view_model.dart

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,11 @@ class TaskStream {
2626
}
2727

2828
class AppViewModel with ChangeNotifier {
29-
// Limit reduced from 8MB to 3MB to account for encryption overhead
30-
// and stay under gRPC's 4MB message size limit.
31-
// Currently it is not possible to configure dart's gRPC message size.
32-
// TODO: Verify encryption overhead / JSON encoding overhead to find find optimal buffer.
33-
// Please follow: https://github.com/grpc/grpc-dart/issues/551
34-
static const maxDataSize = 3 * 1024 * 1024; // 3MB
29+
// Be aware of the max gRPC message size limit:
30+
// https://github.com/grpc/grpc-dart/issues/551
31+
32+
// For upload of large files (PDFs, images) use gRPC streaming!
33+
static const maxDataSize = 8 * 1024 * 1024; // 8MB
3534
Device? device;
3635

3736
final List<Task> allTasks = [];

meesign_core/lib/src/data/decrypt_repository.dart

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:drift/drift.dart';
2+
import 'package:fixnum/fixnum.dart';
23
import 'package:meesign_native/meesign_native.dart';
34
import 'package:meesign_network/grpc.dart' as rpc;
45

@@ -34,13 +35,51 @@ class DecryptRepository extends TaskRepository<Decrypt> {
3435
List<int> gid,
3536
) async {
3637
final enc = ElGamalWrapper.encrypt(data, gid);
37-
await _dispatcher.unauth.decrypt(
38-
rpc.DecryptRequest()
39-
..groupId = gid
40-
..name = description
41-
..dataType = dataType.value
42-
..data = enc,
43-
);
38+
39+
// Use streaming for large encrypted data (> 1MB)
40+
if (enc.length > 1024 * 1024) {
41+
await _encryptStreaming(description, dataType, enc, gid);
42+
} else {
43+
// Use regular RPC for small data
44+
await _dispatcher.unauth.decrypt(
45+
rpc.DecryptRequest()
46+
..groupId = gid
47+
..name = description
48+
..dataType = dataType.value
49+
..data = enc,
50+
);
51+
}
52+
}
53+
54+
/// Stream large encrypted data in chunks to avoid gRPC message size limits.
55+
Future<void> _encryptStreaming(
56+
String description,
57+
MimeType dataType,
58+
List<int> encryptedData,
59+
List<int> gid,
60+
) async {
61+
const chunkSize = 256 * 1024; // 256KB chunks
62+
63+
Stream<rpc.DecryptRequestChunk> chunks() async* {
64+
// First chunk: metadata
65+
yield rpc.DecryptRequestChunk()
66+
..metadata = (rpc.DecryptMetadata()
67+
..name = description
68+
..groupId = gid
69+
..dataType = dataType.value
70+
..totalSize = Int64(encryptedData.length));
71+
72+
// Subsequent chunks: data
73+
for (var i = 0; i < encryptedData.length; i += chunkSize) {
74+
final end = (i + chunkSize < encryptedData.length)
75+
? i + chunkSize
76+
: encryptedData.length;
77+
78+
yield rpc.DecryptRequestChunk()..chunk = encryptedData.sublist(i, end);
79+
}
80+
}
81+
82+
await _dispatcher.unauth.decryptStream(chunks());
4483
}
4584

4685
@override

meesign_core/lib/src/data/file_repository.dart

Lines changed: 40 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:drift/drift.dart';
2+
import 'package:fixnum/fixnum.dart';
23
import 'package:meesign_core/src/model/group.dart';
34
import 'package:meesign_native/meesign_native.dart';
45
import 'package:meesign_network/grpc.dart' as rpc;
@@ -33,12 +34,45 @@ class FileRepository extends TaskRepository<File> {
3334
) : super(rpc.TaskType.SIGN_PDF, taskSource, _taskDao);
3435

3536
Future<void> sign(String name, List<int> data, List<int> gid) async {
36-
await _dispatcher.unauth.sign(
37-
rpc.SignRequest()
38-
..groupId = gid
39-
..name = name
40-
..data = data,
41-
);
37+
// Use streaming for large files (> 1MB)
38+
if (data.length > 1024 * 1024) {
39+
await _signStreaming(name, data, gid);
40+
} else {
41+
// Use regular RPC for small files
42+
await _dispatcher.unauth.sign(
43+
rpc.SignRequest()
44+
..groupId = gid
45+
..name = name
46+
..data = data,
47+
);
48+
}
49+
}
50+
51+
/// Stream large PDF files in chunks to avoid gRPC message size limits.
52+
Future<void> _signStreaming(
53+
String name,
54+
List<int> data,
55+
List<int> gid,
56+
) async {
57+
const chunkSize = 256 * 1024; // 256KB chunks
58+
59+
Stream<rpc.SignRequestChunk> chunks() async* {
60+
// First chunk: metadata
61+
yield rpc.SignRequestChunk()
62+
..metadata = (rpc.SignMetadata()
63+
..name = name
64+
..groupId = gid
65+
..totalSize = Int64(data.length));
66+
67+
// Subsequent chunks: data
68+
for (var i = 0; i < data.length; i += chunkSize) {
69+
final end = (i + chunkSize < data.length) ? i + chunkSize : data.length;
70+
71+
yield rpc.SignRequestChunk()..chunk = data.sublist(i, end);
72+
}
73+
}
74+
75+
await _dispatcher.unauth.signStream(chunks());
4276
}
4377

4478
@override

meesign_core/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ dependencies:
1111
collection: ^1.16.0
1212
convert: ^3.1.1
1313
drift: ^2.26.1
14+
fixnum: ^1.0.1
1415
freezed_annotation: ^3.1.0
1516
meesign_native: {path: ../meesign_native}
1617
meesign_network: {path: ../meesign_network}

0 commit comments

Comments
 (0)