func (rpc *grpcService) readFrom(request *pb.ReadRequest, reader io.ReaderAt, stream pb.ByteStream_ReadServer) error { limit := int(request.ReadLimit) if limit < 0 { return grpc.Errorf(codes.InvalidArgument, "Read(): read_limit=%d is invalid", limit) } offset := request.ReadOffset if offset < 0 { return grpc.Errorf(codes.InvalidArgument, "Read(): offset=%d is invalid", offset) } var buf []byte if limit > 0 { buf = make([]byte, limit) } else { buf = make([]byte, 1024*1024) // 1M buffer is reasonable. } bytesSent := 0 for limit == 0 || bytesSent < limit { n, err := reader.ReadAt(buf, offset) if n > 0 { if err := stream.Send(&pb.ReadResponse{Data: buf[:n]}); err != nil { return grpc.Errorf(grpc.Code(err), "Send(resourceName=%q offset=%d): %v", request.ResourceName, offset, grpc.ErrorDesc(err)) } } else if err == nil { return grpc.Errorf(codes.Internal, "nil error on empty read: io.ReaderAt contract violated") } offset += int64(n) bytesSent += n if err == io.EOF { break } if err != nil { return grpc.Errorf(codes.Unknown, "ReadAt(resourceName=%q offset=%d): %v", request.ResourceName, offset, err) } } return nil }
// Read handles a pb.ReadRequest sending bytes to the pb.ByteStream_ReadServer // Implements bytestream.proto "rpc Read(ReadRequest) returns (stream ReadResponse)" func (rpc *grpcService) Read(request *pb.ReadRequest, stream pb.ByteStream_ReadServer) error { if rpc.parent.readHandler == nil { return grpc.Errorf(codes.Unimplemented, "instance of NewServer(readHandler = nil) rejects all reads") } if request == nil { return grpc.Errorf(codes.Internal, "Read(ReadRequest == nil)") } if request.ResourceName == "" { return grpc.Errorf(codes.InvalidArgument, "ReadRequest: empty or missing resource_name") } reader, err := rpc.parent.readHandler.GetReader(stream.Context(), request.ResourceName) if err != nil { return err } if err = rpc.readFrom(request, reader, stream); err != nil { rpc.parent.readHandler.Close(stream.Context(), request.ResourceName) return err } if err = rpc.parent.readHandler.Close(stream.Context(), request.ResourceName); err != nil { return err } return nil }