http urls monitor.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. package toml
  2. import (
  3. "errors"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "runtime"
  9. "strings"
  10. )
  11. type tomlValue struct {
  12. value interface{} // string, int64, uint64, float64, bool, time.Time, [] of any of this list
  13. comment string
  14. commented bool
  15. multiline bool
  16. position Position
  17. }
  18. // Tree is the result of the parsing of a TOML file.
  19. type Tree struct {
  20. values map[string]interface{} // string -> *tomlValue, *Tree, []*Tree
  21. comment string
  22. commented bool
  23. position Position
  24. }
  25. func newTree() *Tree {
  26. return &Tree{
  27. values: make(map[string]interface{}),
  28. position: Position{},
  29. }
  30. }
  31. // TreeFromMap initializes a new Tree object using the given map.
  32. func TreeFromMap(m map[string]interface{}) (*Tree, error) {
  33. result, err := toTree(m)
  34. if err != nil {
  35. return nil, err
  36. }
  37. return result.(*Tree), nil
  38. }
  39. // Position returns the position of the tree.
  40. func (t *Tree) Position() Position {
  41. return t.position
  42. }
  43. // Has returns a boolean indicating if the given key exists.
  44. func (t *Tree) Has(key string) bool {
  45. if key == "" {
  46. return false
  47. }
  48. return t.HasPath(strings.Split(key, "."))
  49. }
  50. // HasPath returns true if the given path of keys exists, false otherwise.
  51. func (t *Tree) HasPath(keys []string) bool {
  52. return t.GetPath(keys) != nil
  53. }
  54. // Keys returns the keys of the toplevel tree (does not recurse).
  55. func (t *Tree) Keys() []string {
  56. keys := make([]string, len(t.values))
  57. i := 0
  58. for k := range t.values {
  59. keys[i] = k
  60. i++
  61. }
  62. return keys
  63. }
  64. // Get the value at key in the Tree.
  65. // Key is a dot-separated path (e.g. a.b.c) without single/double quoted strings.
  66. // If you need to retrieve non-bare keys, use GetPath.
  67. // Returns nil if the path does not exist in the tree.
  68. // If keys is of length zero, the current tree is returned.
  69. func (t *Tree) Get(key string) interface{} {
  70. if key == "" {
  71. return t
  72. }
  73. return t.GetPath(strings.Split(key, "."))
  74. }
  75. // GetPath returns the element in the tree indicated by 'keys'.
  76. // If keys is of length zero, the current tree is returned.
  77. func (t *Tree) GetPath(keys []string) interface{} {
  78. if len(keys) == 0 {
  79. return t
  80. }
  81. subtree := t
  82. for _, intermediateKey := range keys[:len(keys)-1] {
  83. value, exists := subtree.values[intermediateKey]
  84. if !exists {
  85. return nil
  86. }
  87. switch node := value.(type) {
  88. case *Tree:
  89. subtree = node
  90. case []*Tree:
  91. // go to most recent element
  92. if len(node) == 0 {
  93. return nil
  94. }
  95. subtree = node[len(node)-1]
  96. default:
  97. return nil // cannot navigate through other node types
  98. }
  99. }
  100. // branch based on final node type
  101. switch node := subtree.values[keys[len(keys)-1]].(type) {
  102. case *tomlValue:
  103. return node.value
  104. default:
  105. return node
  106. }
  107. }
  108. // GetPosition returns the position of the given key.
  109. func (t *Tree) GetPosition(key string) Position {
  110. if key == "" {
  111. return t.position
  112. }
  113. return t.GetPositionPath(strings.Split(key, "."))
  114. }
  115. // GetPositionPath returns the element in the tree indicated by 'keys'.
  116. // If keys is of length zero, the current tree is returned.
  117. func (t *Tree) GetPositionPath(keys []string) Position {
  118. if len(keys) == 0 {
  119. return t.position
  120. }
  121. subtree := t
  122. for _, intermediateKey := range keys[:len(keys)-1] {
  123. value, exists := subtree.values[intermediateKey]
  124. if !exists {
  125. return Position{0, 0}
  126. }
  127. switch node := value.(type) {
  128. case *Tree:
  129. subtree = node
  130. case []*Tree:
  131. // go to most recent element
  132. if len(node) == 0 {
  133. return Position{0, 0}
  134. }
  135. subtree = node[len(node)-1]
  136. default:
  137. return Position{0, 0}
  138. }
  139. }
  140. // branch based on final node type
  141. switch node := subtree.values[keys[len(keys)-1]].(type) {
  142. case *tomlValue:
  143. return node.position
  144. case *Tree:
  145. return node.position
  146. case []*Tree:
  147. // go to most recent element
  148. if len(node) == 0 {
  149. return Position{0, 0}
  150. }
  151. return node[len(node)-1].position
  152. default:
  153. return Position{0, 0}
  154. }
  155. }
  156. // GetDefault works like Get but with a default value
  157. func (t *Tree) GetDefault(key string, def interface{}) interface{} {
  158. val := t.Get(key)
  159. if val == nil {
  160. return def
  161. }
  162. return val
  163. }
  164. // SetOptions arguments are supplied to the SetWithOptions and SetPathWithOptions functions to modify marshalling behaviour.
  165. // The default values within the struct are valid default options.
  166. type SetOptions struct {
  167. Comment string
  168. Commented bool
  169. Multiline bool
  170. }
  171. // SetWithOptions is the same as Set, but allows you to provide formatting
  172. // instructions to the key, that will be used by Marshal().
  173. func (t *Tree) SetWithOptions(key string, opts SetOptions, value interface{}) {
  174. t.SetPathWithOptions(strings.Split(key, "."), opts, value)
  175. }
  176. // SetPathWithOptions is the same as SetPath, but allows you to provide
  177. // formatting instructions to the key, that will be reused by Marshal().
  178. func (t *Tree) SetPathWithOptions(keys []string, opts SetOptions, value interface{}) {
  179. subtree := t
  180. for _, intermediateKey := range keys[:len(keys)-1] {
  181. nextTree, exists := subtree.values[intermediateKey]
  182. if !exists {
  183. nextTree = newTree()
  184. subtree.values[intermediateKey] = nextTree // add new element here
  185. }
  186. switch node := nextTree.(type) {
  187. case *Tree:
  188. subtree = node
  189. case []*Tree:
  190. // go to most recent element
  191. if len(node) == 0 {
  192. // create element if it does not exist
  193. subtree.values[intermediateKey] = append(node, newTree())
  194. }
  195. subtree = node[len(node)-1]
  196. }
  197. }
  198. var toInsert interface{}
  199. switch value.(type) {
  200. case *Tree:
  201. tt := value.(*Tree)
  202. tt.comment = opts.Comment
  203. toInsert = value
  204. case []*Tree:
  205. toInsert = value
  206. case *tomlValue:
  207. tt := value.(*tomlValue)
  208. tt.comment = opts.Comment
  209. toInsert = tt
  210. default:
  211. toInsert = &tomlValue{value: value, comment: opts.Comment, commented: opts.Commented, multiline: opts.Multiline}
  212. }
  213. subtree.values[keys[len(keys)-1]] = toInsert
  214. }
  215. // Set an element in the tree.
  216. // Key is a dot-separated path (e.g. a.b.c).
  217. // Creates all necessary intermediate trees, if needed.
  218. func (t *Tree) Set(key string, value interface{}) {
  219. t.SetWithComment(key, "", false, value)
  220. }
  221. // SetWithComment is the same as Set, but allows you to provide comment
  222. // information to the key, that will be reused by Marshal().
  223. func (t *Tree) SetWithComment(key string, comment string, commented bool, value interface{}) {
  224. t.SetPathWithComment(strings.Split(key, "."), comment, commented, value)
  225. }
  226. // SetPath sets an element in the tree.
  227. // Keys is an array of path elements (e.g. {"a","b","c"}).
  228. // Creates all necessary intermediate trees, if needed.
  229. func (t *Tree) SetPath(keys []string, value interface{}) {
  230. t.SetPathWithComment(keys, "", false, value)
  231. }
  232. // SetPathWithComment is the same as SetPath, but allows you to provide comment
  233. // information to the key, that will be reused by Marshal().
  234. func (t *Tree) SetPathWithComment(keys []string, comment string, commented bool, value interface{}) {
  235. subtree := t
  236. for _, intermediateKey := range keys[:len(keys)-1] {
  237. nextTree, exists := subtree.values[intermediateKey]
  238. if !exists {
  239. nextTree = newTree()
  240. subtree.values[intermediateKey] = nextTree // add new element here
  241. }
  242. switch node := nextTree.(type) {
  243. case *Tree:
  244. subtree = node
  245. case []*Tree:
  246. // go to most recent element
  247. if len(node) == 0 {
  248. // create element if it does not exist
  249. subtree.values[intermediateKey] = append(node, newTree())
  250. }
  251. subtree = node[len(node)-1]
  252. }
  253. }
  254. var toInsert interface{}
  255. switch value.(type) {
  256. case *Tree:
  257. tt := value.(*Tree)
  258. tt.comment = comment
  259. toInsert = value
  260. case []*Tree:
  261. toInsert = value
  262. case *tomlValue:
  263. tt := value.(*tomlValue)
  264. tt.comment = comment
  265. toInsert = tt
  266. default:
  267. toInsert = &tomlValue{value: value, comment: comment, commented: commented}
  268. }
  269. subtree.values[keys[len(keys)-1]] = toInsert
  270. }
  271. // createSubTree takes a tree and a key and create the necessary intermediate
  272. // subtrees to create a subtree at that point. In-place.
  273. //
  274. // e.g. passing a.b.c will create (assuming tree is empty) tree[a], tree[a][b]
  275. // and tree[a][b][c]
  276. //
  277. // Returns nil on success, error object on failure
  278. func (t *Tree) createSubTree(keys []string, pos Position) error {
  279. subtree := t
  280. for _, intermediateKey := range keys {
  281. nextTree, exists := subtree.values[intermediateKey]
  282. if !exists {
  283. tree := newTree()
  284. tree.position = pos
  285. subtree.values[intermediateKey] = tree
  286. nextTree = tree
  287. }
  288. switch node := nextTree.(type) {
  289. case []*Tree:
  290. subtree = node[len(node)-1]
  291. case *Tree:
  292. subtree = node
  293. default:
  294. return fmt.Errorf("unknown type for path %s (%s): %T (%#v)",
  295. strings.Join(keys, "."), intermediateKey, nextTree, nextTree)
  296. }
  297. }
  298. return nil
  299. }
  300. // LoadBytes creates a Tree from a []byte.
  301. func LoadBytes(b []byte) (tree *Tree, err error) {
  302. defer func() {
  303. if r := recover(); r != nil {
  304. if _, ok := r.(runtime.Error); ok {
  305. panic(r)
  306. }
  307. err = errors.New(r.(string))
  308. }
  309. }()
  310. tree = parseToml(lexToml(b))
  311. return
  312. }
  313. // LoadReader creates a Tree from any io.Reader.
  314. func LoadReader(reader io.Reader) (tree *Tree, err error) {
  315. inputBytes, err := ioutil.ReadAll(reader)
  316. if err != nil {
  317. return
  318. }
  319. tree, err = LoadBytes(inputBytes)
  320. return
  321. }
  322. // Load creates a Tree from a string.
  323. func Load(content string) (tree *Tree, err error) {
  324. return LoadBytes([]byte(content))
  325. }
  326. // LoadFile creates a Tree from a file.
  327. func LoadFile(path string) (tree *Tree, err error) {
  328. file, err := os.Open(path)
  329. if err != nil {
  330. return nil, err
  331. }
  332. defer file.Close()
  333. return LoadReader(file)
  334. }