1 package storage
2
3 import (
4 "context"
5 "io"
6 "time"
7 )
8
9
10
11
12
13
14
15
16
17
18
19
20 func NewTimeoutWrapper(fs FS, read time.Duration, write time.Duration) FS {
21 return &timeoutWrapper{
22 fs: fs,
23 read: read,
24 write: write,
25 }
26 }
27
28 type timeoutWrapper struct {
29 fs FS
30 read time.Duration
31 write time.Duration
32 }
33
34
35
36
37
38 func timeoutCall(ctx context.Context, timeout time.Duration, call func() (interface{}, error)) (interface{}, error) {
39 var out interface{}
40 var err error
41 done := make(chan struct{})
42 go func() {
43 out, err = call()
44 close(done)
45 }()
46
47 select {
48 case <-time.After(timeout):
49 return nil, context.DeadlineExceeded
50 case <-ctx.Done():
51 return nil, ctx.Err()
52 case <-done:
53 return out, err
54 }
55 }
56
57
58 func (t *timeoutWrapper) Open(ctx context.Context, path string, options *ReaderOptions) (*File, error) {
59 out, err := timeoutCall(ctx, t.read, func() (interface{}, error) {
60 return t.fs.Open(ctx, path, options)
61 })
62 if file, ok := out.(*File); ok {
63 return file, err
64 }
65
66 return nil, err
67 }
68
69
70 func (t *timeoutWrapper) Attributes(ctx context.Context, path string, options *ReaderOptions) (*Attributes, error) {
71 out, err := timeoutCall(ctx, t.read, func() (interface{}, error) {
72 return t.fs.Attributes(ctx, path, options)
73 })
74 if attrs, ok := out.(*Attributes); ok {
75 return attrs, err
76 }
77
78 return nil, err
79 }
80
81
82 func (t *timeoutWrapper) Create(ctx context.Context, path string, options *WriterOptions) (io.WriteCloser, error) {
83 out, err := timeoutCall(ctx, t.write, func() (interface{}, error) {
84 return t.fs.Create(ctx, path, options)
85 })
86 if w, ok := out.(io.WriteCloser); ok {
87 return w, err
88 }
89
90 return nil, err
91 }
92
93
94 func (t *timeoutWrapper) Delete(ctx context.Context, path string) error {
95 _, err := timeoutCall(ctx, t.write, func() (interface{}, error) {
96 return nil, t.fs.Delete(ctx, path)
97 })
98
99 return err
100 }
101
102
103 func (t *timeoutWrapper) Walk(ctx context.Context, path string, fn WalkFn) error {
104 return t.fs.Walk(ctx, path, fn)
105 }
106
107 func (t *timeoutWrapper) URL(ctx context.Context, path string, options *SignedURLOptions) (string, error) {
108 out, err := timeoutCall(ctx, t.write, func() (interface{}, error) {
109 return t.fs.URL(ctx, path, options)
110 })
111 if url, ok := out.(string); ok {
112 return url, err
113 }
114
115 return "", err
116 }
117
View as plain text