package objectstore import ( "context" "io" "time" "gitlab.com/gitlab-org/labkit/log" "gocloud.dev/blob" "gocloud.dev/gcerrors" ) type GoCloudObject struct { bucket *blob.Bucket mux *blob.URLMux bucketURL string objectName string *uploader } type GoCloudObjectParams struct { Ctx context.Context Mux *blob.URLMux BucketURL string ObjectName string } func NewGoCloudObject(p *GoCloudObjectParams) (*GoCloudObject, error) { bucket, err := p.Mux.OpenBucket(p.Ctx, p.BucketURL) if err != nil { return nil, err } o := &GoCloudObject{ bucket: bucket, mux: p.Mux, bucketURL: p.BucketURL, objectName: p.ObjectName, } o.uploader = newUploader(o) return o, nil } func (o *GoCloudObject) Upload(ctx context.Context, r io.Reader) error { defer o.bucket.Close() writer, err := o.bucket.NewWriter(ctx, o.objectName, nil) if err != nil { log.ContextLogger(ctx).WithError(err).Error("error creating GoCloud bucket") return err } if _, err = io.Copy(writer, r); err != nil { log.ContextLogger(ctx).WithError(err).Error("error writing to GoCloud bucket") writer.Close() return err } if err := writer.Close(); err != nil { log.ContextLogger(ctx).WithError(err).Error("error closing GoCloud bucket") return err } return nil } func (o *GoCloudObject) ETag() string { return "" } func (o *GoCloudObject) Abort() { o.Delete() } // Delete will always attempt to delete the temporary file. // According to https://github.com/google/go-cloud/blob/7818961b5c9a112f7e092d3a2d8479cbca80d187/blob/azureblob/azureblob.go#L881-L883, // if the writer is closed before any Write is called, Close will create an empty file. func (o *GoCloudObject) Delete() { if o.bucketURL == "" || o.objectName == "" { return } // Note we can't use the request context because in a successful // case, the original request has already completed. deleteCtx, cancel := context.WithTimeout(context.Background(), 60*time.Second) // lint:allow context.Background defer cancel() bucket, err := o.mux.OpenBucket(deleteCtx, o.bucketURL) if err != nil { log.WithError(err).Error("error opening bucket for delete") return } if err := bucket.Delete(deleteCtx, o.objectName); err != nil { if gcerrors.Code(err) != gcerrors.NotFound { log.WithError(err).Error("error deleting object") } } }