DownloadFile pulls the requested file from the database and sends it over the protobuf stream in chunks.
(request *proto.FileRequest, stream proto.DRPCProvisionerDaemon_DownloadFileStream)
| 1543 | |
| 1544 | // DownloadFile pulls the requested file from the database and sends it over the protobuf stream in chunks. |
| 1545 | func (s *server) DownloadFile(request *proto.FileRequest, stream proto.DRPCProvisionerDaemon_DownloadFileStream) error { |
| 1546 | //nolint:errcheck |
| 1547 | defer stream.CloseSend() |
| 1548 | //nolint:gocritic // Provisionerd is the actor here. |
| 1549 | ctx := dbauthz.AsProvisionerd(stream.Context()) |
| 1550 | |
| 1551 | // A graceful error message will help debugging. |
| 1552 | fail := func(err error) error { |
| 1553 | if sendErr := stream.Send(&sdkproto.FileUpload{ |
| 1554 | Type: &sdkproto.FileUpload_Error{ |
| 1555 | Error: &sdkproto.FailedFile{ |
| 1556 | Error: err.Error(), |
| 1557 | }, |
| 1558 | }, |
| 1559 | }); sendErr != nil { |
| 1560 | s.Logger.Warn(ctx, "failed to send error response on download stream", |
| 1561 | slog.Error(sendErr), |
| 1562 | slog.F("original_error", err.Error()), |
| 1563 | ) |
| 1564 | } |
| 1565 | return err |
| 1566 | } |
| 1567 | if request.FileId == "" || request.FileId == uuid.Nil.String() { |
| 1568 | return fail(xerrors.New("file id is required")) |
| 1569 | } |
| 1570 | |
| 1571 | fid, err := uuid.Parse(request.FileId) |
| 1572 | if err != nil { |
| 1573 | return fail(xerrors.Errorf("invalid file id: %w", err)) |
| 1574 | } |
| 1575 | |
| 1576 | file, err := s.Database.GetFileByID(ctx, fid) |
| 1577 | if err != nil { |
| 1578 | return fail(xerrors.Errorf("get file: %w", err)) |
| 1579 | } |
| 1580 | |
| 1581 | switch request.UploadType { |
| 1582 | case sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES: |
| 1583 | // This check is not perfect. If these conditions are not true, then the file is not a modules file. |
| 1584 | if file.CreatedBy != uuid.Nil || file.Mimetype != tarMimeType { |
| 1585 | return fail(xerrors.Errorf("file %s is not a modules file", fid)) |
| 1586 | } |
| 1587 | default: |
| 1588 | return fail(xerrors.Errorf("unsupported file upload type: %s", request.UploadType)) |
| 1589 | } |
| 1590 | |
| 1591 | upload, chunks, err := sdkproto.BytesToDataUpload(sdkproto.DataUploadType_UPLOAD_TYPE_MODULE_FILES, file.Data) |
| 1592 | if err != nil { |
| 1593 | return fail(xerrors.Errorf("prepare file upload: %w", err)) |
| 1594 | } |
| 1595 | |
| 1596 | err = stream.Send(&sdkproto.FileUpload{ |
| 1597 | Type: &sdkproto.FileUpload_DataUpload{DataUpload: upload}, |
| 1598 | }) |
| 1599 | if err != nil { |
| 1600 | return fail(xerrors.Errorf("send file upload: %w", err)) |
| 1601 | } |
| 1602 |