Search code examples
flutterdartstreaminggrpcgrpc-dart

why is gRPC server side stuck after client is done streaming (client and server both written in dart)?


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?


Solution

  • 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());
      }