-
Notifications
You must be signed in to change notification settings - Fork 271
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Streaming issue on web only #717
Comments
There are two different protocols,
Yes,
I am no expert, but I would probably try using multiple unary requests. |
I am facing exactly the same problem. I was not sure if it was my code, as it works fine on native platforms, except on the web. |
@OppositeDragon streaming server to client should sorta work, with some caveats (e.g. it buffers the whole stream in memory - so I would not recommend using it for any sort of long running streams - we should really migrate our implementation to |
@OppositeDragon I implemented it as a a fallback with unary connection. For my use case it's okay, as I expect most users to use native apps and use web as a fallback. import 'package:<my package>/pb/upload.pb.dart' as grpcu;
const chunkSize = 4096;
Future<String> uploadFile(Uint8List data, String fileName) {
if (kIsWeb) {
return uploadFileFuckingWebFallback(data, fileName);
}
final metadata =
grpcu.UploadRequest_Metadata(size: data.length, fileName: fileName);
var stream = uploadChunks(data, metadata: metadata);
return client.uploadFile(stream).then((r) => r.url);
}
Future<String> uploadFileFuckingWebFallback(
Uint8List bytes, String fileName) {
final request = grpcu.UploadSingleRequest(
data: bytes,
size: bytes.length,
fileName: fileName,
);
return client
.uploadFileFuckingWebFallback(request)
.then((r) => r.url);
}
Stream<grpcu.UploadRequest> uploadChunks(List<int> bytes,
{required grpcu.UploadRequest_Metadata metadata}) async* {
yield grpcu.UploadRequest(metadata: metadata);
if (bytes.isEmpty) {
return;
}
for (var i = 0; i < bytes.length; i += chunkSize) {
int potentialEnd = i + chunkSize;
int end;
if (potentialEnd < bytes.length) {
end = potentialEnd;
} else {
end = bytes.length;
}
final chunk = bytes.sublist(i, end);
yield grpcu.UploadRequest(chunk: chunk);
}
} proto: syntax = "proto3";
option go_package = "server/pb";
package main;
service MyService {
rpc UploadFile(stream UploadRequest) returns (UploadResponse) {}
rpc UploadFileFuckingWebFallback(UploadSingleRequest) returns (UploadResponse) {}
}
message UploadRequest{
message Metadata {
int32 size = 1;
string file_name = 2;
optional string ext = 3;
optional int32 width = 4;
optional int32 height = 5;
}
oneof data {
bytes chunk = 1;
Metadata metadata = 2;
}
}
// used for fucking web fallback unary request
message UploadSingleRequest{
bytes data = 1;
int32 size = 2;
string file_name = 3;
optional string ext = 4;
optional int32 width = 5;
optional int32 height = 6;
}
message UploadResponse{
string url = 1;
} and then on the server side, obviously, two different endpoints: // UploadFile handles streamed file upload from normal frontend apps.
func (s *MyService) UploadFile(stream pb.MyService_UploadFileServer) error {
recv := func() (*pb.UploadRequest, error) {
return stream.Recv()
}
url, err := handleUploadStream(s.DB, recv, stream.Context())
if err != nil {
return er("upload file", err)
}
return stream.SendAndClose(&pb.UploadResponse{
Url: url,
})
}
// UploadFileFuckingWebFallback uploads file as a single request (as a fallback for frontends that use typesetting
// engine from 80s and call it modern UI framework or, as it widely known, a fucking web)
func (s *MyService) UploadFileFuckingWebFallback(ctx context.Context, req *pb.UploadSingleRequest) (*pb.UploadResponse, error) {
url, err := s.DB.SaveFile(ctx, req.Data, req.FileName, req.Size, nil)
if err != nil {
return nil, fmt.Errorf("saving file: %w", err)
}
return &pb.UploadResponse{
Url: url,
}, nil
} |
Hi, I'm having an issue with streaming only when compiled to the web platform. It's the simple file upload chunking code that works fine on native platforms:
upload.dart
proto file:
But on web it returns this for every chunk:
Seems like after the initial metadata, the sending connection is closed/cancelled, and subsequent chunks sends are resulting in this error. I can't, however, see any errors neither on server nor on client (using logging with interceptors).
Meanwhile, as I understood, grpc-dart is using grpc-web under the hood, and on the
grpc-web
README page, there is a paragraph:Server-side Streaming RPCs (example) (NOTE: Only when grpcwebtext mode is used.)
Client-side and Bi-directional streaming is not currently supported (see streaming roadmap).
It leads to this document: https://github.com/grpc/grpc-web/blob/master/doc/streaming-roadmap.md, which is basically saying, "forget about streaming support from the client".
So, I have two questions:
The text was updated successfully, but these errors were encountered: