/* gorqlite A golang database/sql driver for rqlite, the distributed consistent sqlite. Copyright (c)2016 andrew fabbro (andrew@fabbro.org) See LICENSE.md for license. tl;dr: MIT. Conveniently, the same licese as rqlite. Project home page: https://github.com/raindo308/gorqlite Learn more about rqlite at: https://github.com/rqlite/rqlite */ package gorqlite /* this file contains package-level stuff: consts init() Open, TraceOn(), TraceOff() */ import "crypto/rand" import "fmt" import "io" import "io/ioutil" import "strings" /* ***************************************************************** const * *****************************************************************/ type consistencyLevel int const ( cl_NONE consistencyLevel = iota cl_WEAK cl_STRONG ) // used in several places, actually var consistencyLevelNames map[consistencyLevel]string var consistencyLevels map[string]consistencyLevel type apiOperation int const ( api_QUERY apiOperation = iota api_STATUS api_WRITE ) /* ***************************************************************** init() * *****************************************************************/ func init() { traceOut = ioutil.Discard consistencyLevelNames = make(map[consistencyLevel]string) consistencyLevelNames[cl_NONE] = "none" consistencyLevelNames[cl_WEAK] = "weak" consistencyLevelNames[cl_STRONG] = "strong" consistencyLevels = make(map[string]consistencyLevel) consistencyLevels["none"] = cl_NONE consistencyLevels["weak"] = cl_WEAK consistencyLevels["strong"] = cl_STRONG } /* ***************************************************************** Open() creates and returns a "connection" to rqlite. Since rqlite is stateless, there is no actual connection. Open() creates and initializes a gorqlite Connection type, which represents various config information. The URL should be in a form like this: http://localhost:4001 http:// default, no auth, localhost:4001 https:// default, no auth, localhost:4001, using https http://localhost:1234 http://mary:secret2@localhost:1234 https://mary:secret2@somewhere.example.com:1234 https://mary:secret2@somewhere.example.com // will use 4001 * *****************************************************************/ func Open(connURL string) (Connection, error) { var conn Connection // generate our uuid for trace b := make([]byte, 16) _, err := rand.Read(b) if err != nil { return conn, err } conn.ID = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) trace("%s: Open() called for url: %s", conn.ID, connURL) // set defaults conn.timeout = 10 conn.hasBeenClosed = false // parse the URL given err = conn.initConnection(connURL) if err != nil { return conn, err } // call updateClusterInfo() to populate the cluster // also tests the user's default err = conn.updateClusterInfo() // and the err from updateClusterInfo() will be our err as well return conn, err } /* ***************************************************************** func: trace() adds a message to the trace output not a public function. we (inside) can add - outside they can only see. Call trace as: Sprintf pattern , args... This is done so that the more expensive Sprintf() stuff is done only if truly needed. When tracing is off, calls to trace() just hit a bool check and return. If tracing is on, then the Sprintfing is done at a leisurely pace because, well, we're tracing. Premature optimization is the root of all evil, so this is probably sinful behavior. Don't put a \n in your Sprintf pattern becuase trace() adds one * *****************************************************************/ func trace(pattern string, args ...interface{}) { // don't do the probably expensive Sprintf() if not needed if wantsTrace == false { return } // this could all be made into one long statement but we have // compilers to do such things for us. let's sip a mint julep // and spell this out in glorious exposition. // make sure there is one and only one newline nlPattern := strings.TrimSpace(pattern) + "\n" msg := fmt.Sprintf(nlPattern, args...) traceOut.Write([]byte(msg)) } /* TraceOn() Turns on tracing output to the io.Writer of your choice. Trace output is very detailed and verbose, as you might expect. Normally, you should run with tracing off, as it makes absolutely no concession to performance and is intended for debugging/dev use. */ func TraceOn(w io.Writer) { traceOut = w wantsTrace = true } /* TraceOff() Turns off tracing output. Once you call TraceOff(), no further info is sent to the io.Writer, unless it is TraceOn'd again. */ func TraceOff() { wantsTrace = false traceOut = ioutil.Discard }