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  }