<commit_before>package oci8

/*
#include <oci.h>
#include <stdlib.h>
#include <string.h>

#cgo pkg-config: oci8
*/
import "C"
import (
	"database/sql"
	"database/sql/driver"
	"errors"
	"fmt"
	"io"
	"strings"
	"unsafe"
)

func init() {
	sql.Register("oci8", &OCI8Driver{})
}

type OCI8Driver struct {
}

type OCI8Conn struct {
	svc unsafe.Pointer
	env unsafe.Pointer
	err unsafe.Pointer
}

type OCI8Tx struct {
	c *OCI8Conn
}

func (tx *OCI8Tx) Commit() error {
	if err := tx.c.exec("COMMIT"); err != nil {
		return err
	}
	return nil
}

func (tx *OCI8Tx) Rollback() error {
	if err := tx.c.exec("ROLLBACK"); err != nil {
		return err
	}
	return nil
}

func (c *OCI8Conn) exec(cmd string) error {
	stmt, err := c.Prepare(cmd)
	if err == nil {
		defer stmt.Close()
		_, err = stmt.Exec(nil)
	}
	return err
}

func (c *OCI8Conn) Begin() (driver.Tx, error) {
	if err := c.exec("BEGIN"); err != nil {
		return nil, err
	}
	return &OCI8Tx{c}, nil
}

func (d *OCI8Driver) Open(dsn string) (driver.Conn, error) {
	var conn OCI8Conn
	token := strings.SplitN(dsn, "@", 2)
	userpass := strings.SplitN(token[0], "/", 2)

	rv := C.OCIInitialize(
		C.OCI_DEFAULT,
		nil,
		nil,
		nil,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	rv = C.OCIEnvInit(
		(**C.OCIEnv)(unsafe.Pointer(&conn.env)),
		C.OCI_DEFAULT,
		0,
		nil)

	rv = C.OCIHandleAlloc(
		conn.env,
		&conn.err,
		C.OCI_HTYPE_ERROR,
		0,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	var phost *C.char
	phostlen := C.size_t(0)
	if len(token) > 1 {
		phost = C.CString(token[1])
		defer C.free(unsafe.Pointer(phost))
		phostlen = C.strlen(phost)
	}
	puser := C.CString(userpass[0])
	defer C.free(unsafe.Pointer(puser))
	ppass := C.CString(userpass[1])
	defer C.free(unsafe.Pointer(ppass))

	rv = C.OCILogon(
		(*C.OCIEnv)(conn.env),
		(*C.OCIError)(conn.err),
		(**C.OCIServer)(unsafe.Pointer(&conn.svc)),
		(*C.OraText)(unsafe.Pointer(puser)),
		C.ub4(C.strlen(puser)),
		(*C.OraText)(unsafe.Pointer(ppass)),
		C.ub4(C.strlen(ppass)),
		(*C.OraText)(unsafe.Pointer(phost)),
		C.ub4(phostlen))
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	return &conn, nil
}

func (c *OCI8Conn) Close() error {
	rv := C.OCILogoff(
		(*C.OCIServer)(c.svc),
		(*C.OCIError)(c.err))
	if rv == C.OCI_ERROR {
		return ociGetError(c.err)
	}

	C.OCIHandleFree(
		c.env,
		C.OCI_HTYPE_ENV)

	c.svc = nil
	c.env = nil
	c.err = nil
	return nil
}

type OCI8Stmt struct {
	c      *OCI8Conn
	s      unsafe.Pointer
	closed bool
}

func (c *OCI8Conn) Prepare(query string) (driver.Stmt, error) {
	pquery := C.CString(query)
	defer C.free(unsafe.Pointer(pquery))
	var s unsafe.Pointer

	rv := C.OCIHandleAlloc(
		c.env,
		&s,
		C.OCI_HTYPE_STMT,
		0,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(c.err)
	}

	rv = C.OCIStmtPrepare(
		(*C.OCIStmt)(s),
		(*C.OCIError)(c.err),
		(*C.OraText)(unsafe.Pointer(pquery)),
		C.ub4(C.strlen(pquery)),
		C.ub4(C.OCI_NTV_SYNTAX),
		C.ub4(C.OCI_DEFAULT))
	if rv == C.OCI_ERROR {
		return nil, ociGetError(c.err)
	}

	return &OCI8Stmt{c: c, s: s}, nil
}

func (s *OCI8Stmt) Close() error {
	if s.closed {
		return nil
	}
	s.closed = true

	C.OCIHandleFree(
		s.s,
		C.OCI_HTYPE_STMT)
	s.s = nil

	return nil
}

func (s *OCI8Stmt) NumInput() int {
	var num C.int
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&num),
		nil,
		C.OCI_ATTR_BIND_COUNT,
		(*C.OCIError)(s.c.err))
	return int(num)
}

func (s *OCI8Stmt) bind(args []driver.Value) error {
	if args == nil {
		return nil
	}

	var bp *C.OCIBind
	for i, v := range args {
		b := []byte(fmt.Sprintf("%v", v))
		b = append(b, 0)
		rv := C.OCIBindByPos(
			(*C.OCIStmt)(s.s),
			&bp,
			(*C.OCIError)(s.c.err),
			C.ub4(i+1),
			unsafe.Pointer(&b[0]),
			C.sb4(len(b)),
			C.SQLT_STR,
			nil,
			nil,
			nil,
			0,
			nil,
			C.OCI_DEFAULT)

		if rv == C.OCI_ERROR {
			return ociGetError(s.c.err)
		}
	}
	return nil
}

func (s *OCI8Stmt) Query(args []driver.Value) (driver.Rows, error) {
	if err := s.bind(args); err != nil {
		return nil, err
	}

	var t C.int
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_STMT_TYPE,
		(*C.OCIError)(s.c.err))
	iter := C.ub4(1)
	if t == C.OCI_STMT_SELECT {
		iter = 0
	}

	rv := C.OCIStmtExecute(
		(*C.OCIServer)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		iter,
		0,
		nil,
		nil,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}

	var rc C.ub2
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&rc),
		nil,
		C.OCI_ATTR_PARAM_COUNT,
		(*C.OCIError)(s.c.err))

	oci8cols := make([]oci8col, int(rc))
	for i := 0; i < int(rc); i++ {
		var p unsafe.Pointer
		var np *C.char
		var ns C.ub4
		var tp C.ub2
		var lp C.ub2
		C.OCIParamGet(
			s.s,
			C.OCI_HTYPE_STMT,
			(*C.OCIError)(s.c.err),
			(*unsafe.Pointer)(unsafe.Pointer(&p)),
			C.ub4(i+1))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&tp),
			nil,
			C.OCI_ATTR_DATA_TYPE,
			(*C.OCIError)(s.c.err))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&np),
			&ns,
			C.OCI_ATTR_NAME,
			(*C.OCIError)(s.c.err))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&lp),
			nil,
			C.OCI_ATTR_DATA_SIZE,
			(*C.OCIError)(s.c.err))
		oci8cols[i].name = string((*[1 << 30]byte)(unsafe.Pointer(np))[0:int(ns)])
		oci8cols[i].kind = int(tp)
		oci8cols[i].size = int(lp)
		oci8cols[i].pbuf = make([]byte, int(lp)+1)

		var defp *C.OCIDefine
		rv = C.OCIDefineByPos(
			(*C.OCIStmt)(s.s),
			&defp,
			(*C.OCIError)(s.c.err),
			C.ub4(i+1),
			unsafe.Pointer(&oci8cols[i].pbuf[0]),
			C.sb4(lp+1),
			C.SQLT_CHR,
			unsafe.Pointer(&oci8cols[i].ind),
			nil,
			nil,
			C.OCI_DEFAULT)
		if rv == C.OCI_ERROR {
			return nil, ociGetError(s.c.err)
		}
	}
	return &OCI8Rows{s, oci8cols, false}, nil
}

type OCI8Result struct {
	s *OCI8Stmt
}

func (r *OCI8Result) LastInsertId() (int64, error) {
	var t C.ub4
	rv := C.OCIAttrGet(
		r.s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_ROWID,
		(*C.OCIError)(r.s.c.err))
	if rv == C.OCI_ERROR {
		return 0, ociGetError(r.s.c.err)
	}
	return int64(t), nil
}

func (r *OCI8Result) RowsAffected() (int64, error) {
	var t C.ub4
	rv := C.OCIAttrGet(
		r.s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_ROW_COUNT,
		(*C.OCIError)(r.s.c.err))
	if rv == C.OCI_ERROR {
		return 0, ociGetError(r.s.c.err)
	}
	return int64(t), nil
}

func (s *OCI8Stmt) Exec(args []driver.Value) (driver.Result, error) {
	if err := s.bind(args); err != nil {
		return nil, err
	}

	rv := C.OCIStmtExecute(
		(*C.OCIServer)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}
	return &OCI8Result{s}, nil
}

type oci8col struct {
	name string
	kind int
	size int
	ind  int
	pbuf []byte
}

type OCI8Rows struct {
	s    *OCI8Stmt
	cols []oci8col
	e    bool
}

func (rc *OCI8Rows) Close() error {
	return rc.s.Close()
}

func (rc *OCI8Rows) Columns() []string {
	cols := make([]string, len(rc.cols))
	for i, col := range rc.cols {
		cols[i] = col.name
	}
	return cols
}

func (rc *OCI8Rows) Next(dest []driver.Value) error {
	rv := C.OCIStmtFetch(
		(*C.OCIStmt)(rc.s.s),
		(*C.OCIError)(rc.s.c.err),
		1,
		C.OCI_FETCH_NEXT,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return ociGetError(rc.s.c.err)
	}

	if rv == C.OCI_NO_DATA {
		return io.EOF
	}

	for i := range dest {
		switch {
		case rc.cols[i].ind == -1: //Null
			dest[i] = nil
		case rc.cols[i].ind == 0 || //Normal
			rc.cols[i].ind == -2 || //Field longer than type (truncated)
			rc.cols[i].ind > 0: //Field longer than type (truncated). Value is original length.
			dest[i] = string(rc.cols[i].pbuf)
		default:
			return errors.New(fmt.Sprintf("Unknown column indicator: %d", rc.cols[i].ind))
		}
	}

	return nil
}

func ociGetError(err unsafe.Pointer) error {
	var errcode C.sb4
	var errbuff [512]C.char
	C.OCIErrorGet(
		err,
		1,
		nil,
		&errcode,
		(*C.OraText)(unsafe.Pointer(&errbuff[0])),
		512,
		C.OCI_HTYPE_ERROR)
	s := C.GoString(&errbuff[0])
	//println(s)
	return errors.New(s)
}
<commit_msg>Adding string truncating logic<commit_after>package oci8

/*
#include <oci.h>
#include <stdlib.h>
#include <string.h>

#cgo pkg-config: oci8
*/
import "C"
import (
	"database/sql"
	"database/sql/driver"
	"errors"
	"fmt"
	"io"
	"strings"
	"unsafe"
)

func init() {
	sql.Register("oci8", &OCI8Driver{})
}

type OCI8Driver struct {
}

type OCI8Conn struct {
	svc unsafe.Pointer
	env unsafe.Pointer
	err unsafe.Pointer
}

type OCI8Tx struct {
	c *OCI8Conn
}

func (tx *OCI8Tx) Commit() error {
	if err := tx.c.exec("COMMIT"); err != nil {
		return err
	}
	return nil
}

func (tx *OCI8Tx) Rollback() error {
	if err := tx.c.exec("ROLLBACK"); err != nil {
		return err
	}
	return nil
}

func (c *OCI8Conn) exec(cmd string) error {
	stmt, err := c.Prepare(cmd)
	if err == nil {
		defer stmt.Close()
		_, err = stmt.Exec(nil)
	}
	return err
}

func (c *OCI8Conn) Begin() (driver.Tx, error) {
	if err := c.exec("BEGIN"); err != nil {
		return nil, err
	}
	return &OCI8Tx{c}, nil
}

func (d *OCI8Driver) Open(dsn string) (driver.Conn, error) {
	var conn OCI8Conn
	token := strings.SplitN(dsn, "@", 2)
	userpass := strings.SplitN(token[0], "/", 2)

	rv := C.OCIInitialize(
		C.OCI_DEFAULT,
		nil,
		nil,
		nil,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	rv = C.OCIEnvInit(
		(**C.OCIEnv)(unsafe.Pointer(&conn.env)),
		C.OCI_DEFAULT,
		0,
		nil)

	rv = C.OCIHandleAlloc(
		conn.env,
		&conn.err,
		C.OCI_HTYPE_ERROR,
		0,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	var phost *C.char
	phostlen := C.size_t(0)
	if len(token) > 1 {
		phost = C.CString(token[1])
		defer C.free(unsafe.Pointer(phost))
		phostlen = C.strlen(phost)
	}
	puser := C.CString(userpass[0])
	defer C.free(unsafe.Pointer(puser))
	ppass := C.CString(userpass[1])
	defer C.free(unsafe.Pointer(ppass))

	rv = C.OCILogon(
		(*C.OCIEnv)(conn.env),
		(*C.OCIError)(conn.err),
		(**C.OCIServer)(unsafe.Pointer(&conn.svc)),
		(*C.OraText)(unsafe.Pointer(puser)),
		C.ub4(C.strlen(puser)),
		(*C.OraText)(unsafe.Pointer(ppass)),
		C.ub4(C.strlen(ppass)),
		(*C.OraText)(unsafe.Pointer(phost)),
		C.ub4(phostlen))
	if rv == C.OCI_ERROR {
		return nil, ociGetError(conn.err)
	}

	return &conn, nil
}

func (c *OCI8Conn) Close() error {
	rv := C.OCILogoff(
		(*C.OCIServer)(c.svc),
		(*C.OCIError)(c.err))
	if rv == C.OCI_ERROR {
		return ociGetError(c.err)
	}

	C.OCIHandleFree(
		c.env,
		C.OCI_HTYPE_ENV)

	c.svc = nil
	c.env = nil
	c.err = nil
	return nil
}

type OCI8Stmt struct {
	c      *OCI8Conn
	s      unsafe.Pointer
	closed bool
}

func (c *OCI8Conn) Prepare(query string) (driver.Stmt, error) {
	pquery := C.CString(query)
	defer C.free(unsafe.Pointer(pquery))
	var s unsafe.Pointer

	rv := C.OCIHandleAlloc(
		c.env,
		&s,
		C.OCI_HTYPE_STMT,
		0,
		nil)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(c.err)
	}

	rv = C.OCIStmtPrepare(
		(*C.OCIStmt)(s),
		(*C.OCIError)(c.err),
		(*C.OraText)(unsafe.Pointer(pquery)),
		C.ub4(C.strlen(pquery)),
		C.ub4(C.OCI_NTV_SYNTAX),
		C.ub4(C.OCI_DEFAULT))
	if rv == C.OCI_ERROR {
		return nil, ociGetError(c.err)
	}

	return &OCI8Stmt{c: c, s: s}, nil
}

func (s *OCI8Stmt) Close() error {
	if s.closed {
		return nil
	}
	s.closed = true

	C.OCIHandleFree(
		s.s,
		C.OCI_HTYPE_STMT)
	s.s = nil

	return nil
}

func (s *OCI8Stmt) NumInput() int {
	var num C.int
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&num),
		nil,
		C.OCI_ATTR_BIND_COUNT,
		(*C.OCIError)(s.c.err))
	return int(num)
}

func (s *OCI8Stmt) bind(args []driver.Value) error {
	if args == nil {
		return nil
	}

	var bp *C.OCIBind
	for i, v := range args {
		b := []byte(fmt.Sprintf("%v", v))
		b = append(b, 0)
		rv := C.OCIBindByPos(
			(*C.OCIStmt)(s.s),
			&bp,
			(*C.OCIError)(s.c.err),
			C.ub4(i+1),
			unsafe.Pointer(&b[0]),
			C.sb4(len(b)),
			C.SQLT_STR,
			nil,
			nil,
			nil,
			0,
			nil,
			C.OCI_DEFAULT)

		if rv == C.OCI_ERROR {
			return ociGetError(s.c.err)
		}
	}
	return nil
}

func (s *OCI8Stmt) Query(args []driver.Value) (driver.Rows, error) {
	if err := s.bind(args); err != nil {
		return nil, err
	}

	var t C.int
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_STMT_TYPE,
		(*C.OCIError)(s.c.err))
	iter := C.ub4(1)
	if t == C.OCI_STMT_SELECT {
		iter = 0
	}

	rv := C.OCIStmtExecute(
		(*C.OCIServer)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		iter,
		0,
		nil,
		nil,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}

	var rc C.ub2
	C.OCIAttrGet(
		s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&rc),
		nil,
		C.OCI_ATTR_PARAM_COUNT,
		(*C.OCIError)(s.c.err))

	oci8cols := make([]oci8col, int(rc))
	for i := 0; i < int(rc); i++ {
		var p unsafe.Pointer
		var np *C.char
		var ns C.ub4
		var tp C.ub2
		var lp C.ub2
		C.OCIParamGet(
			s.s,
			C.OCI_HTYPE_STMT,
			(*C.OCIError)(s.c.err),
			(*unsafe.Pointer)(unsafe.Pointer(&p)),
			C.ub4(i+1))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&tp),
			nil,
			C.OCI_ATTR_DATA_TYPE,
			(*C.OCIError)(s.c.err))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&np),
			&ns,
			C.OCI_ATTR_NAME,
			(*C.OCIError)(s.c.err))
		C.OCIAttrGet(
			p,
			C.OCI_DTYPE_PARAM,
			unsafe.Pointer(&lp),
			nil,
			C.OCI_ATTR_DATA_SIZE,
			(*C.OCIError)(s.c.err))
		oci8cols[i].name = string((*[1 << 30]byte)(unsafe.Pointer(np))[0:int(ns)])
		oci8cols[i].kind = int(tp)
		oci8cols[i].size = int(lp)
		oci8cols[i].pbuf = make([]byte, int(lp)+1)

		var defp *C.OCIDefine
		rv = C.OCIDefineByPos(
			(*C.OCIStmt)(s.s),
			&defp,
			(*C.OCIError)(s.c.err),
			C.ub4(i+1),
			unsafe.Pointer(&oci8cols[i].pbuf[0]),
			C.sb4(lp+1),
			C.SQLT_CHR,
			unsafe.Pointer(&oci8cols[i].ind),
			&oci8cols[i].rlen,
			nil,
			C.OCI_DEFAULT)
		if rv == C.OCI_ERROR {
			return nil, ociGetError(s.c.err)
		}
	}
	return &OCI8Rows{s, oci8cols, false}, nil
}

type OCI8Result struct {
	s *OCI8Stmt
}

func (r *OCI8Result) LastInsertId() (int64, error) {
	var t C.ub4
	rv := C.OCIAttrGet(
		r.s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_ROWID,
		(*C.OCIError)(r.s.c.err))
	if rv == C.OCI_ERROR {
		return 0, ociGetError(r.s.c.err)
	}
	return int64(t), nil
}

func (r *OCI8Result) RowsAffected() (int64, error) {
	var t C.ub4
	rv := C.OCIAttrGet(
		r.s.s,
		C.OCI_HTYPE_STMT,
		unsafe.Pointer(&t),
		nil,
		C.OCI_ATTR_ROW_COUNT,
		(*C.OCIError)(r.s.c.err))
	if rv == C.OCI_ERROR {
		return 0, ociGetError(r.s.c.err)
	}
	return int64(t), nil
}

func (s *OCI8Stmt) Exec(args []driver.Value) (driver.Result, error) {
	if err := s.bind(args); err != nil {
		return nil, err
	}

	rv := C.OCIStmtExecute(
		(*C.OCIServer)(s.c.svc),
		(*C.OCIStmt)(s.s),
		(*C.OCIError)(s.c.err),
		1,
		0,
		nil,
		nil,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return nil, ociGetError(s.c.err)
	}
	return &OCI8Result{s}, nil
}

type oci8col struct {
	name string
	kind int
	size int
	ind  int
	rlen C.ub2
	pbuf []byte
}

type OCI8Rows struct {
	s    *OCI8Stmt
	cols []oci8col
	e    bool
}

func (rc *OCI8Rows) Close() error {
	return rc.s.Close()
}

func (rc *OCI8Rows) Columns() []string {
	cols := make([]string, len(rc.cols))
	for i, col := range rc.cols {
		cols[i] = col.name
	}
	return cols
}

func (rc *OCI8Rows) Next(dest []driver.Value) error {
	rv := C.OCIStmtFetch(
		(*C.OCIStmt)(rc.s.s),
		(*C.OCIError)(rc.s.c.err),
		1,
		C.OCI_FETCH_NEXT,
		C.OCI_DEFAULT)
	if rv == C.OCI_ERROR {
		return ociGetError(rc.s.c.err)
	}

	if rv == C.OCI_NO_DATA {
		return io.EOF
	}

	for i := range dest {
		switch {
		case rc.cols[i].ind == -1: //Null
			dest[i] = nil
		case rc.cols[i].ind == 0: //Normal
			dest[i] = string(rc.cols[i].pbuf)[0:rc.cols[i].rlen]
		case rc.cols[i].ind == -2 || //Field longer than type (truncated)
			rc.cols[i].ind > 0: //Field longer than type (truncated). Value is original length.
			dest[i] = string(rc.cols[i].pbuf)
		default:
			return errors.New(fmt.Sprintf("Unknown column indicator: %d", rc.cols[i].ind))
		}
	}

	return nil
}

func ociGetError(err unsafe.Pointer) error {
	var errcode C.sb4
	var errbuff [512]C.char
	C.OCIErrorGet(
		err,
		1,
		nil,
		&errcode,
		(*C.OraText)(unsafe.Pointer(&errbuff[0])),
		512,
		C.OCI_HTYPE_ERROR)
	s := C.GoString(&errbuff[0])
	//println(s)
	return errors.New(s)
}
<|endoftext|>


<commit_before>package endpoint

import (
	"strings"
//	"fmt"
//	"os"
)

type path struct {
	raw string
	pos int
	segments []string
}

func newPath(str string) *path {
	p := &path{raw: str, pos: 0}
	if str == "" || str == "/" {
		p.segments = []string{""}
	} else {
		p.segments = strings.Split(str, "/")
	}
	return p
}

func (p *path) next() *string {
	if p.pos + 1 >= len(p.segments) {
		return nil
	}
	p.pos++
	return &p.segments[p.pos]
}

//func (p *path) dump() {
//	util.Dumpl("path", p.raw)
//	util.Dumpl("pos", p.pos)
//	if p.segments == nil {
//		fmt.Println("path not parsed")
//	} else {
//		fmt.Println("path segments =")
//		for i := 0; i < len(p.segments); i++ {
//			fmt.Fprintln(os.Stdout, fmt.Sprintf(" [%d] => '%s'", i, p.segments[i]))
//		}
//	}
//}
<commit_msg>cleanup<commit_after>package endpoint

import "strings"

type path struct {
	raw string
	pos int
	segments []string
}

func newPath(str string) *path {
	p := &path{raw: str, pos: 0}
	if str == "" || str == "/" {
		p.segments = []string{""}
	} else {
		p.segments = strings.Split(str, "/")
	}
	return p
}

func (p *path) next() *string {
	if p.pos + 1 >= len(p.segments) {
		return nil
	}
	p.pos++
	return &p.segments[p.pos]
}
<|endoftext|>


<commit_before>package weave

import (
	"code.google.com/p/gopacket/pcap"
)

type PcapIO struct {
	handle *pcap.Handle
}

func NewPcapIO(ifName string, bufSz int) (PacketSourceSink, error) {
	pio, err := newPcapIO(ifName, true, 65535, bufSz)
	if err != nil {
		return pio, err
	}

	// Under Linux, libpcap implements the SetDirection filtering
	// in userspace.  So set a BPF filter to discard outbound
	// packets inside the kernel.  We do this here rather than in
	// newPcapIO because libpcap doesn't like this in combination
	// with a 0 snaplen.
	err = pio.handle.SetBPFFilter("inbound")
	return pio, err
}

func NewPcapO(ifName string) (po PacketSink, err error) {
	po, err = newPcapIO(ifName, false, 0, 0)
	return
}

func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *PcapIO, err error) {
	inactive, err := pcap.NewInactiveHandle(ifName)
	if err != nil {
		return
	}
	defer inactive.CleanUp()
	if err = inactive.SetPromisc(promisc); err != nil {
		return
	}
	if err = inactive.SetSnapLen(snaplen); err != nil {
		return
	}
	if err = inactive.SetTimeout(-1); err != nil {
		return
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		return
	}
	if err = inactive.SetBufferSize(bufSz); err != nil {
		return
	}
	active, err := inactive.Activate()
	if err != nil {
		return
	}
	if err = active.SetDirection(pcap.DirectionIn); err != nil {
		return
	}
	return &PcapIO{handle: active}, nil
}

func (pi *PcapIO) ReadPacket() (data []byte, err error) {
	data, _, err = pi.handle.ZeroCopyReadPacketData()
	return
}

func (po *PcapIO) WritePacket(data []byte) error {
	return po.handle.WritePacketData(data)
}
<commit_msg>don't set pcap timeout, to prevent cpu churn pcap timeouts are a mystery. Setting the timeout to -1 used to reduce latency, but that was before we started setting immediate mode. And it turns out that with that timeout, pcap chews through a lot of CPU polling its file descriptor, checking timers, etc.<commit_after>package weave

import (
	"code.google.com/p/gopacket/pcap"
)

type PcapIO struct {
	handle *pcap.Handle
}

func NewPcapIO(ifName string, bufSz int) (PacketSourceSink, error) {
	pio, err := newPcapIO(ifName, true, 65535, bufSz)
	if err != nil {
		return pio, err
	}

	// Under Linux, libpcap implements the SetDirection filtering
	// in userspace.  So set a BPF filter to discard outbound
	// packets inside the kernel.  We do this here rather than in
	// newPcapIO because libpcap doesn't like this in combination
	// with a 0 snaplen.
	err = pio.handle.SetBPFFilter("inbound")
	return pio, err
}

func NewPcapO(ifName string) (po PacketSink, err error) {
	po, err = newPcapIO(ifName, false, 0, 0)
	return
}

func newPcapIO(ifName string, promisc bool, snaplen int, bufSz int) (handle *PcapIO, err error) {
	inactive, err := pcap.NewInactiveHandle(ifName)
	if err != nil {
		return
	}
	defer inactive.CleanUp()
	if err = inactive.SetPromisc(promisc); err != nil {
		return
	}
	if err = inactive.SetSnapLen(snaplen); err != nil {
		return
	}
	if err = inactive.SetImmediateMode(true); err != nil {
		return
	}
	if err = inactive.SetBufferSize(bufSz); err != nil {
		return
	}
	active, err := inactive.Activate()
	if err != nil {
		return
	}
	if err = active.SetDirection(pcap.DirectionIn); err != nil {
		return
	}
	return &PcapIO{handle: active}, nil
}

func (pi *PcapIO) ReadPacket() (data []byte, err error) {
	data, _, err = pi.handle.ZeroCopyReadPacketData()
	return
}

func (po *PcapIO) WritePacket(data []byte) error {
	return po.handle.WritePacketData(data)
}
<|endoftext|>


<commit_before>package main

import "fmt"

//import "reflect"
import "time"
import "log"
import "flag"
import "os"
import "strings"
import "database/sql"
import _ "github.com/lib/pq"
import "github.com/joncrlsn/pgutil"
import "github.com/joncrlsn/misc"

const isoFormat = "2006-01-02T15:04:05.000-0700"

/*
 * Queries the given table name and copies the column values to either an INSERT statement or
 * an UPDATE statement.
 *
 * Example: pgcp -U myuser -d mydb INSERT t_user "WHERE user_id < 4"
 */
func main() {
	dbInfo := pgutil.DbInfo{}
	dbInfo.Populate()
	//fmt.Println("dbInfo:", dbInfo)
	//fmt.Println("connection string:", dbInfo.ConnectionString())

	// Remaining args:
	args := flag.Args()
	if len(args) < 2 {
		fmt.Fprintln(os.Stderr, "Missing some arguments")
		usage()
	}

	// genType
	genType := strings.ToUpper(args[0])
	if genType != "INSERT" && genType != "UPDATE" {
		fmt.Fprintf(os.Stderr, "Invalid generation type: %s.  Requires either INSERT or UPDATE\n", genType)
		usage()
	}

	// tableName
	tableName := args[1]

	// idColumn (UPDATE only) and whereClause
	whereClause := ""
	idCol := ""
	if genType == "INSERT" {
		if len(args) > 2 {
			whereClause = args[2]
		}
	} else {
		if len(args) < 3 {
			fmt.Fprintf(os.Stderr, "UPDATE requires an idColumn.")
			usage()
		}
		idCol = args[2]
		if len(args) > 3 {
			whereClause = args[3]
		}
	}

	if len(whereClause) == 0 {
		// Make sure user intended there to be no where clause
		if !misc.PromptYesNo("Did you intend to have no where clause?", true) {
			os.Exit(1)
		}
	}

	db, err := dbInfo.Open()
	check("opening database", err)

	query := "SELECT * FROM " + tableName + " " + whereClause
	fmt.Println("-- Running query:", query)
	rowChan, columnNames := querySqlValues(db, query)

	for row := range rowChan {
		if genType == "INSERT" {
			generateInsert(tableName, row, columnNames)
		} else {
			generateUpdate(tableName, row, idCol)
		}
	}
}

func generateInsert(tableName string, row map[string]string, colNames []string) {
	fmt.Printf("INSERT INTO %s (", tableName)
	first := true
	for _, name := range colNames {
		//fmt.Println("ix/name:", ix, name)
		if !first {
			fmt.Print(", ")
		}
		fmt.Printf(name)
		first = false
	}
	fmt.Print(") VALUES (")
	first = true
	for _, name := range colNames {
		if !first {
			fmt.Print(", ")
		}
		v := row[name]
		fmt.Printf(v)
		first = false
	}
	fmt.Println(");")
}

func generateUpdate(tableName string, row map[string]string, idCol string) {
	fmt.Printf("UPDATE %s SET ", tableName)
	idVal := ""
	idColFound := false
	first := true
	for k, v := range row {
		if k == idCol {
			idVal = v
			idColFound = true
		} else {
			if !first {
				fmt.Print(", ")
			}
			fmt.Printf("%s=%s", k, v)
			first = false
		}
	}
	if !idColFound {
		log.Fatalf("\nid column not found: %s\n", idCol)
		os.Exit(1)
	}
	fmt.Printf(" WHERE %s=%s", idCol, idVal)
	fmt.Println(";")
}

/*
 * Returns row maps (keyed by the column name) in a channel.
 * Dynamically converts each column value to a SQL string value.
 * See http://stackoverflow.com/questions/23507531/is-golangs-sql-package-incapable-of-ad-hoc-exploratory-queries
 */
func querySqlValues(db *sql.DB, query string) (chan map[string]string, []string) {
	rowChan := make(chan map[string]string)

	rows, err := db.Query(query)
	check("running query", err)
	columnNames, err := rows.Columns()
	check("getting column names", err)

	go func() {

		defer rows.Close()

		vals := make([]interface{}, len(columnNames))
		valPointers := make([]interface{}, len(columnNames))
		// Copy
		for i := 0; i < len(columnNames); i++ {
			valPointers[i] = &vals[i]
		}

		for rows.Next() {
			err = rows.Scan(valPointers...)
			check("scanning a row", err)

			row := make(map[string]string)
			// Convert each cell to a SQL-valid string representation
			for i, valPtr := range vals {
				//fmt.Println(reflect.TypeOf(valPtr))
				switch valueType := valPtr.(type) {
				case nil:
					row[columnNames[i]] = "null"
				case []uint8:
					row[columnNames[i]] = "'" + string(valPtr.([]byte)) + "'"
				case string:
					row[columnNames[i]] = "'" + valPtr.(string) + "'"
				case int64:
					row[columnNames[i]] = fmt.Sprintf("%d", valPtr)
				case float64:
					row[columnNames[i]] = fmt.Sprintf("%f", valPtr)
				case bool:
					row[columnNames[i]] = fmt.Sprintf("%t", valPtr)
				case time.Time:
					row[columnNames[i]] = "'" + valPtr.(time.Time).Format(isoFormat) + "'"
				case fmt.Stringer:
					row[columnNames[i]] = fmt.Sprintf("%v", valPtr)
				default:
					row[columnNames[i]] = fmt.Sprintf("%v", valPtr)
					fmt.Println("Column %s is an unhandled type: %v", columnNames[i], valueType)
				}
			}
			rowChan <- row
		}
		close(rowChan)
	}()
	return rowChan, columnNames
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [database flags] <genType> <tableName> <whereClause> \n", os.Args[0])
	fmt.Fprintln(os.Stderr, `
Copies table data as either INSERT or UPDATE statements.

[database flags]: (optional)
  -U     : postgres user (matches psql flag)
  -h     : database host -- default is localhost (matches psql flag)
  -p     : port.  defaults to 5432 (matches psql flag)
  -d     : database name (matches psql flag)
  -pw    : password for the postgres user (otherwise you'll be prompted)

<genType>     : type of SQL to generate: insert, update

<tableName>   : name of table to be copied (fully or partially)

<whereClause> : specifies which rows to copy. Example: WHERE user_id < 100 AND username IS NOT NULL

Database connection information can be specified in two ways:
  * Environment variables
  * Program flags (overrides environment variables.  See above)
  * ~/.pgpass file (for the password)
  * Note that if password is not specified, you will be prompted.

Optional Environment variables (if program flags are not desirable):
  DBHOST : host name where database is running (default is localhost)
  DBPORT : port database is listening on (default is 5432)
  DBNAME : name of database you want to copy
  DBUSER : user in postgres you'll be executing the queries as
  DBPASS : password for the user
`)

	os.Exit(2)
}

func check(msg string, err error) {
	if err != nil {
		log.Fatal("Error "+msg, err)
	}
}
<commit_msg>Minor text change in warning situation<commit_after>package main

import "fmt"

//import "reflect"
import "time"
import "log"
import "flag"
import "os"
import "strings"
import "database/sql"
import _ "github.com/lib/pq"
import "github.com/joncrlsn/pgutil"
import "github.com/joncrlsn/misc"

const isoFormat = "2006-01-02T15:04:05.000-0700"

/*
 * Queries the given table name and copies the column values to either an INSERT statement or
 * an UPDATE statement.
 *
 * Example: pgcp -U myuser -d mydb INSERT t_user "WHERE user_id < 4"
 */
func main() {
	dbInfo := pgutil.DbInfo{}
	dbInfo.Populate()
	//fmt.Println("dbInfo:", dbInfo)
	//fmt.Println("connection string:", dbInfo.ConnectionString())

	// Remaining args:
	args := flag.Args()
	if len(args) < 2 {
		fmt.Fprintln(os.Stderr, "Missing some arguments")
		usage()
	}

	// genType
	genType := strings.ToUpper(args[0])
	if genType != "INSERT" && genType != "UPDATE" {
		fmt.Fprintf(os.Stderr, "Invalid generation type: %s.  Requires either INSERT or UPDATE\n", genType)
		usage()
	}

	// tableName
	tableName := args[1]

	// idColumn (UPDATE only) and whereClause
	whereClause := ""
	idCol := ""
	if genType == "INSERT" {
		if len(args) > 2 {
			whereClause = args[2]
		}
	} else {
		if len(args) < 3 {
			fmt.Fprintf(os.Stderr, "UPDATE requires an idColumn.")
			usage()
		}
		idCol = args[2]
		if len(args) > 3 {
			whereClause = args[3]
		}
	}

	if len(whereClause) == 0 {
		// Make sure user intended there to be no where clause
		if !misc.PromptYesNo("Did you intend to have no where clause?", true) {
			os.Exit(1)
		}
	}

	db, err := dbInfo.Open()
	check("opening database", err)

	query := "SELECT * FROM " + tableName + " " + whereClause
	fmt.Println("-- Running query:", query)
	rowChan, columnNames := querySqlValues(db, query)

	for row := range rowChan {
		if genType == "INSERT" {
			generateInsert(tableName, row, columnNames)
		} else {
			generateUpdate(tableName, row, idCol)
		}
	}
}

func generateInsert(tableName string, row map[string]string, colNames []string) {
	fmt.Printf("INSERT INTO %s (", tableName)
	first := true
	for _, name := range colNames {
		//fmt.Println("ix/name:", ix, name)
		if !first {
			fmt.Print(", ")
		}
		fmt.Printf(name)
		first = false
	}
	fmt.Print(") VALUES (")
	first = true
	for _, name := range colNames {
		if !first {
			fmt.Print(", ")
		}
		v := row[name]
		fmt.Printf(v)
		first = false
	}
	fmt.Println(");")
}

func generateUpdate(tableName string, row map[string]string, idCol string) {
	fmt.Printf("UPDATE %s SET ", tableName)
	idVal := ""
	idColFound := false
	first := true
	for k, v := range row {
		if k == idCol {
			idVal = v
			idColFound = true
		} else {
			if !first {
				fmt.Print(", ")
			}
			fmt.Printf("%s=%s", k, v)
			first = false
		}
	}
	if !idColFound {
		log.Fatalf("\nid column not found: %s\n", idCol)
		os.Exit(1)
	}
	fmt.Printf(" WHERE %s=%s", idCol, idVal)
	fmt.Println(";")
}

/*
 * Returns row maps (keyed by the column name) in a channel.
 * Dynamically converts each column value to a SQL string value.
 * See http://stackoverflow.com/questions/23507531/is-golangs-sql-package-incapable-of-ad-hoc-exploratory-queries
 */
func querySqlValues(db *sql.DB, query string) (chan map[string]string, []string) {
	rowChan := make(chan map[string]string)

	rows, err := db.Query(query)
	check("running query", err)
	columnNames, err := rows.Columns()
	check("getting column names", err)

	go func() {

		defer rows.Close()

		vals := make([]interface{}, len(columnNames))
		valPointers := make([]interface{}, len(columnNames))
		// Copy
		for i := 0; i < len(columnNames); i++ {
			valPointers[i] = &vals[i]
		}

		for rows.Next() {
			err = rows.Scan(valPointers...)
			check("scanning a row", err)

			row := make(map[string]string)
			// Convert each cell to a SQL-valid string representation
			for i, valPtr := range vals {
				//fmt.Println(reflect.TypeOf(valPtr))
				switch valueType := valPtr.(type) {
				case nil:
					row[columnNames[i]] = "null"
				case []uint8:
					row[columnNames[i]] = "'" + string(valPtr.([]byte)) + "'"
				case string:
					row[columnNames[i]] = "'" + valPtr.(string) + "'"
				case int64:
					row[columnNames[i]] = fmt.Sprintf("%d", valPtr)
				case float64:
					row[columnNames[i]] = fmt.Sprintf("%f", valPtr)
				case bool:
					row[columnNames[i]] = fmt.Sprintf("%t", valPtr)
				case time.Time:
					row[columnNames[i]] = "'" + valPtr.(time.Time).Format(isoFormat) + "'"
				case fmt.Stringer:
					row[columnNames[i]] = fmt.Sprintf("%v", valPtr)
				default:
					row[columnNames[i]] = fmt.Sprintf("%v", valPtr)
					fmt.Println("-- Warning, column %s is an unhandled type: %v", columnNames[i], valueType)
				}
			}
			rowChan <- row
		}
		close(rowChan)
	}()
	return rowChan, columnNames
}

func usage() {
	fmt.Fprintf(os.Stderr, "usage: %s [database flags] <genType> <tableName> <whereClause> \n", os.Args[0])
	fmt.Fprintln(os.Stderr, `
Copies table data as either INSERT or UPDATE statements.

[database flags]: (optional)
  -U     : postgres user (matches psql flag)
  -h     : database host -- default is localhost (matches psql flag)
  -p     : port.  defaults to 5432 (matches psql flag)
  -d     : database name (matches psql flag)
  -pw    : password for the postgres user (otherwise you'll be prompted)

<genType>     : type of SQL to generate: insert, update

<tableName>   : name of table to be copied (fully or partially)

<whereClause> : specifies which rows to copy. Example: WHERE user_id < 100 AND username IS NOT NULL

Database connection information can be specified in two ways:
  * Environment variables
  * Program flags (overrides environment variables.  See above)
  * ~/.pgpass file (for the password)
  * Note that if password is not specified, you will be prompted.

Optional Environment variables (if program flags are not desirable):
  DBHOST : host name where database is running (default is localhost)
  DBPORT : port database is listening on (default is 5432)
  DBNAME : name of database you want to copy
  DBUSER : user in postgres you'll be executing the queries as
  DBPASS : password for the user
`)

	os.Exit(2)
}

func check(msg string, err error) {
	if err != nil {
		log.Fatal("Error "+msg, err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"path/filepath"
	"runtime"
	"strconv"
)

var port = flag.Int("port", 8000, "port number")

func init() {
	flag.Parse()
}

var rootPath = ""

func init() {
	_, path, _, _ := runtime.Caller(0)
	rootPath = filepath.Join(filepath.Dir(path), "..", "public")
}

func main() {
	http.Handle("/", http.FileServer(http.Dir(rootPath)))
	fmt.Printf("http://localhost:%d/\n", *port)
	log.Fatal(http.ListenAndServe("localhost:"+strconv.Itoa(*port), nil))
}
<commit_msg>doc: Avoid using symbolic links in paths<commit_after>// Copyright 2016 Hajime Hoshi
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package main

import (
	"flag"
	"fmt"
	"log"
	"net/http"
	"path/filepath"
	"runtime"
	"strconv"
)

var port = flag.Int("port", 8000, "port number")

func init() {
	flag.Parse()
}

var rootPath = ""

func init() {
	_, path, _, _ := runtime.Caller(0)
	rootPath = filepath.Join(filepath.Dir(path), "..", "..", "docs")
}

func main() {
	http.Handle("/", http.FileServer(http.Dir(rootPath)))
	fmt.Printf("http://localhost:%d/\n", *port)
	log.Fatal(http.ListenAndServe("localhost:"+strconv.Itoa(*port), nil))
}
<|endoftext|>


<commit_before>package procspy

import (
	"net"
	"reflect"
	"testing"
)

func TestProcNet(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
   1: 00000000:006F 00000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 5084 1 ffff8800a6aaf740 100 0 0 10 0
   2: 0100007F:0019 00000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 10550 1 ffff8800a729b780 100 0 0 10 0
   3: A12CF62E:E4D7 57FC1EC0:01BB 01 00000000:00000000 02:000006FA 00000000  1000        0 639474 2 ffff88007e75a740 48 4 26 10 -1
`
	p := NewProcNet([]byte(testString), tcpEstablished)
	expected := []Connection{
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0xa6c0,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         5107,
		},
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0x006f,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         5084,
		},
		{
			LocalAddress:  net.IP([]byte{0x7f, 0x0, 0x0, 0x01}),
			LocalPort:     0x0019,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         10550,
		},
		{
			LocalAddress:  net.IP([]byte{0x2e, 0xf6, 0x2c, 0xa1}),
			LocalPort:     0xe4d7,
			RemoteAddress: net.IP([]byte{0xc0, 0x1e, 0xfc, 0x57}),
			RemotePort:    0x01bb,
			inode:         639474,
		},
	}
	for i := 0; i < 4; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("transport 4 error. Got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestTransport6(t *testing.T) {
	// Abridged copy of my /proc/net/tcp6
	testString := ` sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000000000000000000000000000:19C8 00000000000000000000000000000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 23661201 1 ffff880103fb4800 100 0 0 10 -1
   8: 4500032000BE692B8AE31EBD919D9D10:D61C 5014002A080805400000000015100000:01BB 01 00000000:00000000 02:00000045 00000000  1000        0 36856710 2 ffff88010b796080 22 4 30 8 7
`

	p := NewProcNet([]byte(testString), tcpEstablished)
	expected := []Connection{
		{
			// state:         10,
			LocalAddress:  net.IP(make([]byte, 16)),
			LocalPort:     0x19c8,
			RemoteAddress: net.IP(make([]byte, 16)),
			RemotePort:    0x0,
			// uid:           0,
			inode: 23661201,
		},
		{
			// state: 1,
			LocalAddress: net.IP([]byte{
				0x20, 0x03, 0, 0x45,
				0x2b, 0x69, 0xbe, 0x00,
				0xbd, 0x1e, 0xe3, 0x8a,
				0x10, 0x9d, 0x9d, 0x91,
			}),
			LocalPort: 0xd61c,
			RemoteAddress: net.IP([]byte{
				0x2a, 0x00, 0x14, 0x50,
				0x40, 0x05, 0x08, 0x08,
				0, 0, 0, 0,
				0, 0, 0x10, 0x15,
			}),
			RemotePort: 0x01bb,
			// uid:        1000,
			inode: 36856710,
		},
	}

	for i := 0; i < 2; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestTransportNonsense(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 000000
broken line
`
	p := NewProcNet([]byte(testString), tcpEstablished)
	expected := []Connection{
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0xa6c0,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
		},
	}

	for i := 0; i < 1; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("Got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestProcNetFiltersDuplicates(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
   1: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
`
	p := NewProcNet([]byte(testString), tcpEstablished)
	expected := Connection{
		LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
		LocalPort:     0xa6c0,
		RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
		RemotePort:    0x0,
		inode:         5107,
	}
	have := p.Next()
	want := expected
	if !reflect.DeepEqual(*have, want) {
		t.Errorf("transport 4 error. Got\n%+v\nExpected\n%+v\n", *have, want)
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}
<commit_msg>Fix tests<commit_after>package procspy

import (
	"net"
	"reflect"
	"testing"
)

func TestProcNet(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
   1: 00000000:006F 00000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 5084 1 ffff8800a6aaf740 100 0 0 10 0
   2: 0100007F:0019 00000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 10550 1 ffff8800a729b780 100 0 0 10 0
   3: A12CF62E:E4D7 57FC1EC0:01BB 01 00000000:00000000 02:000006FA 00000000  1000        0 639474 2 ffff88007e75a740 48 4 26 10 -1
`
	p := NewProcNet([]byte(testString))
	expected := []Connection{
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0xa6c0,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         5107,
		},
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0x006f,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         5084,
		},
		{
			LocalAddress:  net.IP([]byte{0x7f, 0x0, 0x0, 0x01}),
			LocalPort:     0x0019,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
			inode:         10550,
		},
		{
			LocalAddress:  net.IP([]byte{0x2e, 0xf6, 0x2c, 0xa1}),
			LocalPort:     0xe4d7,
			RemoteAddress: net.IP([]byte{0xc0, 0x1e, 0xfc, 0x57}),
			RemotePort:    0x01bb,
			inode:         639474,
		},
	}
	for i := 0; i < 4; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("transport 4 error. Got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestTransport6(t *testing.T) {
	// Abridged copy of my /proc/net/tcp6
	testString := ` sl  local_address                         remote_address                        st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000000000000000000000000000:19C8 00000000000000000000000000000000:0000 01 00000000:00000000 00:00000000 00000000     0        0 23661201 1 ffff880103fb4800 100 0 0 10 -1
   8: 4500032000BE692B8AE31EBD919D9D10:D61C 5014002A080805400000000015100000:01BB 01 00000000:00000000 02:00000045 00000000  1000        0 36856710 2 ffff88010b796080 22 4 30 8 7
`

	p := NewProcNet([]byte(testString))
	expected := []Connection{
		{
			// state:         10,
			LocalAddress:  net.IP(make([]byte, 16)),
			LocalPort:     0x19c8,
			RemoteAddress: net.IP(make([]byte, 16)),
			RemotePort:    0x0,
			// uid:           0,
			inode: 23661201,
		},
		{
			// state: 1,
			LocalAddress: net.IP([]byte{
				0x20, 0x03, 0, 0x45,
				0x2b, 0x69, 0xbe, 0x00,
				0xbd, 0x1e, 0xe3, 0x8a,
				0x10, 0x9d, 0x9d, 0x91,
			}),
			LocalPort: 0xd61c,
			RemoteAddress: net.IP([]byte{
				0x2a, 0x00, 0x14, 0x50,
				0x40, 0x05, 0x08, 0x08,
				0, 0, 0, 0,
				0, 0, 0x10, 0x15,
			}),
			RemotePort: 0x01bb,
			// uid:        1000,
			inode: 36856710,
		},
	}

	for i := 0; i < 2; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestTransportNonsense(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 000000
broken line
`
	p := NewProcNet([]byte(testString))
	expected := []Connection{
		{
			LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
			LocalPort:     0xa6c0,
			RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
			RemotePort:    0x0,
		},
	}

	for i := 0; i < 1; i++ {
		have := p.Next()
		want := expected[i]
		if !reflect.DeepEqual(*have, want) {
			t.Errorf("Got\n%+v\nExpected\n%+v\n", *have, want)
		}
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}

func TestProcNetFiltersDuplicates(t *testing.T) {
	testString := `  sl  local_address rem_address   st tx_queue rx_queue tr tm->when retrnsmt   uid  timeout Inode
   0: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
   1: 00000000:A6C0 00000000:0000 01 00000000:00000000 00:00000000 00000000   105        0 5107 1 ffff8800a6aaf040 100 0 0 10 0
`
	p := NewProcNet([]byte(testString))
	expected := Connection{
		LocalAddress:  net.IP([]byte{0, 0, 0, 0}),
		LocalPort:     0xa6c0,
		RemoteAddress: net.IP([]byte{0, 0, 0, 0}),
		RemotePort:    0x0,
		inode:         5107,
	}
	have := p.Next()
	want := expected
	if !reflect.DeepEqual(*have, want) {
		t.Errorf("transport 4 error. Got\n%+v\nExpected\n%+v\n", *have, want)
	}
	if got := p.Next(); got != nil {
		t.Errorf("p.Next() wasn't empty")
	}

}
<|endoftext|>


<commit_before>package main

import (
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"

	"github.com/votinginfoproject/sms-web/env"
	"github.com/votinginfoproject/sms-web/queue"
	"github.com/votinginfoproject/sms-web/routes"
)

func main() {
	env.Load()

	procs, err := strconv.Atoi(os.Getenv("PROCS"))
	if err != nil {
		log.Fatal("[ERROR] you must specify procs in the .env file")
	}
	runtime.GOMAXPROCS(procs)

	q := queue.New()
	log.Panic(http.ListenAndServe(":8080", routes.New(q)))
}
<commit_msg>add log for server startup<commit_after>package main

import (
	"log"
	"net/http"
	"os"
	"runtime"
	"strconv"

	"github.com/votinginfoproject/sms-web/env"
	"github.com/votinginfoproject/sms-web/queue"
	"github.com/votinginfoproject/sms-web/routes"
)

func main() {
	env.Load()

	procs, err := strconv.Atoi(os.Getenv("PROCS"))
	if err != nil {
		log.Fatal("[ERROR] you must specify procs in the .env file")
	}
	runtime.GOMAXPROCS(procs)

	q := queue.New()
	log.Print("[INFO] starting server on port 8080")
	log.Panic(http.ListenAndServe(":8080", routes.New(q)))
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backup

import (
	"fmt"
	"github.com/jacobsa/comeback/blob"
	"io"
	"io/ioutil"
)

// An object that knows how to save files to some underlying storage.
type FileSaver interface {
	// Save the contents of the supplied reader to underlying storage, returning
	// a list of scores of blobs that should be concatenated in order to recover
	// its contents.
	Save(r io.Reader) (scores []blob.Score, err error)
}

// Create a file saver that uses the supplied blob store, splitting files into
// chunks of the specified size.
func NewFileSaver(store blob.Store, chunkSize uint32) (FileSaver, error) {
	if chunkSize == 0 {
		return nil, fmt.Errorf("Chunk size must be positive.")
	}

	return &fileSaver{blobStore: store, chunkSize: chunkSize}, nil
}

type fileSaver struct {
	blobStore blob.Store
	chunkSize uint32
}

// Read 16 MiB from the supplied reader, returning less iff the reader returns
// an error (including EOF). Do not treat EOF as an error condition.
func getChunk(r io.Reader, chunkSize uint32) ([]byte, error) {
	r = io.LimitReader(r, int64(chunkSize))
	return ioutil.ReadAll(r)
}

func (s *fileSaver) Save(r io.Reader) (scores []blob.Score, err error) {
	// Turn the file into chunks, saving each to the blob store.
	scores = []blob.Score{}
	for {
		chunk, err := getChunk(r, s.chunkSize)
		if err != nil {
			return nil, fmt.Errorf("Reading chunk: %v", err)
		}

		// Are we done?
		if len(chunk) == 0 {
			break
		}

		// Store the chunk.
		score, err := s.blobStore.Store(chunk)
		if err != nil {
			return nil, fmt.Errorf("Storing chunk: %v", err)
		}

		scores = append(scores, score)
	}

	return scores, nil
}
<commit_msg>Added a finalizer stub.<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package backup

import (
	"fmt"
	"github.com/jacobsa/comeback/blob"
	"io"
	"io/ioutil"
	"runtime"
)

// An object that knows how to save files to some underlying storage.
type FileSaver interface {
	// Save the contents of the supplied reader to underlying storage, returning
	// a list of scores of blobs that should be concatenated in order to recover
	// its contents.
	Save(r io.Reader) (scores []blob.Score, err error)
}

// Create a file saver that uses the supplied blob store, splitting files into
// chunks of the specified size.
func NewFileSaver(store blob.Store, chunkSize uint32) (FileSaver, error) {
	if chunkSize == 0 {
		return nil, fmt.Errorf("Chunk size must be positive.")
	}

	saver := &fileSaver{blobStore: store, chunkSize: chunkSize}
	startWorkers(saver)
	runtime.SetFinalizer(saver, stopWorkers)

	return saver, nil
}

type fileSaver struct {
	blobStore blob.Store
	chunkSize uint32
}

func startWorkers(f *fileSaver) {
}

func stopWorkers(f *fileSaver) {
}

// Read 16 MiB from the supplied reader, returning less iff the reader returns
// an error (including EOF). Do not treat EOF as an error condition.
func getChunk(r io.Reader, chunkSize uint32) ([]byte, error) {
	r = io.LimitReader(r, int64(chunkSize))
	return ioutil.ReadAll(r)
}

func (s *fileSaver) Save(r io.Reader) (scores []blob.Score, err error) {
	// Turn the file into chunks, saving each to the blob store.
	scores = []blob.Score{}
	for {
		chunk, err := getChunk(r, s.chunkSize)
		if err != nil {
			return nil, fmt.Errorf("Reading chunk: %v", err)
		}

		// Are we done?
		if len(chunk) == 0 {
			break
		}

		// Store the chunk.
		score, err := s.blobStore.Store(chunk)
		if err != nil {
			return nil, fmt.Errorf("Storing chunk: %v", err)
		}

		scores = append(scores, score)
	}

	return scores, nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"os"
	"strings"
	"time"

	"github.com/bwmarrin/discordgo"
)

func init() {
	flag.StringVar(&token, "t", "", "Bot Token")
	flag.Parse()
}

var token string
var buffer = make([][]byte, 0)

func main() {
	if token == "" {
		fmt.Println("No token provided. Please run: airhorn -t <bot token>")
		return
	}

	// Load the sound file.
	err := loadSound()
	if err != nil {
		fmt.Println("Error loading sound: ", err)
		fmt.Println("Please copy $GOPATH/src/github.com/bwmarrin/examples/airhorn/airhorn.dca to this directory.")
		return
	}

	// Create a new Discord session using the provided bot token.
	dg, err := discordgo.New("Bot " + token)
	if err != nil {
		fmt.Println("Error creating Discord session: ", err)
		return
	}

	// Register ready as a callback for the ready events.
	dg.AddHandler(ready)

	// Register messageCreate as a callback for the messageCreate events.
	dg.AddHandler(messageCreate)

	// Register guildCreate as a callback for the guildCreate events.
	dg.AddHandler(guildCreate)

	// Open the websocket and begin listening.
	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening Discord session: ", err)
	}

	fmt.Println("Airhorn is now running.  Press CTRL-C to exit.")
	// Simple way to keep program running until CTRL-C is pressed.
	<-make(chan struct{})
	return
}

func ready(s *discordgo.Session, event *discordgo.Ready) {
	// Set the playing status.
	_ = s.UpdateStatus(0, "!airhorn")
}

// This function will be called (due to AddHandler above) every time a new
// message is created on any channel that the autenticated bot has access to.
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
	if strings.HasPrefix(m.Content, "!airhorn") {
		// Find the channel that the message came from.
		c, err := s.State.Channel(m.ChannelID)
		if err != nil {
			// Could not find channel.
			return
		}

		// Find the guild for that channel.
		g, err := s.State.Guild(c.GuildID)
		if err != nil {
			// Could not find guild.
			return
		}

		// Look for the message sender in that guilds current voice states.
		for _, vs := range g.VoiceStates {
			if vs.UserID == m.Author.ID {
				err = playSound(s, g.ID, vs.ChannelID)
				if err != nil {
					fmt.Println("Error playing sound:", err)
				}

				return
			}
		}
	}
}

// This function will be called (due to AddHandler above) every time a new
// guild is joined.
func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {
	if event.Guild.Unavailable {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			_, _ = s.ChannelMessageSend(channel.ID, "Airhorn is ready! Type !airhorn while in a voice channel to play a sound.")
			return
		}
	}
}

// loadSound attempts to load an encoded sound file from disk.
func loadSound() error {
	file, err := os.Open("airhorn.dca")

	if err != nil {
		fmt.Println("Error opening dca file :", err)
		return err
	}

	var opuslen int16

	for {
		// Read opus frame length from dca file.
		err = binary.Read(file, binary.LittleEndian, &opuslen)

		// If this is the end of the file, just return.
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			err := file.Close()
			if err != nil {
				return err
			}
			return nil
		}

		if err != nil {
			fmt.Println("Error reading from dca file :", err)
			return err
		}

		// Read encoded pcm from dca file.
		InBuf := make([]byte, opuslen)
		err = binary.Read(file, binary.LittleEndian, &InBuf)

		// Should not be any end of file errors
		if err != nil {
			fmt.Println("Error reading from dca file :", err)
			return err
		}

		// Append encoded pcm data to the buffer.
		buffer = append(buffer, InBuf)
	}
}

// playSound plays the current buffer to the provided channel.
func playSound(s *discordgo.Session, guildID, channelID string) (err error) {
	// Join the provided voice channel.
	vc, err := s.ChannelVoiceJoin(guildID, channelID, false, true)
	if err != nil {
		return err
	}

	// Sleep for a specified amount of time before playing the sound
	time.Sleep(250 * time.Millisecond)

	// Start speaking.
	_ = vc.Speaking(true)

	// Send the buffer data.
	for _, buff := range buffer {
		vc.OpusSend <- buff
	}

	// Stop speaking
	_ = vc.Speaking(false)

	// Sleep for a specificed amount of time before ending.
	time.Sleep(250 * time.Millisecond)

	// Disconnect from the provided voice channel.
	_ = vc.Disconnect()

	return nil
}
<commit_msg>Clean up comments, better blocking code.<commit_after>package main

import (
	"encoding/binary"
	"flag"
	"fmt"
	"io"
	"os"
	"os/signal"
	"strings"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
)

func init() {
	flag.StringVar(&token, "t", "", "Bot Token")
	flag.Parse()
}

var token string
var buffer = make([][]byte, 0)

func main() {

	if token == "" {
		fmt.Println("No token provided. Please run: airhorn -t <bot token>")
		return
	}

	// Load the sound file.
	err := loadSound()
	if err != nil {
		fmt.Println("Error loading sound: ", err)
		fmt.Println("Please copy $GOPATH/src/github.com/bwmarrin/examples/airhorn/airhorn.dca to this directory.")
		return
	}

	// Create a new Discord session using the provided bot token.
	dg, err := discordgo.New("Bot " + token)
	if err != nil {
		fmt.Println("Error creating Discord session: ", err)
		return
	}

	// Register ready as a callback for the ready events.
	dg.AddHandler(ready)

	// Register messageCreate as a callback for the messageCreate events.
	dg.AddHandler(messageCreate)

	// Register guildCreate as a callback for the guildCreate events.
	dg.AddHandler(guildCreate)

	// Open the websocket and begin listening.
	err = dg.Open()
	if err != nil {
		fmt.Println("Error opening Discord session: ", err)
	}

	// Wait here until CTRL-C or other term signal is received.
	fmt.Println("Airhorn is now running.  Press CTRL-C to exit.")
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt, os.Kill)
	<-sc

	// Cleanly close down the Discord session.
	dg.Close()
}

// This function will be called (due to AddHandler above) when the bot receives
// the "ready" event from Discord.
func ready(s *discordgo.Session, event *discordgo.Ready) {

	// Set the playing status.
	s.UpdateStatus(0, "!airhorn")
}

// This function will be called (due to AddHandler above) every time a new
// message is created on any channel that the autenticated bot has access to.
func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {

	// Ignore all messages created by the bot itself
	// This isn't required in this specific example but it's a good practice.
	if m.Author.ID == s.State.User.ID {
		return
	}

	// check if the message is "!airhorn"
	if strings.HasPrefix(m.Content, "!airhorn") {

		// Find the channel that the message came from.
		c, err := s.State.Channel(m.ChannelID)
		if err != nil {
			// Could not find channel.
			return
		}

		// Find the guild for that channel.
		g, err := s.State.Guild(c.GuildID)
		if err != nil {
			// Could not find guild.
			return
		}

		// Look for the message sender in that guild's current voice states.
		for _, vs := range g.VoiceStates {
			if vs.UserID == m.Author.ID {
				err = playSound(s, g.ID, vs.ChannelID)
				if err != nil {
					fmt.Println("Error playing sound:", err)
				}

				return
			}
		}
	}
}

// This function will be called (due to AddHandler above) every time a new
// guild is joined.
func guildCreate(s *discordgo.Session, event *discordgo.GuildCreate) {

	if event.Guild.Unavailable {
		return
	}

	for _, channel := range event.Guild.Channels {
		if channel.ID == event.Guild.ID {
			_, _ = s.ChannelMessageSend(channel.ID, "Airhorn is ready! Type !airhorn while in a voice channel to play a sound.")
			return
		}
	}
}

// loadSound attempts to load an encoded sound file from disk.
func loadSound() error {

	file, err := os.Open("airhorn.dca")
	if err != nil {
		fmt.Println("Error opening dca file :", err)
		return err
	}

	var opuslen int16

	for {
		// Read opus frame length from dca file.
		err = binary.Read(file, binary.LittleEndian, &opuslen)

		// If this is the end of the file, just return.
		if err == io.EOF || err == io.ErrUnexpectedEOF {
			err := file.Close()
			if err != nil {
				return err
			}
			return nil
		}

		if err != nil {
			fmt.Println("Error reading from dca file :", err)
			return err
		}

		// Read encoded pcm from dca file.
		InBuf := make([]byte, opuslen)
		err = binary.Read(file, binary.LittleEndian, &InBuf)

		// Should not be any end of file errors
		if err != nil {
			fmt.Println("Error reading from dca file :", err)
			return err
		}

		// Append encoded pcm data to the buffer.
		buffer = append(buffer, InBuf)
	}
}

// playSound plays the current buffer to the provided channel.
func playSound(s *discordgo.Session, guildID, channelID string) (err error) {

	// Join the provided voice channel.
	vc, err := s.ChannelVoiceJoin(guildID, channelID, false, true)
	if err != nil {
		return err
	}

	// Sleep for a specified amount of time before playing the sound
	time.Sleep(250 * time.Millisecond)

	// Start speaking.
	vc.Speaking(true)

	// Send the buffer data.
	for _, buff := range buffer {
		vc.OpusSend <- buff
	}

	// Stop speaking
	vc.Speaking(false)

	// Sleep for a specificed amount of time before ending.
	time.Sleep(250 * time.Millisecond)

	// Disconnect from the provided voice channel.
	vc.Disconnect()

	return nil
}
<|endoftext|>


<commit_before>package concordances

import (
	"fmt"

	"github.com/Financial-Times/neo-model-utils-go/mapper"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/jmcvetta/neoism"
	log "github.com/sirupsen/logrus"
)

// Driver interface
type Driver interface {
	ReadByConceptID(ids []string) (concordances Concordances, found bool, err error)
	ReadByAuthority(authority string, ids []string) (concordances Concordances, found bool, err error)
	CheckConnectivity() error
}

// CypherDriver struct
type CypherDriver struct {
	conn neoutils.NeoConnection
	env  string
}

//NewCypherDriver instantiate driver
func NewCypherDriver(conn neoutils.NeoConnection, env string) CypherDriver {
	return CypherDriver{conn, env}
}

// CheckConnectivity tests neo4j by running a simple cypher query
func (pcw CypherDriver) CheckConnectivity() error {
	return neoutils.Check(pcw.conn)
}

type neoReadStruct struct {
	UUID                string        `json:"UUID"`
	PrefUUID            string        `json:"prefUUID"`
	NewModelTypes       []string      `json:"newModelTypes"`
	NewModelIdentifiers neoIdentifier `json:"newModelIdentifiers"`
	OldModelTypes       []string      `json:"oldModelTypes"`
	OldModelIdentifiers neoIdentifier `json:"oldModelIdentifiers"`
}

type neoIdentifier struct {
	Labels []string `json:"labels"`
	Value  string   `json:"value"`
}

func (pcw CypherDriver) ReadByConceptID(identifiers []string) (concordances Concordances, found bool, err error) {
	results := []neoReadStruct{}
	query := &neoism.CypherQuery{
		Statement: `
		MATCH (p:Concept)<-[:IDENTIFIES]-(i:UPPIdentifier)
		WHERE i.value in {identifiers}
		MATCH (p:Concept)<-[:IDENTIFIES]-(ids:Identifier)
		WHERE NOT ids:UPPIdentifier
        OPTIONAL MATCH (p:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        OPTIONAL MATCH (leafNode:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        OPTIONAL MATCH (leafNode:Concept)<-[:IDENTIFIES]-(leafId:Identifier)
        WHERE NOT leafId:UPPIdentifier
	    RETURN canonical.prefUUID as prefUUID, p.uuid AS UUID, labels(p) AS oldModelTypes, labels(p) AS newModelTypes,
	    {labels:labels(ids), value:ids.value} AS oldModelIdentifiers,
	    {labels:labels(leafId), value:leafId.value} AS newModelIdentifiers
        `,
		Parameters: neoism.Props{"identifiers": identifiers},
		Result:     &results,
	}

	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{query})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", query.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore for identifier:")
	}

	if (len(results)) == 0 {
		return Concordances{}, false, nil
	}

	concordances = Concordances{
		Concordance: []Concordance{},
	}

	return processCypherQueryToConcordances(pcw, query, results)

}

func (pcw CypherDriver) ReadByAuthority(authority string, identifierValues []string) (concordances Concordances, found bool, err error) {
	results := []neoReadStruct{}

	authorityProperty := mapAuthorityToAuthorityProperty(authority)
	if authorityProperty == "" {
		return Concordances{}, false, nil
	}
	query := &neoism.CypherQuery{
		Statement: `
		MATCH (p:Concept)<-[:IDENTIFIES]-(ids:Identifier)
 		WHERE ids.value in {identifierValues} AND NOT ids:UPPIdentifier
        OPTIONAL MATCH (p:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        RETURN canonical.prefUUID as prefUUID, p.uuid AS UUID, labels(p) AS oldModelTypes, labels(canonical) AS newModelTypes,
        {labels:labels(ids), value:ids.value} AS oldModelIdentifiers,
        {labels:labels(ids), value:ids.value} AS newModelIdentifiers`,
		Parameters: neoism.Props{
			"identifierValues": identifierValues,
			"authority":        authorityProperty,
		},
		Result: &results,
	}

	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{query})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", query.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore for identifier:")
	}

	if (len(results)) == 0 {
		return Concordances{}, false, nil
	}

	concordances = Concordances{
		Concordance: []Concordance{},
	}

	return processCypherQueryToConcordances(pcw, query, results)
}

func processCypherQueryToConcordances(pcw CypherDriver, q *neoism.CypherQuery, results []neoReadStruct) (concordances Concordances, found bool, err error) {
	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{q})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", q.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore")
	}

	concordances = neoReadStructToConcordances(results, pcw.env)

	if (len(concordances.Concordance)) == 0 {
		return Concordances{}, false, nil
	}
	return concordances, true, nil
}

func neoReadStructToConcordances(neo []neoReadStruct, env string) (concordances Concordances) {
	concordances = Concordances{
		Concordance: []Concordance{},
	}
	for _, neoCon := range neo {
		var con = Concordance{}
		var concept = Concept{}

		if neoCon.PrefUUID != "" {
			log.Debugf("New concept model with prefUUID: %v", neoCon.PrefUUID)
			concept.ID = mapper.IDURL(neoCon.PrefUUID)
			concept.APIURL = mapper.APIURL(neoCon.PrefUUID, neoCon.NewModelTypes, env)
			con.Identifier = Identifier{Authority: mapNeoLabelsToAuthorityValue(neoCon.NewModelIdentifiers.Labels), IdentifierValue: neoCon.NewModelIdentifiers.Value}
		} else {
			log.Debugf("Old concept model with UUID: %v", neoCon.UUID)
			concept.ID = mapper.IDURL(neoCon.UUID)
			concept.APIURL = mapper.APIURL(neoCon.UUID, neoCon.OldModelTypes, env)
			con.Identifier = Identifier{Authority: mapNeoLabelsToAuthorityValue(neoCon.OldModelIdentifiers.Labels), IdentifierValue: neoCon.OldModelIdentifiers.Value}
		}

		con.Concept = concept
		concordances.Concordance = append(concordances.Concordance, con)
	}
	return concordances
}

func mapNeoLabelsToAuthorityValue(labelNames []string) (authority string) {
	for _, label := range labelNames {
		switch label {
		// Old style node label lookup
		case TME_ID_NODE_LABEL:
			return TME_AUTHORITY
		case FS_ID_NODE_LABEL:
			return FS_AUTHORITY
		case UP_ID_NODE_LABEL:
			return UP_AUTHORITY
		case LEI_ID_NODE_LABEL:
			return LEI_AUTHORITY
		case SL_ID_NODE_LABEL:
			return SL_AUTHORITY

		// New style authority properties
		case FS_AUTHORITY_PROPERTY:
			return FS_AUTHORITY
		case UP_AUTHORITY_PROPERTY:
			return UP_AUTHORITY
		case SL_AUTHORITY_PROPERTY:
			return SL_AUTHORITY
		case TME_AUTHORITY_PROPERTY:
			return TME_AUTHORITY
		}
	}
	return ""
}

func mapAuthorityToAuthorityProperty(authority string) string {
	switch authority {
	case TME_AUTHORITY:
		return TME_AUTHORITY_PROPERTY
	case FS_AUTHORITY:
		return FS_AUTHORITY_PROPERTY
	case SL_AUTHORITY:
		return SL_AUTHORITY_PROPERTY
	default:
		return ""
	}
}

func mapAuthorityToIdentifierLabel(authority string) (label string) {
	switch authority {
	case TME_AUTHORITY:
		return TME_ID_NODE_LABEL
	case FS_AUTHORITY:
		return FS_ID_NODE_LABEL
	case LEI_AUTHORITY:
		return LEI_ID_NODE_LABEL
	}
	return ""
}

const TME_AUTHORITY = "http://api.ft.com/system/FT-TME"
const FS_AUTHORITY = "http://api.ft.com/system/FACTSET"
const UP_AUTHORITY = "http://api.ft.com/system/UPP"
const LEI_AUTHORITY = "http://api.ft.com/system/LEI"
const SL_AUTHORITY = "http://api.ft.com/system/SMARTLOGIC"

const TME_ID_NODE_LABEL = "TMEIdentifier"
const FS_ID_NODE_LABEL = "FactsetIdentifier"
const UP_ID_NODE_LABEL = "UPPIdentifier"
const LEI_ID_NODE_LABEL = "LegalEntityIdentifier"
const SL_ID_NODE_LABEL = "SmartlogicIdentifier"

const TME_AUTHORITY_PROPERTY = "TME"
const FS_AUTHORITY_PROPERTY = "FACTSET"
const UP_AUTHORITY_PROPERTY = "UPP"
const SL_AUTHORITY_PROPERTY = "Smartlogic"
<commit_msg>Added values to a error message<commit_after>package concordances

import (
	"fmt"

	"github.com/Financial-Times/neo-model-utils-go/mapper"
	"github.com/Financial-Times/neo-utils-go/neoutils"
	"github.com/jmcvetta/neoism"
	log "github.com/sirupsen/logrus"
)

// Driver interface
type Driver interface {
	ReadByConceptID(ids []string) (concordances Concordances, found bool, err error)
	ReadByAuthority(authority string, ids []string) (concordances Concordances, found bool, err error)
	CheckConnectivity() error
}

// CypherDriver struct
type CypherDriver struct {
	conn neoutils.NeoConnection
	env  string
}

//NewCypherDriver instantiate driver
func NewCypherDriver(conn neoutils.NeoConnection, env string) CypherDriver {
	return CypherDriver{conn, env}
}

// CheckConnectivity tests neo4j by running a simple cypher query
func (pcw CypherDriver) CheckConnectivity() error {
	return neoutils.Check(pcw.conn)
}

type neoReadStruct struct {
	UUID                string        `json:"UUID"`
	PrefUUID            string        `json:"prefUUID"`
	NewModelTypes       []string      `json:"newModelTypes"`
	NewModelIdentifiers neoIdentifier `json:"newModelIdentifiers"`
	OldModelTypes       []string      `json:"oldModelTypes"`
	OldModelIdentifiers neoIdentifier `json:"oldModelIdentifiers"`
}

type neoIdentifier struct {
	Labels []string `json:"labels"`
	Value  string   `json:"value"`
}

func (pcw CypherDriver) ReadByConceptID(identifiers []string) (concordances Concordances, found bool, err error) {
	results := []neoReadStruct{}
	query := &neoism.CypherQuery{
		Statement: `
		MATCH (p:Concept)<-[:IDENTIFIES]-(i:UPPIdentifier)
		WHERE i.value in {identifiers}
		MATCH (p:Concept)<-[:IDENTIFIES]-(ids:Identifier)
		WHERE NOT ids:UPPIdentifier
        OPTIONAL MATCH (p:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        OPTIONAL MATCH (leafNode:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        OPTIONAL MATCH (leafNode:Concept)<-[:IDENTIFIES]-(leafId:Identifier)
        WHERE NOT leafId:UPPIdentifier
	    RETURN canonical.prefUUID as prefUUID, p.uuid AS UUID, labels(p) AS oldModelTypes, labels(p) AS newModelTypes,
	    {labels:labels(ids), value:ids.value} AS oldModelIdentifiers,
	    {labels:labels(leafId), value:leafId.value} AS newModelIdentifiers
        `,
		Parameters: neoism.Props{"identifiers": identifiers},
		Result:     &results,
	}

	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{query})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", query.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore for identifier: %v", identifiers)
	}

	if (len(results)) == 0 {
		return Concordances{}, false, nil
	}

	concordances = Concordances{
		Concordance: []Concordance{},
	}

	return processCypherQueryToConcordances(pcw, query, results)

}

func (pcw CypherDriver) ReadByAuthority(authority string, identifierValues []string) (concordances Concordances, found bool, err error) {
	results := []neoReadStruct{}

	authorityProperty := mapAuthorityToAuthorityProperty(authority)
	if authorityProperty == "" {
		return Concordances{}, false, nil
	}
	query := &neoism.CypherQuery{
		Statement: `
		MATCH (p:Concept)<-[:IDENTIFIES]-(ids:Identifier)
 		WHERE ids.value in {identifierValues} AND NOT ids:UPPIdentifier
        OPTIONAL MATCH (p:Concept)-[:EQUIVALENT_TO]->(canonical:Concept)
        RETURN canonical.prefUUID as prefUUID, p.uuid AS UUID, labels(p) AS oldModelTypes, labels(canonical) AS newModelTypes,
        {labels:labels(ids), value:ids.value} AS oldModelIdentifiers,
        {labels:labels(ids), value:ids.value} AS newModelIdentifiers`,
		Parameters: neoism.Props{
			"identifierValues": identifierValues,
			"authority":        authorityProperty,
		},
		Result: &results,
	}

	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{query})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", query.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore for identifier:")
	}

	if (len(results)) == 0 {
		return Concordances{}, false, nil
	}

	concordances = Concordances{
		Concordance: []Concordance{},
	}

	return processCypherQueryToConcordances(pcw, query, results)
}

func processCypherQueryToConcordances(pcw CypherDriver, q *neoism.CypherQuery, results []neoReadStruct) (concordances Concordances, found bool, err error) {
	err = pcw.conn.CypherBatch([]*neoism.CypherQuery{q})
	if err != nil {
		log.Errorf("Error looking up Concordances with query %s from neoism: %+v\n", q.Statement, err)
		return Concordances{}, false, fmt.Errorf("Error accessing Concordance datastore")
	}

	concordances = neoReadStructToConcordances(results, pcw.env)

	if (len(concordances.Concordance)) == 0 {
		return Concordances{}, false, nil
	}
	return concordances, true, nil
}

func neoReadStructToConcordances(neo []neoReadStruct, env string) (concordances Concordances) {
	concordances = Concordances{
		Concordance: []Concordance{},
	}
	for _, neoCon := range neo {
		var con = Concordance{}
		var concept = Concept{}

		if neoCon.PrefUUID != "" {
			log.Debugf("New concept model with prefUUID: %v", neoCon.PrefUUID)
			concept.ID = mapper.IDURL(neoCon.PrefUUID)
			concept.APIURL = mapper.APIURL(neoCon.PrefUUID, neoCon.NewModelTypes, env)
			con.Identifier = Identifier{Authority: mapNeoLabelsToAuthorityValue(neoCon.NewModelIdentifiers.Labels), IdentifierValue: neoCon.NewModelIdentifiers.Value}
		} else {
			log.Debugf("Old concept model with UUID: %v", neoCon.UUID)
			concept.ID = mapper.IDURL(neoCon.UUID)
			concept.APIURL = mapper.APIURL(neoCon.UUID, neoCon.OldModelTypes, env)
			con.Identifier = Identifier{Authority: mapNeoLabelsToAuthorityValue(neoCon.OldModelIdentifiers.Labels), IdentifierValue: neoCon.OldModelIdentifiers.Value}
		}

		con.Concept = concept
		concordances.Concordance = append(concordances.Concordance, con)
	}
	return concordances
}

func mapNeoLabelsToAuthorityValue(labelNames []string) (authority string) {
	for _, label := range labelNames {
		switch label {
		// Old style node label lookup
		case TME_ID_NODE_LABEL:
			return TME_AUTHORITY
		case FS_ID_NODE_LABEL:
			return FS_AUTHORITY
		case UP_ID_NODE_LABEL:
			return UP_AUTHORITY
		case LEI_ID_NODE_LABEL:
			return LEI_AUTHORITY
		case SL_ID_NODE_LABEL:
			return SL_AUTHORITY

		// New style authority properties
		case FS_AUTHORITY_PROPERTY:
			return FS_AUTHORITY
		case UP_AUTHORITY_PROPERTY:
			return UP_AUTHORITY
		case SL_AUTHORITY_PROPERTY:
			return SL_AUTHORITY
		case TME_AUTHORITY_PROPERTY:
			return TME_AUTHORITY
		}
	}
	return ""
}

func mapAuthorityToAuthorityProperty(authority string) string {
	switch authority {
	case TME_AUTHORITY:
		return TME_AUTHORITY_PROPERTY
	case FS_AUTHORITY:
		return FS_AUTHORITY_PROPERTY
	case SL_AUTHORITY:
		return SL_AUTHORITY_PROPERTY
	default:
		return ""
	}
}

func mapAuthorityToIdentifierLabel(authority string) (label string) {
	switch authority {
	case TME_AUTHORITY:
		return TME_ID_NODE_LABEL
	case FS_AUTHORITY:
		return FS_ID_NODE_LABEL
	case LEI_AUTHORITY:
		return LEI_ID_NODE_LABEL
	}
	return ""
}

const TME_AUTHORITY = "http://api.ft.com/system/FT-TME"
const FS_AUTHORITY = "http://api.ft.com/system/FACTSET"
const UP_AUTHORITY = "http://api.ft.com/system/UPP"
const LEI_AUTHORITY = "http://api.ft.com/system/LEI"
const SL_AUTHORITY = "http://api.ft.com/system/SMARTLOGIC"

const TME_ID_NODE_LABEL = "TMEIdentifier"
const FS_ID_NODE_LABEL = "FactsetIdentifier"
const UP_ID_NODE_LABEL = "UPPIdentifier"
const LEI_ID_NODE_LABEL = "LegalEntityIdentifier"
const SL_ID_NODE_LABEL = "SmartlogicIdentifier"

const TME_AUTHORITY_PROPERTY = "TME"
const FS_AUTHORITY_PROPERTY = "FACTSET"
const UP_AUTHORITY_PROPERTY = "UPP"
const SL_AUTHORITY_PROPERTY = "Smartlogic"
<|endoftext|>


<commit_before>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gdb

import (
	"fmt"
	"strings"
)

// Where sets the condition statement for the model. The parameter `where` can be type of
// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
// multiple conditions will be joined into where statement using "AND".
// Eg:
// Where("uid=10000")
// Where("uid", 10000)
// Where("money>? AND name like ?", 99999, "vip_%")
// Where("uid", 1).Where("name", "john")
// Where("status IN (?)", g.Slice{1,2,3})
// Where("age IN(?,?)", 18, 50)
// Where(User{ Id : 1, UserName : "john"})
func (m *Model) Where(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderWhere,
		where:    where,
		args:     args,
	})
	return model
}

// Having sets the having statement for the model.
// The parameters of this function usage are as the same as function Where.
// See Where.
func (m *Model) Having(having interface{}, args ...interface{}) *Model {
	model := m.getModel()
	model.having = []interface{}{
		having, args,
	}
	return model
}

// WherePri does the same logic as Model.Where except that if the parameter `where`
// is a single condition like int/string/float/slice, it treats the condition as the primary
// key value. That is, if primary key is "id" and given `where` parameter as "123", the
// WherePri function treats the condition as "id=123", but Model.Where treats the condition
// as string "123".
func (m *Model) WherePri(where interface{}, args ...interface{}) *Model {
	if len(args) > 0 {
		return m.Where(where, args...)
	}
	newWhere := GetPrimaryKeyCondition(m.getPrimaryKey(), where)
	return m.Where(newWhere[0], newWhere[1:]...)
}

// WhereBetween builds `xxx BETWEEN x AND y` statement.
func (m *Model) WhereBetween(column string, min, max interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereLike builds `xxx LIKE x` statement.
func (m *Model) WhereLike(column string, like interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereIn builds `xxx IN (x)` statement.
func (m *Model) WhereIn(column string, in interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereNull builds `xxx IS NULL` statement.
func (m *Model) WhereNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.Where(fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereNotBetween builds `xxx NOT BETWEEN x AND y` statement.
func (m *Model) WhereNotBetween(column string, min, max interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereNotLike builds `xxx NOT LIKE x` statement.
func (m *Model) WhereNotLike(column string, like interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereNotIn builds `xxx NOT IN (x)` statement.
func (m *Model) WhereNotIn(column string, in interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereNotNull builds `xxx IS NOT NULL` statement.
func (m *Model) WhereNotNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.Where(fmt.Sprintf(`%s IS NOT NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereOr adds "OR" condition to the where statement.
func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderOr,
		where:    where,
		args:     args,
	})
	return model
}

// WhereOrBetween builds `xxx BETWEEN x AND y` statement in `OR` conditions.
func (m *Model) WhereOrBetween(column string, min, max interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereOrLike builds `xxx LIKE x` statement in `OR` conditions.
func (m *Model) WhereOrLike(column string, like interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereOrIn builds `xxx IN (x)` statement in `OR` conditions.
func (m *Model) WhereOrIn(column string, in interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereOrNull builds `xxx IS NULL` statement in `OR` conditions.
func (m *Model) WhereOrNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.WhereOr(fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereOrNotBetween builds `xxx NOT BETWEEN x AND y` statement in `OR` conditions.
func (m *Model) WhereOrNotBetween(column string, min, max interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereOrNotLike builds `xxx NOT LIKE x` statement in `OR` conditions.
func (m *Model) WhereOrNotLike(column string, like interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereOrNotIn builds `xxx NOT IN (x)` statement.
func (m *Model) WhereOrNotIn(column string, in interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereOrNotNull builds `xxx IS NOT NULL` statement in `OR` conditions.
func (m *Model) WhereOrNotNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.WhereOr(fmt.Sprintf(`%s IS NOT NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// Group sets the "GROUP BY" statement for the model.
func (m *Model) Group(groupBy string) *Model {
	model := m.getModel()
	model.groupBy = m.db.QuoteString(groupBy)
	return model
}

// And adds "AND" condition to the where statement.
// Deprecated, use Where instead.
func (m *Model) And(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderAnd,
		where:    where,
		args:     args,
	})
	return model
}

// Or adds "OR" condition to the where statement.
// Deprecated, use WhereOr instead.
func (m *Model) Or(where interface{}, args ...interface{}) *Model {
	return m.WhereOr(where, args...)
}

// GroupBy is alias of Model.Group.
// See Model.Group.
// Deprecated, use Group instead.
func (m *Model) GroupBy(groupBy string) *Model {
	return m.Group(groupBy)
}

// Order sets the "ORDER BY" statement for the model.
func (m *Model) Order(orderBy ...string) *Model {
	if len(orderBy) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteString(strings.Join(orderBy, " "))
	return model
}

// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
func (m *Model) OrderAsc(column string) *Model {
	if len(column) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteWord(column) + " ASC"
	return model
}

// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
func (m *Model) OrderDesc(column string) *Model {
	if len(column) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteWord(column) + " DESC"
	return model
}

// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
func (m *Model) OrderRandom(orderBy ...string) *Model {
	model := m.getModel()
	model.orderBy = "RAND()"
	return model
}

// OrderBy is alias of Model.Order.
// See Model.Order.
// Deprecated, use Order instead.
func (m *Model) OrderBy(orderBy string) *Model {
	return m.Order(orderBy)
}

// Limit sets the "LIMIT" statement for the model.
// The parameter `limit` can be either one or two number, if passed two number is passed,
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
// statement.
func (m *Model) Limit(limit ...int) *Model {
	model := m.getModel()
	switch len(limit) {
	case 1:
		model.limit = limit[0]
	case 2:
		model.start = limit[0]
		model.limit = limit[1]
	}
	return model
}

// Offset sets the "OFFSET" statement for the model.
// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
func (m *Model) Offset(offset int) *Model {
	model := m.getModel()
	model.offset = offset
	return model
}

// Distinct forces the query to only return distinct results.
func (m *Model) Distinct() *Model {
	model := m.getModel()
	model.distinct = "DISTINCT "
	return model
}

// Page sets the paging number for the model.
// The parameter `page` is started from 1 for paging.
// Note that, it differs that the Limit function starts from 0 for "LIMIT" statement.
func (m *Model) Page(page, limit int) *Model {
	model := m.getModel()
	if page <= 0 {
		page = 1
	}
	model.start = (page - 1) * limit
	model.limit = limit
	return model
}

// ForPage is alias of Model.Page.
// See Model.Page.
// Deprecated, use Page instead.
func (m *Model) ForPage(page, limit int) *Model {
	return m.Page(page, limit)
}
<commit_msg>improve OrderRandom function for package gdb<commit_after>// Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
//
// This Source Code Form is subject to the terms of the MIT License.
// If a copy of the MIT was not distributed with this file,
// You can obtain one at https://github.com/gogf/gf.

package gdb

import (
	"fmt"
	"strings"
)

// Where sets the condition statement for the model. The parameter `where` can be type of
// string/map/gmap/slice/struct/*struct, etc. Note that, if it's called more than one times,
// multiple conditions will be joined into where statement using "AND".
// Eg:
// Where("uid=10000")
// Where("uid", 10000)
// Where("money>? AND name like ?", 99999, "vip_%")
// Where("uid", 1).Where("name", "john")
// Where("status IN (?)", g.Slice{1,2,3})
// Where("age IN(?,?)", 18, 50)
// Where(User{ Id : 1, UserName : "john"})
func (m *Model) Where(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderWhere,
		where:    where,
		args:     args,
	})
	return model
}

// Having sets the having statement for the model.
// The parameters of this function usage are as the same as function Where.
// See Where.
func (m *Model) Having(having interface{}, args ...interface{}) *Model {
	model := m.getModel()
	model.having = []interface{}{
		having, args,
	}
	return model
}

// WherePri does the same logic as Model.Where except that if the parameter `where`
// is a single condition like int/string/float/slice, it treats the condition as the primary
// key value. That is, if primary key is "id" and given `where` parameter as "123", the
// WherePri function treats the condition as "id=123", but Model.Where treats the condition
// as string "123".
func (m *Model) WherePri(where interface{}, args ...interface{}) *Model {
	if len(args) > 0 {
		return m.Where(where, args...)
	}
	newWhere := GetPrimaryKeyCondition(m.getPrimaryKey(), where)
	return m.Where(newWhere[0], newWhere[1:]...)
}

// WhereBetween builds `xxx BETWEEN x AND y` statement.
func (m *Model) WhereBetween(column string, min, max interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereLike builds `xxx LIKE x` statement.
func (m *Model) WhereLike(column string, like interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereIn builds `xxx IN (x)` statement.
func (m *Model) WhereIn(column string, in interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereNull builds `xxx IS NULL` statement.
func (m *Model) WhereNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.Where(fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereNotBetween builds `xxx NOT BETWEEN x AND y` statement.
func (m *Model) WhereNotBetween(column string, min, max interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereNotLike builds `xxx NOT LIKE x` statement.
func (m *Model) WhereNotLike(column string, like interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereNotIn builds `xxx NOT IN (x)` statement.
func (m *Model) WhereNotIn(column string, in interface{}) *Model {
	return m.Where(fmt.Sprintf(`%s NOT IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereNotNull builds `xxx IS NOT NULL` statement.
func (m *Model) WhereNotNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.Where(fmt.Sprintf(`%s IS NOT NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereOr adds "OR" condition to the where statement.
func (m *Model) WhereOr(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderOr,
		where:    where,
		args:     args,
	})
	return model
}

// WhereOrBetween builds `xxx BETWEEN x AND y` statement in `OR` conditions.
func (m *Model) WhereOrBetween(column string, min, max interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereOrLike builds `xxx LIKE x` statement in `OR` conditions.
func (m *Model) WhereOrLike(column string, like interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereOrIn builds `xxx IN (x)` statement in `OR` conditions.
func (m *Model) WhereOrIn(column string, in interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereOrNull builds `xxx IS NULL` statement in `OR` conditions.
func (m *Model) WhereOrNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.WhereOr(fmt.Sprintf(`%s IS NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// WhereOrNotBetween builds `xxx NOT BETWEEN x AND y` statement in `OR` conditions.
func (m *Model) WhereOrNotBetween(column string, min, max interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT BETWEEN ? AND ?`, m.db.QuoteWord(column)), min, max)
}

// WhereOrNotLike builds `xxx NOT LIKE x` statement in `OR` conditions.
func (m *Model) WhereOrNotLike(column string, like interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT LIKE ?`, m.db.QuoteWord(column)), like)
}

// WhereOrNotIn builds `xxx NOT IN (x)` statement.
func (m *Model) WhereOrNotIn(column string, in interface{}) *Model {
	return m.WhereOr(fmt.Sprintf(`%s NOT IN (?)`, m.db.QuoteWord(column)), in)
}

// WhereOrNotNull builds `xxx IS NOT NULL` statement in `OR` conditions.
func (m *Model) WhereOrNotNull(columns ...string) *Model {
	model := m
	for _, column := range columns {
		model = m.WhereOr(fmt.Sprintf(`%s IS NOT NULL`, m.db.QuoteWord(column)))
	}
	return model
}

// Group sets the "GROUP BY" statement for the model.
func (m *Model) Group(groupBy string) *Model {
	model := m.getModel()
	model.groupBy = m.db.QuoteString(groupBy)
	return model
}

// And adds "AND" condition to the where statement.
// Deprecated, use Where instead.
func (m *Model) And(where interface{}, args ...interface{}) *Model {
	model := m.getModel()
	if model.whereHolder == nil {
		model.whereHolder = make([]*whereHolder, 0)
	}
	model.whereHolder = append(model.whereHolder, &whereHolder{
		operator: whereHolderAnd,
		where:    where,
		args:     args,
	})
	return model
}

// Or adds "OR" condition to the where statement.
// Deprecated, use WhereOr instead.
func (m *Model) Or(where interface{}, args ...interface{}) *Model {
	return m.WhereOr(where, args...)
}

// GroupBy is alias of Model.Group.
// See Model.Group.
// Deprecated, use Group instead.
func (m *Model) GroupBy(groupBy string) *Model {
	return m.Group(groupBy)
}

// Order sets the "ORDER BY" statement for the model.
func (m *Model) Order(orderBy ...string) *Model {
	if len(orderBy) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteString(strings.Join(orderBy, " "))
	return model
}

// OrderAsc sets the "ORDER BY xxx ASC" statement for the model.
func (m *Model) OrderAsc(column string) *Model {
	if len(column) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteWord(column) + " ASC"
	return model
}

// OrderDesc sets the "ORDER BY xxx DESC" statement for the model.
func (m *Model) OrderDesc(column string) *Model {
	if len(column) == 0 {
		return m
	}
	model := m.getModel()
	model.orderBy = m.db.QuoteWord(column) + " DESC"
	return model
}

// OrderRandom sets the "ORDER BY RANDOM()" statement for the model.
func (m *Model) OrderRandom() *Model {
	model := m.getModel()
	model.orderBy = "RAND()"
	return model
}

// OrderBy is alias of Model.Order.
// See Model.Order.
// Deprecated, use Order instead.
func (m *Model) OrderBy(orderBy string) *Model {
	return m.Order(orderBy)
}

// Limit sets the "LIMIT" statement for the model.
// The parameter `limit` can be either one or two number, if passed two number is passed,
// it then sets "LIMIT limit[0],limit[1]" statement for the model, or else it sets "LIMIT limit[0]"
// statement.
func (m *Model) Limit(limit ...int) *Model {
	model := m.getModel()
	switch len(limit) {
	case 1:
		model.limit = limit[0]
	case 2:
		model.start = limit[0]
		model.limit = limit[1]
	}
	return model
}

// Offset sets the "OFFSET" statement for the model.
// It only makes sense for some databases like SQLServer, PostgreSQL, etc.
func (m *Model) Offset(offset int) *Model {
	model := m.getModel()
	model.offset = offset
	return model
}

// Distinct forces the query to only return distinct results.
func (m *Model) Distinct() *Model {
	model := m.getModel()
	model.distinct = "DISTINCT "
	return model
}

// Page sets the paging number for the model.
// The parameter `page` is started from 1 for paging.
// Note that, it differs that the Limit function starts from 0 for "LIMIT" statement.
func (m *Model) Page(page, limit int) *Model {
	model := m.getModel()
	if page <= 0 {
		page = 1
	}
	model.start = (page - 1) * limit
	model.limit = limit
	return model
}

// ForPage is alias of Model.Page.
// See Model.Page.
// Deprecated, use Page instead.
func (m *Model) ForPage(page, limit int) *Model {
	return m.Page(page, limit)
}
<|endoftext|>