diff --git a/pkg/crud/get.go b/pkg/crud/get.go index f5932eaf..3578718c 100644 --- a/pkg/crud/get.go +++ b/pkg/crud/get.go @@ -109,12 +109,12 @@ func (a App) handleDir(w http.ResponseWriter, r *http.Request, request provider. } if query.GetBool(r, "geojson") { - a.serveGeoJSON(w, r, request, items) + a.serveGeoJSON(w, r, request, item, items) return renderer.Page{}, nil } if query.GetBool(r, "thumbnail") { - a.thumbnailApp.List(w, r, items) + a.thumbnailApp.List(w, r, request, item, items) return renderer.Page{}, nil } @@ -172,13 +172,24 @@ func (a App) listFiles(r *http.Request, request provider.Request, item absto.Ite return items, err } -func (a App) serveGeoJSON(w http.ResponseWriter, r *http.Request, request provider.Request, items []absto.Item) { +func (a App) serveGeoJSON(w http.ResponseWriter, r *http.Request, request provider.Request, item absto.Item, items []absto.Item) { if len(items) == 0 { w.WriteHeader(http.StatusNoContent) return } - etag, ok := provider.EtagMatch(w, r, a.exifHash(r.Context(), items)) + ctx := r.Context() + + var hash string + if query.GetBool(r, "search") { + hash = a.exifHash(ctx, items) + } else if exifs, err := a.exifApp.ListDir(ctx, item); err != nil { + logger.WithField("item", item.Pathname).Error("unable to list exifs: %s", err) + } else { + hash = sha.New(exifs) + } + + etag, ok := provider.EtagMatch(w, r, hash) if ok { return } diff --git a/pkg/crud/get_test.go b/pkg/crud/get_test.go index be7ac30b..6e0a5823 100644 --- a/pkg/crud/get_test.go +++ b/pkg/crud/get_test.go @@ -14,30 +14,6 @@ import ( ) func BenchmarkServeGeoJSON(b *testing.B) { - ctrl := gomock.NewController(b) - defer ctrl.Finish() - - mockExif := mocks.NewExif(ctrl) - - mockExif.EXPECT().GetExifFor(gomock.Any(), gomock.Any()).Return(exas.Exif{ - Geocode: exas.Geocode{ - Latitude: 1.0, - Longitude: 1.0, - }, - Date: time.Date(2022, 0o2, 22, 22, 0o2, 22, 0, time.UTC), - }, nil).AnyTimes() - - mockeStorage := mocks.NewStorage(ctrl) - - mockeStorage.EXPECT().Info(gomock.Any(), gomock.Any()).Return(absto.Item{}, nil).AnyTimes() - - instance := App{ - exifApp: mockExif, - storageApp: mockeStorage, - } - - r := httptest.NewRequest(http.MethodGet, "/", nil) - request := provider.Request{} items := []absto.Item{ { ID: "1234", @@ -62,7 +38,36 @@ func BenchmarkServeGeoJSON(b *testing.B) { }, } + ctrl := gomock.NewController(b) + defer ctrl.Finish() + + mockExif := mocks.NewExif(ctrl) + + mockExif.EXPECT().GetExifFor(gomock.Any(), gomock.Any()).Return(exas.Exif{ + Geocode: exas.Geocode{ + Latitude: 1.0, + Longitude: 1.0, + }, + Date: time.Date(2022, 0o2, 22, 22, 0o2, 22, 0, time.UTC), + }, nil).AnyTimes() + + mockExif.EXPECT().ListDir(gomock.Any(), gomock.Any()).Return(items, nil).AnyTimes() + + instance := App{ + exifApp: mockExif, + } + + r := httptest.NewRequest(http.MethodGet, "/", nil) + request := provider.Request{} + item := absto.Item{ + ID: "1234", + Name: "first.jpeg", + Pathname: "/first.jpeg", + Extension: ".jpeg", + IsDir: false, + } + for i := 0; i < b.N; i++ { - instance.serveGeoJSON(httptest.NewRecorder(), r, request, items) + instance.serveGeoJSON(httptest.NewRecorder(), r, request, item, items) } } diff --git a/pkg/mocks/exif.go b/pkg/mocks/exif.go index 5f4328d2..4dd80bc8 100644 --- a/pkg/mocks/exif.go +++ b/pkg/mocks/exif.go @@ -67,6 +67,21 @@ func (mr *ExifMockRecorder) GetExifFor(arg0, arg1 interface{}) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetExifFor", reflect.TypeOf((*Exif)(nil).GetExifFor), arg0, arg1) } +// ListDir mocks base method. +func (m *Exif) ListDir(arg0 context.Context, arg1 model.Item) ([]model.Item, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ListDir", arg0, arg1) + ret0, _ := ret[0].([]model.Item) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ListDir indicates an expected call of ListDir. +func (mr *ExifMockRecorder) ListDir(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListDir", reflect.TypeOf((*Exif)(nil).ListDir), arg0, arg1) +} + // SaveExifFor mocks base method. func (m *Exif) SaveExifFor(arg0 context.Context, arg1 model.Item, arg2 model0.Exif) error { m.ctrl.T.Helper() diff --git a/pkg/provider/interfaces.go b/pkg/provider/interfaces.go index 3c5f4a34..63c6048f 100644 --- a/pkg/provider/interfaces.go +++ b/pkg/provider/interfaces.go @@ -56,6 +56,7 @@ type WebhookManager interface { // ExifManager description //go:generate mockgen -destination ../mocks/exif.go -mock_names ExifManager=Exif -package mocks github.com/ViBiOh/fibr/pkg/provider ExifManager type ExifManager interface { + ListDir(ctx context.Context, item absto.Item) ([]absto.Item, error) GetAggregateFor(ctx context.Context, item absto.Item) (Aggregate, error) GetExifFor(ctx context.Context, item absto.Item) (exas.Exif, error) SaveExifFor(ctx context.Context, item absto.Item, exif exas.Exif) error diff --git a/pkg/thumbnail/thumbnail.go b/pkg/thumbnail/thumbnail.go index b20048a3..7fbc5470 100644 --- a/pkg/thumbnail/thumbnail.go +++ b/pkg/thumbnail/thumbnail.go @@ -19,6 +19,7 @@ import ( "github.com/ViBiOh/httputils/v4/pkg/httperror" "github.com/ViBiOh/httputils/v4/pkg/logger" prom "github.com/ViBiOh/httputils/v4/pkg/prometheus" + "github.com/ViBiOh/httputils/v4/pkg/query" "github.com/ViBiOh/httputils/v4/pkg/request" "github.com/ViBiOh/httputils/v4/pkg/sha" "github.com/prometheus/client_golang/prometheus" @@ -194,16 +195,25 @@ func (a App) Serve(w http.ResponseWriter, r *http.Request, item absto.Item) { http.ServeContent(w, r, path.Base(thumbnailInfo.Pathname), item.Date, reader) } -// List return all thumbnail in a base64 form -func (a App) List(w http.ResponseWriter, r *http.Request, items []absto.Item) { +// List return all thumbnails in a base64 form +func (a App) List(w http.ResponseWriter, r *http.Request, request provider.Request, item absto.Item, items []absto.Item) { if len(items) == 0 { w.WriteHeader(http.StatusNoContent) return } ctx := r.Context() + var hash string - etag, ok := provider.EtagMatch(w, r, a.thumbnailHash(ctx, items)) + if query.GetBool(r, "search") { + hash = a.thumbnailHash(ctx, items) + } else if thumbnails, err := a.ListDir(ctx, item); err != nil { + logger.WithField("item", item.Pathname).Error("unable to list thumbnails: %s", err) + } else { + hash = sha.New(thumbnails) + } + + etag, ok := provider.EtagMatch(w, r, hash) if ok { return }