diff --git a/apps/drivers/fs.go b/apps/drivers/fs.go index 3f441b8..a721099 100644 --- a/apps/drivers/fs.go +++ b/apps/drivers/fs.go @@ -1,6 +1,7 @@ package drivers import ( + "errors" "io" "io/ioutil" "os" @@ -83,3 +84,8 @@ func (f FSDriver) List(prefix string) ([]string, error) { func (f FSDriver) Delete(key string) error { return os.Remove(path.Join(f.Path, key)) } + +// GetDownloadLink is not implemented in this driver +func (f FSDriver) GetDownloadLink(key string) (string, error) { + return "", errors.New("not implemented") +} diff --git a/apps/drivers/s3.go b/apps/drivers/s3.go index 316479f..f8ad718 100644 --- a/apps/drivers/s3.go +++ b/apps/drivers/s3.go @@ -5,11 +5,14 @@ import ( "context" "fmt" "io/ioutil" + "time" "github.com/minio/minio-go/v7" "github.com/minio/minio-go/v7/pkg/credentials" ) +const s3LinkExpiration = 72 // in hours + // S3Driver provides basic interface for S3 storage compatible with Driver interface type S3Driver struct { // S3 storage related things @@ -155,3 +158,19 @@ func (s S3Driver) Delete(key string) error { return nil } + +// GetDownloadLink returns URL of object with given key. That URL can be used to download the object. +func (s S3Driver) GetDownloadLink(key string) (string, error) { + client, err := s.getMinioClient() + if err != nil { + return "", fmt.Errorf("getting minio client error: %v", err) + } + + expiry := time.Second * s3LinkExpiration * 60 * 60 // 1 day. + presignedURL, err := client.PresignedPutObject(context.Background(), s.Bucket, key, expiry) + if err != nil { + return "", fmt.Errorf("generating presign URL error: %v", err) + } + + return presignedURL.String(), nil +} diff --git a/apps/drivers/types.go b/apps/drivers/types.go index a29bea5..52c5534 100644 --- a/apps/drivers/types.go +++ b/apps/drivers/types.go @@ -19,4 +19,7 @@ type DriverInterface interface { // Delete deletes one object Delete(key string) error + + // GetDownloadLink returns URL of object with given key. That URL can be used to download the object. + GetDownloadLink(key string) (string, error) } diff --git a/apps/snapshots.go b/apps/snapshots.go index 2e52890..1636ca2 100644 --- a/apps/snapshots.go +++ b/apps/snapshots.go @@ -331,6 +331,16 @@ func (s *SnapshotProcessor) GetSnapshot(key string) (Snapshot, error) { return snapshot, nil } +// GetDownloadLink returns an URL for given snapshot +func (s *SnapshotProcessor) GetDownloadLink(key string) (string, error) { + link, err := s.GetDownloadLink(key) + if err != nil { + return link, err + } + + return link, nil +} + // DeleteSnapshot delete's one snapshot func (s *SnapshotProcessor) DeleteSnapshot(key string) error { err := s.Driver.Delete(key) diff --git a/handlers_nats.go b/handlers_nats.go index cb3f3dd..667113f 100644 --- a/handlers_nats.go +++ b/handlers_nats.go @@ -40,32 +40,33 @@ func _messageHandler(m *nats.Msg) error { fmt.Printf("Received a message: %v\n", message) eventHandlerMap := map[string](func(m *nats.Msg, message *RequestMessage) error){ - "list": listEventHandler, - "get": getEventHandler, - "create": createEventHandler, - "register": registerEventHandler, - "update": updateEventHandler, - "delete": deleteEventHandler, - "stop": stopEventHandler, - "start": startEventHandler, - "restart": restartEventHandler, - "update_keys": updateKeysEventHandler, - "set_password": setPasswordEventHandler, - "processes": processesEventHandler, - "enable_tech": enableTechEventHandler, - "rebuild": rebuildEventHandler, - "add_label": addLabelEventHandler, - "remove_label": removeLabelEventHandler, - "list_orphans": listOrphansEventHandler, - "node": getNoteEventHandler, - "create_snapshot": createSnapshotEventHandler, - "restore_from_snapshot": restoreFromSnapshotEventHandler, - "list_snapshots": listSnapshotsEventHandler, - "list_apps_snapshots": listAppsSnapshotsEventHandler, - "list_snapshots_by_label": listSnapshotsByLabelEventHandler, - "get_snapshot": getSnapshotEventHandler, - "delete_snapshot": deleteSnapshotEventHandler, - "delete_app_snapshots": deleteAppSnapshotsEventHandler, + "list": listEventHandler, + "get": getEventHandler, + "create": createEventHandler, + "register": registerEventHandler, + "update": updateEventHandler, + "delete": deleteEventHandler, + "stop": stopEventHandler, + "start": startEventHandler, + "restart": restartEventHandler, + "update_keys": updateKeysEventHandler, + "set_password": setPasswordEventHandler, + "processes": processesEventHandler, + "enable_tech": enableTechEventHandler, + "rebuild": rebuildEventHandler, + "add_label": addLabelEventHandler, + "remove_label": removeLabelEventHandler, + "list_orphans": listOrphansEventHandler, + "node": getNoteEventHandler, + "create_snapshot": createSnapshotEventHandler, + "restore_from_snapshot": restoreFromSnapshotEventHandler, + "list_snapshots": listSnapshotsEventHandler, + "list_apps_snapshots": listAppsSnapshotsEventHandler, + "list_snapshots_by_label": listSnapshotsByLabelEventHandler, + "get_snapshot": getSnapshotEventHandler, + "get_snapshot_download_link": getSnapshotDownloadLinkEventHandler, + "delete_snapshot": deleteSnapshotEventHandler, + "delete_app_snapshots": deleteAppSnapshotsEventHandler, } if eventHandler, ok := eventHandlerMap[message.Type]; ok { @@ -1000,6 +1001,26 @@ func getSnapshotEventHandler(m *nats.Msg, message *RequestMessage) error { return nil } +/* +getSnapshotDownloadLinkEventHandler return URL that can be used to download snapshot + +Payload: string with a snapshot name (key) +Response: string with the URL +*/ +func getSnapshotDownloadLinkEventHandler(m *nats.Msg, message *RequestMessage) error { + link, err := snapshotProcessor.GetDownloadLink(message.Payload) + if err != nil { + return errorReplyFormater(m, "backend error", err) + } + + err = m.Respond([]byte(link)) + if err != nil { + log.Println("ERROR: get snapshot:", err.Error()) + } + + return nil +} + /* deleteSnapshotEventHandler delete a single snapshot. This is not bound to application name.