1package godo 2 3import ( 4 "bytes" 5 "fmt" 6 "io" 7 "reflect" 8 "strings" 9) 10 11var timestampType = reflect.TypeOf(Timestamp{}) 12 13// ResourceWithURN is an interface for interfacing with the types 14// that implement the URN method. 15type ResourceWithURN interface { 16 URN() string 17} 18 19// ToURN converts the resource type and ID to a valid DO API URN. 20func ToURN(resourceType string, id interface{}) string { 21 return fmt.Sprintf("%s:%s:%v", "do", strings.ToLower(resourceType), id) 22} 23 24// Stringify attempts to create a string representation of DigitalOcean types 25func Stringify(message interface{}) string { 26 var buf bytes.Buffer 27 v := reflect.ValueOf(message) 28 stringifyValue(&buf, v) 29 return buf.String() 30} 31 32// stringifyValue was graciously cargoculted from the goprotubuf library 33func stringifyValue(w io.Writer, val reflect.Value) { 34 if val.Kind() == reflect.Ptr && val.IsNil() { 35 _, _ = w.Write([]byte("<nil>")) 36 return 37 } 38 39 v := reflect.Indirect(val) 40 41 switch v.Kind() { 42 case reflect.String: 43 fmt.Fprintf(w, `"%s"`, v) 44 case reflect.Slice: 45 stringifySlice(w, v) 46 return 47 case reflect.Struct: 48 stringifyStruct(w, v) 49 default: 50 if v.CanInterface() { 51 fmt.Fprint(w, v.Interface()) 52 } 53 } 54} 55 56func stringifySlice(w io.Writer, v reflect.Value) { 57 _, _ = w.Write([]byte{'['}) 58 for i := 0; i < v.Len(); i++ { 59 if i > 0 { 60 _, _ = w.Write([]byte{' '}) 61 } 62 63 stringifyValue(w, v.Index(i)) 64 } 65 66 _, _ = w.Write([]byte{']'}) 67} 68 69func stringifyStruct(w io.Writer, v reflect.Value) { 70 if v.Type().Name() != "" { 71 _, _ = w.Write([]byte(v.Type().String())) 72 } 73 74 // special handling of Timestamp values 75 if v.Type() == timestampType { 76 fmt.Fprintf(w, "{%s}", v.Interface()) 77 return 78 } 79 80 _, _ = w.Write([]byte{'{'}) 81 82 var sep bool 83 for i := 0; i < v.NumField(); i++ { 84 fv := v.Field(i) 85 if fv.Kind() == reflect.Ptr && fv.IsNil() { 86 continue 87 } 88 if fv.Kind() == reflect.Slice && fv.IsNil() { 89 continue 90 } 91 92 if sep { 93 _, _ = w.Write([]byte(", ")) 94 } else { 95 sep = true 96 } 97 98 _, _ = w.Write([]byte(v.Type().Field(i).Name)) 99 _, _ = w.Write([]byte{':'}) 100 stringifyValue(w, fv) 101 } 102 103 _, _ = w.Write([]byte{'}'}) 104} 105