utils.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. // Copyright (C) 2016 The Syncthing Authors.
  2. //
  3. // This Source Code Form is subject to the terms of the Mozilla Public
  4. // License, v. 2.0. If a copy of the MPL was not distributed with this file,
  5. // You can obtain one at https://mozilla.org/MPL/2.0/.
  6. package util
  7. import (
  8. "fmt"
  9. "net/url"
  10. "reflect"
  11. "strconv"
  12. "strings"
  13. "github.com/syncthing/syncthing/lib/sync"
  14. "github.com/thejerf/suture"
  15. )
  16. type defaultParser interface {
  17. ParseDefault(string) error
  18. }
  19. // SetDefaults sets default values on a struct, based on the default annotation.
  20. func SetDefaults(data interface{}) {
  21. s := reflect.ValueOf(data).Elem()
  22. t := s.Type()
  23. for i := 0; i < s.NumField(); i++ {
  24. f := s.Field(i)
  25. tag := t.Field(i).Tag
  26. v := tag.Get("default")
  27. if len(v) > 0 {
  28. if f.CanInterface() {
  29. if parser, ok := f.Interface().(defaultParser); ok {
  30. if err := parser.ParseDefault(v); err != nil {
  31. panic(err)
  32. }
  33. continue
  34. }
  35. }
  36. if f.CanAddr() && f.Addr().CanInterface() {
  37. if parser, ok := f.Addr().Interface().(defaultParser); ok {
  38. if err := parser.ParseDefault(v); err != nil {
  39. panic(err)
  40. }
  41. continue
  42. }
  43. }
  44. switch f.Interface().(type) {
  45. case string:
  46. f.SetString(v)
  47. case int:
  48. i, err := strconv.ParseInt(v, 10, 64)
  49. if err != nil {
  50. panic(err)
  51. }
  52. f.SetInt(i)
  53. case float64:
  54. i, err := strconv.ParseFloat(v, 64)
  55. if err != nil {
  56. panic(err)
  57. }
  58. f.SetFloat(i)
  59. case bool:
  60. f.SetBool(v == "true")
  61. case []string:
  62. // We don't do anything with string slices here. Any default
  63. // we set will be appended to by the XML decoder, so we fill
  64. // those after decoding.
  65. default:
  66. panic(f.Type())
  67. }
  68. }
  69. }
  70. }
  71. // CopyMatchingTag copies fields tagged tag:"value" from "from" struct onto "to" struct.
  72. func CopyMatchingTag(from interface{}, to interface{}, tag string, shouldCopy func(value string) bool) {
  73. fromStruct := reflect.ValueOf(from).Elem()
  74. fromType := fromStruct.Type()
  75. toStruct := reflect.ValueOf(to).Elem()
  76. toType := toStruct.Type()
  77. if fromType != toType {
  78. panic(fmt.Sprintf("non equal types: %s != %s", fromType, toType))
  79. }
  80. for i := 0; i < toStruct.NumField(); i++ {
  81. fromField := fromStruct.Field(i)
  82. toField := toStruct.Field(i)
  83. if !toField.CanSet() {
  84. // Unexported fields
  85. continue
  86. }
  87. structTag := toType.Field(i).Tag
  88. v := structTag.Get(tag)
  89. if shouldCopy(v) {
  90. toField.Set(fromField)
  91. }
  92. }
  93. }
  94. // UniqueTrimmedStrings returns a list on unique strings, trimming at the same time.
  95. func UniqueTrimmedStrings(ss []string) []string {
  96. // Trim all first
  97. for i, v := range ss {
  98. ss[i] = strings.Trim(v, " ")
  99. }
  100. var m = make(map[string]struct{}, len(ss))
  101. var us = make([]string, 0, len(ss))
  102. for _, v := range ss {
  103. if _, ok := m[v]; ok {
  104. continue
  105. }
  106. m[v] = struct{}{}
  107. us = append(us, v)
  108. }
  109. return us
  110. }
  111. // FillNilSlices sets default value on slices that are still nil.
  112. func FillNilSlices(data interface{}) error {
  113. s := reflect.ValueOf(data).Elem()
  114. t := s.Type()
  115. for i := 0; i < s.NumField(); i++ {
  116. f := s.Field(i)
  117. tag := t.Field(i).Tag
  118. v := tag.Get("default")
  119. if len(v) > 0 {
  120. switch f.Interface().(type) {
  121. case []string:
  122. if f.IsNil() {
  123. // Treat the default as a comma separated slice
  124. vs := strings.Split(v, ",")
  125. for i := range vs {
  126. vs[i] = strings.TrimSpace(vs[i])
  127. }
  128. rv := reflect.MakeSlice(reflect.TypeOf([]string{}), len(vs), len(vs))
  129. for i, v := range vs {
  130. rv.Index(i).SetString(v)
  131. }
  132. f.Set(rv)
  133. }
  134. }
  135. }
  136. }
  137. return nil
  138. }
  139. // Address constructs a URL from the given network and hostname.
  140. func Address(network, host string) string {
  141. u := url.URL{
  142. Scheme: network,
  143. Host: host,
  144. }
  145. return u.String()
  146. }
  147. // AsService wraps the given function to implement suture.Service by calling
  148. // that function on serve and closing the passed channel when Stop is called.
  149. func AsService(fn func(stop chan struct{})) suture.Service {
  150. return AsServiceWithError(func(stop chan struct{}) error {
  151. fn(stop)
  152. return nil
  153. })
  154. }
  155. type ServiceWithError interface {
  156. suture.Service
  157. Error() error
  158. SetError(error)
  159. }
  160. // AsServiceWithError does the same as AsService, except that it keeps track
  161. // of an error returned by the given function.
  162. func AsServiceWithError(fn func(stop chan struct{}) error) ServiceWithError {
  163. s := &service{
  164. serve: fn,
  165. stop: make(chan struct{}),
  166. stopped: make(chan struct{}),
  167. mut: sync.NewMutex(),
  168. }
  169. close(s.stopped) // not yet started, don't block on Stop()
  170. return s
  171. }
  172. type service struct {
  173. serve func(stop chan struct{}) error
  174. stop chan struct{}
  175. stopped chan struct{}
  176. err error
  177. mut sync.Mutex
  178. }
  179. func (s *service) Serve() {
  180. s.mut.Lock()
  181. select {
  182. case <-s.stop:
  183. s.mut.Unlock()
  184. return
  185. default:
  186. }
  187. s.err = nil
  188. s.stopped = make(chan struct{})
  189. s.mut.Unlock()
  190. var err error
  191. defer func() {
  192. s.mut.Lock()
  193. s.err = err
  194. close(s.stopped)
  195. s.mut.Unlock()
  196. }()
  197. err = s.serve(s.stop)
  198. }
  199. func (s *service) Stop() {
  200. s.mut.Lock()
  201. close(s.stop)
  202. s.mut.Unlock()
  203. <-s.stopped
  204. }
  205. func (s *service) Error() error {
  206. s.mut.Lock()
  207. defer s.mut.Unlock()
  208. return s.err
  209. }
  210. func (s *service) SetError(err error) {
  211. s.mut.Lock()
  212. s.err = err
  213. s.mut.Unlock()
  214. }