github.com/MetalBlockchain/metalgo@v1.11.9/utils/json/codec.go (about)

     1  // Copyright (C) 2019-2024, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package json
     5  
     6  import (
     7  	"errors"
     8  	"fmt"
     9  	"net/http"
    10  	"strings"
    11  	"unicode"
    12  	"unicode/utf8"
    13  
    14  	"github.com/gorilla/rpc/v2"
    15  	"github.com/gorilla/rpc/v2/json2"
    16  )
    17  
    18  const (
    19  	// Null is the string representation of a null value
    20  	Null = "null"
    21  )
    22  
    23  var (
    24  	errUppercaseMethod = errors.New("method must start with a non-uppercase letter")
    25  	errInvalidArg      = errors.New("couldn't unmarshal an argument. Ensure arguments are valid and properly formatted. See documentation for example calls")
    26  )
    27  
    28  // NewCodec returns a new json codec that will convert the first character of
    29  // the method to uppercase
    30  func NewCodec() rpc.Codec {
    31  	return lowercase{json2.NewCodec()}
    32  }
    33  
    34  type lowercase struct{ *json2.Codec }
    35  
    36  func (lc lowercase) NewRequest(r *http.Request) rpc.CodecRequest {
    37  	return &request{lc.Codec.NewRequest(r).(*json2.CodecRequest)}
    38  }
    39  
    40  type request struct{ *json2.CodecRequest }
    41  
    42  func (r *request) Method() (string, error) {
    43  	method, err := r.CodecRequest.Method()
    44  	methodSections := strings.SplitN(method, ".", 2)
    45  	if len(methodSections) != 2 || err != nil {
    46  		return method, err
    47  	}
    48  	class, function := methodSections[0], methodSections[1]
    49  	firstRune, runeLen := utf8.DecodeRuneInString(function)
    50  	if firstRune == utf8.RuneError {
    51  		return method, nil
    52  	}
    53  	if unicode.IsUpper(firstRune) {
    54  		return method, errUppercaseMethod
    55  	}
    56  	uppercaseRune := string(unicode.ToUpper(firstRune))
    57  	return fmt.Sprintf("%s.%s%s", class, uppercaseRune, function[runeLen:]), nil
    58  }
    59  
    60  func (r *request) ReadRequest(args interface{}) error {
    61  	if err := r.CodecRequest.ReadRequest(args); err != nil {
    62  		return errInvalidArg
    63  	}
    64  	return nil
    65  }