gorqlite.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. /*
  2. gorqlite
  3. A golang database/sql driver for rqlite, the distributed consistent sqlite.
  4. Copyright (c)2016 andrew fabbro (andrew@fabbro.org)
  5. See LICENSE.md for license. tl;dr: MIT. Conveniently, the same licese as rqlite.
  6. Project home page: https://github.com/raindo308/gorqlite
  7. Learn more about rqlite at: https://github.com/rqlite/rqlite
  8. */
  9. package gorqlite
  10. /*
  11. this file contains package-level stuff:
  12. consts
  13. init()
  14. Open, TraceOn(), TraceOff()
  15. */
  16. import "crypto/rand"
  17. import "fmt"
  18. import "io"
  19. import "io/ioutil"
  20. import "strings"
  21. /* *****************************************************************
  22. const
  23. * *****************************************************************/
  24. type consistencyLevel int
  25. const (
  26. cl_NONE consistencyLevel = iota
  27. cl_WEAK
  28. cl_STRONG
  29. )
  30. // used in several places, actually
  31. var consistencyLevelNames map[consistencyLevel]string
  32. var consistencyLevels map[string]consistencyLevel
  33. type apiOperation int
  34. const (
  35. api_QUERY apiOperation = iota
  36. api_STATUS
  37. api_WRITE
  38. )
  39. /* *****************************************************************
  40. init()
  41. * *****************************************************************/
  42. func init() {
  43. traceOut = ioutil.Discard
  44. consistencyLevelNames = make(map[consistencyLevel]string)
  45. consistencyLevelNames[cl_NONE] = "none"
  46. consistencyLevelNames[cl_WEAK] = "weak"
  47. consistencyLevelNames[cl_STRONG] = "strong"
  48. consistencyLevels = make(map[string]consistencyLevel)
  49. consistencyLevels["none"] = cl_NONE
  50. consistencyLevels["weak"] = cl_WEAK
  51. consistencyLevels["strong"] = cl_STRONG
  52. }
  53. /* *****************************************************************
  54. Open() creates and returns a "connection" to rqlite.
  55. Since rqlite is stateless, there is no actual connection. Open() creates and initializes a gorqlite Connection type, which represents various config information.
  56. The URL should be in a form like this:
  57. http://localhost:4001
  58. http:// default, no auth, localhost:4001
  59. https:// default, no auth, localhost:4001, using https
  60. http://localhost:1234
  61. http://mary:secret2@localhost:1234
  62. https://mary:secret2@somewhere.example.com:1234
  63. https://mary:secret2@somewhere.example.com // will use 4001
  64. * *****************************************************************/
  65. func Open(connURL string) (Connection, error) {
  66. var conn Connection
  67. // generate our uuid for trace
  68. b := make([]byte, 16)
  69. _, err := rand.Read(b)
  70. if err != nil {
  71. return conn, err
  72. }
  73. conn.ID = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:])
  74. trace("%s: Open() called for url: %s", conn.ID, connURL)
  75. // set defaults
  76. conn.timeout = 10
  77. conn.hasBeenClosed = false
  78. // parse the URL given
  79. err = conn.initConnection(connURL)
  80. if err != nil {
  81. return conn, err
  82. }
  83. // call updateClusterInfo() to populate the cluster
  84. // also tests the user's default
  85. err = conn.updateClusterInfo()
  86. // and the err from updateClusterInfo() will be our err as well
  87. return conn, err
  88. }
  89. /* *****************************************************************
  90. func: trace()
  91. adds a message to the trace output
  92. not a public function. we (inside) can add - outside they can
  93. only see.
  94. Call trace as: Sprintf pattern , args...
  95. This is done so that the more expensive Sprintf() stuff is
  96. done only if truly needed. When tracing is off, calls to
  97. trace() just hit a bool check and return. If tracing is on,
  98. then the Sprintfing is done at a leisurely pace because, well,
  99. we're tracing.
  100. Premature optimization is the root of all evil, so this is
  101. probably sinful behavior.
  102. Don't put a \n in your Sprintf pattern becuase trace() adds one
  103. * *****************************************************************/
  104. func trace(pattern string, args ...interface{}) {
  105. // don't do the probably expensive Sprintf() if not needed
  106. if wantsTrace == false {
  107. return
  108. }
  109. // this could all be made into one long statement but we have
  110. // compilers to do such things for us. let's sip a mint julep
  111. // and spell this out in glorious exposition.
  112. // make sure there is one and only one newline
  113. nlPattern := strings.TrimSpace(pattern) + "\n"
  114. msg := fmt.Sprintf(nlPattern, args...)
  115. traceOut.Write([]byte(msg))
  116. }
  117. /*
  118. TraceOn()
  119. Turns on tracing output to the io.Writer of your choice.
  120. Trace output is very detailed and verbose, as you might expect.
  121. Normally, you should run with tracing off, as it makes absolutely
  122. no concession to performance and is intended for debugging/dev use.
  123. */
  124. func TraceOn(w io.Writer) {
  125. traceOut = w
  126. wantsTrace = true
  127. }
  128. /*
  129. TraceOff()
  130. Turns off tracing output. Once you call TraceOff(), no further
  131. info is sent to the io.Writer, unless it is TraceOn'd again.
  132. */
  133. func TraceOff() {
  134. wantsTrace = false
  135. traceOut = ioutil.Discard
  136. }