diff --git a/service/storage/tiff.go b/service/storage/tiff.go index 2169e56..e70b108 100644 --- a/service/storage/tiff.go +++ b/service/storage/tiff.go @@ -22,8 +22,6 @@ import ( cloud "cloud.google.com/go/storage" "connectrpc.com/connect" - "github.com/observerly/iris/pkg/fits" - "github.com/observerly/iris/pkg/image" "github.com/rs/zerolog/log" "golang.org/x/image/tiff" ) @@ -33,69 +31,22 @@ import ( func (s *server) GetFITSAsTIFFHandler(ctx context.Context, req *connect.Request[pb.GetFITSAsGenericHandlerRequest]) (*connect.Response[pb.GetFITSAsGenericHandlerResponse], error) { now := time.Now() - // Assume an image of 2x2 pixels with 16-bit depth, and no offset: - fit := fits.NewFITSImage(2, 0, 0, 65535) - - logger := log.With().Str("owner", req.Msg.Owner).Str("bucket", req.Msg.BucketName).Str("location", req.Msg.Location).Str("rfc3339", now.Format(time.RFC3339)).Logger() - - url := fmt.Sprintf("https://%s/%s", req.Msg.BucketName, req.Msg.Location) - - width := int32(0) - - height := int32(0) - - storage, err := s.App.Storage(ctx) - - if err != nil { - logger.Error().Err(err).Msg("Failed to get storage client") - return nil, connect.NewError(connect.CodeInternal, err) - } + s.Logger = log.With().Str("owner", req.Msg.Owner).Str("bucket", req.Msg.BucketName).Str("location", req.Msg.Location).Str("rfc3339", now.Format(time.RFC3339)).Logger() // Get the bucket from the storage client: - bucket, err := storage.Bucket(req.Msg.BucketName) - - if err != nil { - logger.Error().Err(err).Msg("Failed to get bucket") - return nil, connect.NewError(connect.CodeInternal, err) - } - - // Create a new Firebase Storage client: - client := stores.NewFirebaseStorageClient(storage) - - // Get the buffer from the storage client: - buff, err := client.RetriveBuffer(ctx, req.Msg.BucketName, req.Msg.Location) + bucket, err := s.Storage.Bucket(req.Msg.BucketName) if err != nil { - logger.Error().Err(err).Msg("Failed to get buffer") + s.Logger.Error().Err(err).Msg("Failed to get bucket") return nil, connect.NewError(connect.CodeInternal, err) } - // Read in our exposure data into the image: - err = fit.Read(buff) + // Get the image from the storage client as a 16-bit grayscale image: + img, err := s.getFITSAsGray16Image(ctx, req.Msg.BucketName, req.Msg.Location) if err != nil { - logger.Error().Err(err).Msg("Failed to read exposure data") - return nil, connect.NewError(connect.CodeInternal, err) - } - - // We know the image is 2D, so we can extract the width from the fits image: - width = fit.Header.Naxis1 - - // We know the image is 2D, so we can extract the height from the fits image: - height = fit.Header.Naxis2 - - if fit.Pixels != width*height { - logger.Error().Msg("Failed to read exposure data") - return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to read exposure data as the number of pixels does not match the width and height")) - } - - // [TBI]: Extract the fits.Date to a simple Gray16 image: - // img, err := s.float32ArrayToGray16Image(fit.Data, int(width), int(height)) - img, err := image.NewGray16FromRawFloat32Pixels(fit.Data, int(width)) - - if err != nil { - logger.Error().Err(err).Msg("Failed to convert exposure data to image") - return nil, connect.NewError(connect.CodeInternal, err) + s.Logger.Error().Err(err).Msg("Failed to get image as 16-bit grayscale from FITS") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to get image as 16-bit grayscale from FITS: %w", err)) } // Create a new buffer to store the object data: @@ -105,11 +56,12 @@ func (s *server) GetFITSAsTIFFHandler(ctx context.Context, req *connect.Request[ err = tiff.Encode(tiffb, img, nil) if err != nil { - return nil, fmt.Errorf("failed to encode image to TIFF: %w", err) + s.Logger.Error().Err(err).Msg("Failed to encode image as TIFF") + return nil, connect.NewError(connect.CodeInternal, fmt.Errorf("failed to encode image to TIFF: %w", err)) } if err != nil { - logger.Error().Err(err).Msg("Failed to encode image as TIFF") + s.Logger.Error().Err(err).Msg("Failed to encode image as TIFF") return nil, connect.NewError(connect.CodeInternal, err) } @@ -117,30 +69,30 @@ func (s *server) GetFITSAsTIFFHandler(ctx context.Context, req *connect.Request[ location := strings.Replace(req.Msg.Location, ".fits", ".tiff", 1) // Store the exposure image in Firebase Storage: - err = client.StoreBuffer(ctx, tiffb, req.Msg.BucketName, location, stores.StoreBufferParams{ + err = s.Client.StoreBuffer(ctx, tiffb, req.Msg.BucketName, location, stores.StoreBufferParams{ ContentType: "image/tiff", Owner: req.Msg.Owner, }) if err != nil { - logger.Error().Err(err).Msg("Failed to store buffer") + s.Logger.Error().Err(err).Msg("Failed to store buffer") return nil, connect.NewError(connect.CodeInternal, err) } // Generate a signed URL for the newly created image in Firebase Storage, valid for 1 minutes: - url, err = bucket.SignedURL(location, &cloud.SignedURLOptions{ + url, err := bucket.SignedURL(location, &cloud.SignedURLOptions{ Expires: now.Add(1 * time.Minute), Method: "GET", }) if err != nil { - logger.Error().Err(err).Msg("Failed to generate signed URL") + s.Logger.Error().Err(err).Msg("Failed to generate signed URL") return nil, connect.NewError(connect.CodeInternal, err) } // Delete the newly created image from Firebase Storage after 1 minutes (until the signed URL expires): go func() { - ctx := context.Background() + ctx = context.Background() // Sleep for the duration of the signed URL: time.Sleep(1 * time.Minute) @@ -149,16 +101,18 @@ func (s *server) GetFITSAsTIFFHandler(ctx context.Context, req *connect.Request[ err = bucket.Object(location).Delete(ctx) if err != nil { - logger.Error().Err(err).Msg("Failed to delete object") + s.Logger.Error().Err(err).Msg("Failed to delete object") } }() - logger.Info().Msg("Returning TIFF Download URL") + bounds := img.Bounds() + + s.Logger.Info().Msg("Returning TIFF Download URL") return connect.NewResponse(&pb.GetFITSAsGenericHandlerResponse{ DownloadUrl: url, - Height: height, - Width: width, + Height: int32(bounds.Dy()), + Width: int32(bounds.Dx()), }), nil }