github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/lib/params.go (about)

     1  package lib
     2  
     3  import (
     4  	"reflect"
     5  
     6  	"github.com/qri-io/qfs"
     7  	"github.com/qri-io/qri/dsref"
     8  )
     9  
    10  // EmptyParams is for methods that don't need any input
    11  type EmptyParams struct {
    12  }
    13  
    14  // NZDefaultSetter modifies zero values to non-zero defaults when called
    15  type NZDefaultSetter interface {
    16  	SetNonZeroDefaults()
    17  }
    18  
    19  // normalizeInputParams will look at each field of the params, and modify filepaths so that
    20  // they are absolute paths, making them safe to send across RPC to another process
    21  func normalizeInputParams(param interface{}) interface{} {
    22  	typ := reflect.TypeOf(param)
    23  	val := reflect.ValueOf(param)
    24  	if typ.Kind() == reflect.Ptr {
    25  		typ = typ.Elem()
    26  		val = val.Elem()
    27  	}
    28  	if typ.Kind() == reflect.Struct {
    29  		num := typ.NumField()
    30  		for i := 0; i < num; i++ {
    31  			tfield := typ.Field(i)
    32  			vfield := val.Field(i)
    33  			qriTag := tfield.Tag.Get("qri")
    34  			if isQriStructTag(qriTag) {
    35  				normalizeFileField(vfield, qriTag)
    36  			} else if qriTag != "" {
    37  				log.Errorf("unknown qri struct tag %q", qriTag)
    38  			}
    39  		}
    40  	}
    41  	return param
    42  }
    43  
    44  // qri struct tags augment how fields are marshalled for dispatched methods
    45  const (
    46  	// QriStTagFspath means the field is a filesystem path and needs to be absolute
    47  	QriStTagFspath = "fspath"
    48  	// QriStTagRefOrPath means the field is either a dataset ref, or is a filesys path
    49  	QriStTagRefOrPath = "dsrefOrFspath"
    50  )
    51  
    52  func isQriStructTag(text string) bool {
    53  	return text == QriStTagFspath || text == QriStTagRefOrPath
    54  }
    55  
    56  func normalizeFileField(vfield reflect.Value, qriTag string) {
    57  	interf := vfield.Interface()
    58  	if str, ok := interf.(string); ok {
    59  		if qriTag == QriStTagRefOrPath && dsref.IsRefString(str) {
    60  			return
    61  		}
    62  		if err := qfs.AbsPath(&str); err == nil {
    63  			vfield.SetString(str)
    64  		}
    65  	}
    66  	if strList, ok := interf.([]string); ok {
    67  		build := make([]string, 0, len(strList))
    68  		for _, str := range strList {
    69  			if qriTag != QriStTagRefOrPath || !dsref.IsRefString(str) {
    70  				_ = qfs.AbsPath(&str)
    71  			}
    72  			build = append(build, str)
    73  		}
    74  		vfield.Set(reflect.ValueOf(build))
    75  	}
    76  }