github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/runtimevar/constantvar/constantvar.go (about) 1 // Copyright 2018 The Go Cloud Development Kit Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package constantvar provides a runtimevar implementation with Variables 16 // that never change. Use New, NewBytes, or NewError to construct a 17 // *runtimevar.Variable. 18 // 19 // # URLs 20 // 21 // For runtimevar.OpenVariable, constantvar registers for the scheme "constant". 22 // For more details on the URL format, see URLOpener. 23 // See https://gocloud.dev/concepts/urls/ for background information. 24 // 25 // # As 26 // 27 // constantvar does not support any types for As. 28 package constantvar // import "gocloud.dev/runtimevar/constantvar" 29 30 import ( 31 "context" 32 "errors" 33 "fmt" 34 "net/url" 35 "time" 36 37 "gocloud.dev/gcerrors" 38 "gocloud.dev/runtimevar" 39 "gocloud.dev/runtimevar/driver" 40 ) 41 42 func init() { 43 runtimevar.DefaultURLMux().RegisterVariable(Scheme, &URLOpener{}) 44 } 45 46 // Scheme is the URL scheme constantvar registers its URLOpener under on blob.DefaultMux. 47 const Scheme = "constant" 48 49 // URLOpener opens constantvar URLs like "constant://?val=foo&decoder=string". 50 // 51 // The host and path are ignored. 52 // 53 // The following URL parameters are supported: 54 // - val: The value to use for the constant Variable. The bytes from val 55 // are passed to NewBytes. 56 // - err: The error to use for the constant Variable. A new error is created 57 // using errors.New and passed to NewError. 58 // - decoder: The decoder to use. Defaults to runtimevar.BytesDecoder. 59 // See runtimevar.DecoderByName for supported values. 60 // 61 // If both "err" and "val" are provided, "val" is ignored. 62 type URLOpener struct { 63 // Decoder specifies the decoder to use if one is not specified in the URL. 64 // Defaults to runtimevar.BytesDecoder. 65 Decoder *runtimevar.Decoder 66 } 67 68 // OpenVariableURL opens the variable at the URL's path. See the package doc 69 // for more details. 70 func (o *URLOpener) OpenVariableURL(ctx context.Context, u *url.URL) (*runtimevar.Variable, error) { 71 q := u.Query() 72 73 val := q.Get("val") 74 q.Del("val") 75 76 errVal := q.Get("err") 77 q.Del("err") 78 79 decoderName := q.Get("decoder") 80 q.Del("decoder") 81 decoder, err := runtimevar.DecoderByName(ctx, decoderName, o.Decoder) 82 if err != nil { 83 return nil, fmt.Errorf("open variable %v: invalid decoder: %v", u, err) 84 } 85 86 for param := range q { 87 return nil, fmt.Errorf("open variable %v: invalid query parameter %q", u, param) 88 } 89 if errVal != "" { 90 return NewError(errors.New(errVal)), nil 91 } 92 return NewBytes([]byte(val), decoder), nil 93 } 94 95 var errNotExist = errors.New("variable does not exist") 96 97 // New constructs a *runtimevar.Variable holding value. 98 func New(value interface{}) *runtimevar.Variable { 99 return runtimevar.New(&watcher{value: value, t: time.Now()}) 100 } 101 102 // NewBytes uses decoder to decode b. If the decode succeeds, it constructs 103 // a *runtimevar.Variable holding the decoded value. If the decode fails, it 104 // constructs a runtimevar.Variable that always fails with the error. 105 func NewBytes(b []byte, decoder *runtimevar.Decoder) *runtimevar.Variable { 106 value, err := decoder.Decode(context.Background(), b) 107 if err != nil { 108 return NewError(err) 109 } 110 return New(value) 111 } 112 113 // NewError constructs a *runtimevar.Variable that always fails. Runtimevar 114 // wraps errors returned by drivers, so the error returned 115 // by runtimevar will not equal err. 116 func NewError(err error) *runtimevar.Variable { 117 return runtimevar.New(&watcher{err: err}) 118 } 119 120 // watcher implements driver.Watcher and driver.State. 121 type watcher struct { 122 value interface{} 123 err error 124 t time.Time 125 } 126 127 // Value implements driver.State.Value. 128 func (w *watcher) Value() (interface{}, error) { 129 return w.value, w.err 130 } 131 132 // UpdateTime implements driver.State.UpdateTime. 133 func (w *watcher) UpdateTime() time.Time { 134 return w.t 135 } 136 137 // As implements driver.State.As. 138 func (w *watcher) As(i interface{}) bool { 139 return false 140 } 141 142 // WatchVariable implements driver.WatchVariable. 143 func (w *watcher) WatchVariable(ctx context.Context, prev driver.State) (driver.State, time.Duration) { 144 // The first time this is called, return the constant value. 145 if prev == nil { 146 return w, 0 147 } 148 // On subsequent calls, block forever as the value will never change. 149 <-ctx.Done() 150 w.err = ctx.Err() 151 return w, 0 152 } 153 154 // Close implements driver.Close. 155 func (*watcher) Close() error { return nil } 156 157 // ErrorAs implements driver.ErrorAs. 158 func (*watcher) ErrorAs(err error, i interface{}) bool { return false } 159 160 // ErrorCode implements driver.ErrorCode 161 func (*watcher) ErrorCode(err error) gcerrors.ErrorCode { 162 if err == errNotExist { 163 return gcerrors.NotFound 164 } 165 return gcerrors.Unknown 166 }