1 package storage
2
3 import (
4 "bytes"
5 "context"
6 "errors"
7 "fmt"
8 "hash"
9 "io"
10 )
11
12
13
14 func NewHashWrapper(h hash.Hash, fs FS, gs GetSetter) FS {
15 return &hashWrapper{
16 h: h,
17 fs: fs,
18 gs: gs,
19 }
20 }
21
22 type hashWrapper struct {
23 h hash.Hash
24 fs FS
25 gs GetSetter
26 }
27
28
29
30 type GetSetter interface {
31 Get(key string) (string, error)
32 Set(key string, value string) error
33 Delete(key string) error
34 }
35
36
37 func (hfs *hashWrapper) Open(ctx context.Context, path string, options *ReaderOptions) (*File, error) {
38 v, err := hfs.gs.Get(path)
39 if err != nil {
40 return nil, err
41 }
42
43 return hfs.fs.Open(ctx, v, options)
44 }
45
46
47 func (hfs *hashWrapper) Attributes(ctx context.Context, path string, options *ReaderOptions) (*Attributes, error) {
48 v, err := hfs.gs.Get(path)
49 if err != nil {
50 return nil, err
51 }
52
53 return hfs.fs.Attributes(ctx, v, options)
54 }
55
56
57 func (hfs *hashWrapper) Walk(_ context.Context, _ string, _ WalkFn) error {
58 return errors.New("HashFS.Walk is not implemented")
59 }
60
61 type hashWriteCloser struct {
62 buf *bytes.Buffer
63 path string
64 ctx context.Context
65
66 hfs *hashWrapper
67 options *WriterOptions
68 }
69
70 func (w *hashWriteCloser) Write(b []byte) (int, error) {
71 n, err := w.buf.Write(b)
72 if err != nil {
73 return n, err
74 }
75
76 return w.hfs.h.Write(b)
77 }
78
79 func (w *hashWriteCloser) Close() (err error) {
80 hashPath := fmt.Sprintf("%x", w.hfs.h.Sum(nil))
81 if err := w.hfs.gs.Set(w.path, hashPath); err != nil {
82 return err
83 }
84
85 fsw, err := w.hfs.fs.Create(w.ctx, hashPath, w.options)
86 if err != nil {
87 return err
88 }
89 defer func() {
90 if err1 := fsw.Close(); err == nil {
91 err = err1
92 }
93 }()
94
95 _, err = io.Copy(fsw, w.buf)
96
97 return err
98 }
99
100
101
102
103 func (hfs *hashWrapper) Create(ctx context.Context, path string, options *WriterOptions) (io.WriteCloser, error) {
104 return &hashWriteCloser{
105 buf: &bytes.Buffer{},
106 path: path,
107 ctx: ctx,
108 hfs: hfs,
109 options: options,
110 }, nil
111 }
112
113
114 func (hfs *hashWrapper) Delete(ctx context.Context, path string) error {
115 if err := hfs.fs.Delete(ctx, path); err != nil {
116 return err
117 }
118
119 return hfs.gs.Delete(path)
120 }
121
122 func (hfs *hashWrapper) URL(ctx context.Context, path string, options *SignedURLOptions) (string, error) {
123
124 return hfs.fs.URL(ctx, path, options)
125 }
126
View as plain text