Skip to content

Commit 38a1175

Browse files
AchoArnoldCopilot
andcommitted
feat: add GCSAttachmentStorage implementation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ee01c32 commit 38a1175

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package repositories
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
8+
"cloud.google.com/go/storage"
9+
"github.com/NdoleStudio/httpsms/pkg/telemetry"
10+
"github.com/palantir/stacktrace"
11+
)
12+
13+
// GCSAttachmentStorage stores attachments in Google Cloud Storage
14+
type GCSAttachmentStorage struct {
15+
logger telemetry.Logger
16+
tracer telemetry.Tracer
17+
client *storage.Client
18+
bucket string
19+
}
20+
21+
// NewGCSAttachmentStorage creates a new GCSAttachmentStorage
22+
func NewGCSAttachmentStorage(
23+
logger telemetry.Logger,
24+
tracer telemetry.Tracer,
25+
client *storage.Client,
26+
bucket string,
27+
) *GCSAttachmentStorage {
28+
return &GCSAttachmentStorage{
29+
logger: logger.WithService(fmt.Sprintf("%T", &GCSAttachmentStorage{})),
30+
tracer: tracer,
31+
client: client,
32+
bucket: bucket,
33+
}
34+
}
35+
36+
// Upload stores attachment data at the given path in GCS
37+
func (s *GCSAttachmentStorage) Upload(ctx context.Context, path string, data []byte) error {
38+
ctx, span := s.tracer.Start(ctx)
39+
defer span.End()
40+
41+
writer := s.client.Bucket(s.bucket).Object(path).NewWriter(ctx)
42+
if _, err := writer.Write(data); err != nil {
43+
return s.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot write attachment to GCS path [%s]", path)))
44+
}
45+
46+
if err := writer.Close(); err != nil {
47+
return s.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot close GCS writer for path [%s]", path)))
48+
}
49+
50+
s.logger.Info(fmt.Sprintf("uploaded attachment to GCS path [%s/%s] with size [%d]", s.bucket, path, len(data)))
51+
return nil
52+
}
53+
54+
// Download retrieves attachment data from the given path in GCS
55+
func (s *GCSAttachmentStorage) Download(ctx context.Context, path string) ([]byte, error) {
56+
ctx, span := s.tracer.Start(ctx)
57+
defer span.End()
58+
59+
reader, err := s.client.Bucket(s.bucket).Object(path).NewReader(ctx)
60+
if err != nil {
61+
return nil, s.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot open GCS reader for path [%s]", path)))
62+
}
63+
defer reader.Close()
64+
65+
data, err := io.ReadAll(reader)
66+
if err != nil {
67+
return nil, s.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot read attachment from GCS path [%s]", path)))
68+
}
69+
70+
return data, nil
71+
}
72+
73+
// Delete removes an attachment at the given path in GCS
74+
func (s *GCSAttachmentStorage) Delete(ctx context.Context, path string) error {
75+
ctx, span := s.tracer.Start(ctx)
76+
defer span.End()
77+
78+
if err := s.client.Bucket(s.bucket).Object(path).Delete(ctx); err != nil {
79+
return s.tracer.WrapErrorSpan(span, stacktrace.Propagate(err, fmt.Sprintf("cannot delete GCS object at path [%s]", path)))
80+
}
81+
82+
s.logger.Info(fmt.Sprintf("deleted attachment from GCS path [%s/%s]", s.bucket, path))
83+
return nil
84+
}

0 commit comments

Comments
 (0)