I want to upload an image from client to server in gRPC. For this purpose i have created the proto file below:
syntax = "proto3";
service EshopService {
rpc UploadImage (stream ImageToUpload) returns (ImageLink);
}
message ImageToUpload {
bytes image = 1;
}
message ImageLink {
string image_links = 1;
}
in client in order to stream the image i have written the code below:
Future<ImageLink> uploadImage(ImageToUpload image) async {
return await stub.uploadImage(streamImage(images.image));
}
Stream<ImageToUpload> streamImage(List<int> image) async* {
for (var element in image) {
yield ImageToUpload(image: [element]);
}
}
then on server side I have the code below:
Future<ImageLink> uploadImage(grpc.ServiceCall call, Stream<ImageToUpload> request) async {
print('uploading');
final List<int> image = [];
await for (var bytes in request) {
image.addAll(bytes.image);
}
print('image gotten');
File imageFile = File('image.jpg');
await imageFile.writeAsBytes(image);
return ImageLinks(imageLinks: 'image');
}
}
the image is sent to the server and it is being received (I know because I printed it out), but the server never gets out of the await for
section. It gets stuck there even after the stream is complete and on client side I get the following error after a while
gRPC Error (code: 4, codeName: DEADLINE_EXCEEDED, message: Deadline exceeded, details: null, rawResponse: null, trailers: {})
how do I let the server know that the stream is completed so it will get out of the for loop?
I found the issue. It was because I was sending one byte at a time and that took too long, which resulted in a timeout at the client side. It got fixed when I changed it to 128 bytes in each stream. So basically I changed the client side code to this:
Future<ImageLink> uploadImage(XFile image) async {
return await stub.uploadImage(() async* {
final imageBytes = await image.readAsBytes();
int index = 0;
while (index < imageBytes.length) {
int lastIndex = index + 128;
if (lastIndex > imageBytes.length) lastIndex = imageBytes.length;
final data = ImageToUpload(
image: imageBytes.sublist(index, lastIndex),
);
yield data;
index = lastIndex;
}
}.call());
}