<commit_before>package utils

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"

	"github.com/techjanitor/pram-post/config"
)

var db *sql.DB

// NewDb initializes a connection to MySQL and tries to connect.
func NewDb() {
	var err error

	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/%s",
		config.Settings.Database.User,
		config.Settings.Database.Password,
		config.Settings.Database.Proto,
		config.Settings.Database.Host,
		config.Settings.Database.Database,
	))
	if err != nil {
		panic(err)
	}

	err = db.Ping()
	if err != nil {
		panic(err)
	}

	db.SetMaxIdleConns(config.Settings.Database.MaxIdle)
	db.SetMaxOpenConns(config.Settings.Database.MaxConnections)
}

// GetDb returns a connection to MySQL
func GetDb() (*sql.DB, error) {
	return db, nil
}

// GetTransaction will return a transaction
func GetTransaction() (*sql.Tx, error) {
	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	return tx, err
}

// Check a bool in the database
func GetBool(column, table, row string, id uint) (boolean bool) {

	// Check if thread is closed and get the total amount of posts
	err := db.QueryRow("SELECT ? FROM ? WHERE ? = ?", column, table, row, id).Scan(&boolean)
	if err != nil {
		return false
	}

	return

}

// Set a bool in the database
func SetBool(table, column, row string, boolean bool, id uint) (err error) {

	ps, err = db.Prepare("UPDATE ? SET ?=? WHERE ?=?")
	if err != nil {
		return
	}
	defer ps.Close()

	_, err = updatestatus.Exec(table, column, boolean, row, id)
	if err != nil {
		return
	}

	return

}
<commit_msg>db bool functions<commit_after>package utils

import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"

	"github.com/techjanitor/pram-post/config"
)

var db *sql.DB

// NewDb initializes a connection to MySQL and tries to connect.
func NewDb() {
	var err error

	db, err = sql.Open("mysql", fmt.Sprintf("%s:%s@%s(%s)/%s",
		config.Settings.Database.User,
		config.Settings.Database.Password,
		config.Settings.Database.Proto,
		config.Settings.Database.Host,
		config.Settings.Database.Database,
	))
	if err != nil {
		panic(err)
	}

	err = db.Ping()
	if err != nil {
		panic(err)
	}

	db.SetMaxIdleConns(config.Settings.Database.MaxIdle)
	db.SetMaxOpenConns(config.Settings.Database.MaxConnections)
}

// GetDb returns a connection to MySQL
func GetDb() (*sql.DB, error) {
	return db, nil
}

// GetTransaction will return a transaction
func GetTransaction() (*sql.Tx, error) {
	tx, err := db.Begin()
	if err != nil {
		panic(err)
	}

	return tx, err
}

// Check a bool in the database
func GetBool(column, table, row string, id uint) (boolean bool) {

	// Check if thread is closed and get the total amount of posts
	err := db.QueryRow("SELECT ? FROM ? WHERE ? = ?", column, table, row, id).Scan(&boolean)
	if err != nil {
		return false
	}

	return

}

// Set a bool in the database
func SetBool(table, column, row string, boolean bool, id uint) (err error) {

	ps, err := db.Prepare("UPDATE ? SET ?=? WHERE ?=?")
	if err != nil {
		return
	}
	defer ps.Close()

	_, err = ps.Exec(table, column, boolean, row, id)
	if err != nil {
		return
	}

	return

}
<|endoftext|>


<commit_before>package utils

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/adrienkohlbecker/errors"
	"github.com/mattn/go-isatty"
	"github.com/spf13/cobra"
)

// ReadFromFile reads the contents of the given file, and returns the contents
// with trimmed spaces
//
// If file is a terminal (such as when running with os.Stdin), it prints
// instructions to the user on how to close the input by sending an EOF.
func ReadFromFile(file *os.File) (string, errors.Error) {

	if isatty.IsTerminal(file.Fd()) {
		fmt.Println("Please enter the value and press Ctrl+D:")
	}

	reader := bufio.NewReader(file)
	bytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return "", errors.WrapPrefix(err, "Unable to read from file", 0)
	}

	value := strings.TrimSpace(string(bytes))
	return value, nil

}

// Fatal prints a pretty error message when a cobra command returns an error.
//
// Included in the output is the error message and a prompt to check out the
// documentation.
//
// If the environment variable EJSON_KMS_DEBUG is set to 1, it also prints
// the stacktrace of the given error.
func Fatal(cmd *cobra.Command, err errors.Error) {

	fmt.Fprintf(os.Stderr, "%s\n", err)
	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "Run `%s --help` for documentation\n", cmd.CommandPath())

	enableDebug := os.Getenv("EJSON_KMS_DEBUG") == "1"
	if enableDebug {
		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintln(os.Stderr, string(err.Stack()))
	}

}
<commit_msg>Add note on coverage<commit_after>package utils

import (
	"bufio"
	"fmt"
	"io/ioutil"
	"os"
	"strings"

	"github.com/adrienkohlbecker/errors"
	"github.com/mattn/go-isatty"
	"github.com/spf13/cobra"
)

// ReadFromFile reads the contents of the given file, and returns the contents
// with trimmed spaces
//
// If file is a terminal (such as when running with os.Stdin), it prints
// instructions to the user on how to close the input by sending an EOF.
func ReadFromFile(file *os.File) (string, errors.Error) {

	if isatty.IsTerminal(file.Fd()) {
		// Note: not covered by tests, need a way to test IsTerminal
		fmt.Println("Please enter the value and press Enter then Ctrl+D:")
	}

	reader := bufio.NewReader(file)
	bytes, err := ioutil.ReadAll(reader)
	if err != nil {
		return "", errors.WrapPrefix(err, "Unable to read from file", 0)
	}

	value := strings.TrimSpace(string(bytes))
	return value, nil

}

// Fatal prints a pretty error message when a cobra command returns an error.
//
// Included in the output is the error message and a prompt to check out the
// documentation.
//
// If the environment variable EJSON_KMS_DEBUG is set to 1, it also prints
// the stacktrace of the given error.
func Fatal(cmd *cobra.Command, err errors.Error) {

	fmt.Fprintf(os.Stderr, "%s\n", err)
	fmt.Fprintf(os.Stderr, "\n")
	fmt.Fprintf(os.Stderr, "Run `%s --help` for documentation\n", cmd.CommandPath())

	enableDebug := os.Getenv("EJSON_KMS_DEBUG") == "1"
	if enableDebug {
		fmt.Fprintf(os.Stderr, "\n")
		fmt.Fprintln(os.Stderr, string(err.Stack()))
	}

}
<|endoftext|>


<commit_before>package scenarios

import (
	"net"
	"testing"

	"v2ray.com/core"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/serial"
	"v2ray.com/core/common/uuid"
	"v2ray.com/core/proxy/dokodemo"
	"v2ray.com/core/proxy/freedom"
	"v2ray.com/core/proxy/vmess"
	"v2ray.com/core/proxy/vmess/inbound"
	"v2ray.com/core/proxy/vmess/outbound"
	"v2ray.com/core/testing/assert"
	"v2ray.com/core/testing/servers/tcp"
)

func TestDokodemoTCP(t *testing.T) {
	assert := assert.On(t)

	tcpServer := tcp.Server{
		MsgProcessor: xor,
	}
	dest, err := tcpServer.Start()
	assert.Error(err).IsNil()
	defer tcpServer.Close()

	userID := protocol.NewID(uuid.New())
	serverPort := pickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: v2net.SinglePortRange(serverPort),
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&inbound.Config{
					User: []*protocol.User{
						{
							Account: serial.ToTypedMessage(&vmess.Account{
								Id: userID.String(),
							}),
						},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	clientPort := uint32(pickPort())
	clientPortRange := uint32(5)
	clientConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&dokodemo.Config{
					Address: v2net.NewIPOrDomain(dest.Address),
					Port:    uint32(dest.Port),
					NetworkList: &v2net.NetworkList{
						Network: []v2net.Network{v2net.Network_TCP},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&outbound.Config{
					Receiver: []*protocol.ServerEndpoint{
						{
							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
							Port:    uint32(serverPort),
							User: []*protocol.User{
								{
									Account: serial.ToTypedMessage(&vmess.Account{
										Id: userID.String(),
									}),
								},
							},
						},
					},
				}),
			},
		},
	}

	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
	assert.Error(InitializeServerConfig(clientConfig)).IsNil()

	for port := clientPort; port <= clientPort+clientPortRange; port++ {
		conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: int(port),
		})

		payload := "dokodemo request."
		nBytes, err := conn.Write([]byte(payload))
		assert.Error(err).IsNil()
		assert.Int(nBytes).Equals(len(payload))

		response := make([]byte, 1024)
		nBytes, err = conn.Read(response)
		assert.Error(err).IsNil()
		assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
		assert.Error(conn.Close()).IsNil()
	}

	CloseAllServers()
}
<commit_msg>test case for dokodemo udp<commit_after>package scenarios

import (
	"net"
	"testing"

	"v2ray.com/core"
	v2net "v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/serial"
	"v2ray.com/core/common/uuid"
	"v2ray.com/core/proxy/dokodemo"
	"v2ray.com/core/proxy/freedom"
	"v2ray.com/core/proxy/vmess"
	"v2ray.com/core/proxy/vmess/inbound"
	"v2ray.com/core/proxy/vmess/outbound"
	"v2ray.com/core/testing/assert"
	"v2ray.com/core/testing/servers/tcp"
	"v2ray.com/core/testing/servers/udp"
)

func TestDokodemoTCP(t *testing.T) {
	assert := assert.On(t)

	tcpServer := tcp.Server{
		MsgProcessor: xor,
	}
	dest, err := tcpServer.Start()
	assert.Error(err).IsNil()
	defer tcpServer.Close()

	userID := protocol.NewID(uuid.New())
	serverPort := pickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: v2net.SinglePortRange(serverPort),
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&inbound.Config{
					User: []*protocol.User{
						{
							Account: serial.ToTypedMessage(&vmess.Account{
								Id: userID.String(),
							}),
						},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	clientPort := uint32(pickPort())
	clientPortRange := uint32(5)
	clientConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&dokodemo.Config{
					Address: v2net.NewIPOrDomain(dest.Address),
					Port:    uint32(dest.Port),
					NetworkList: &v2net.NetworkList{
						Network: []v2net.Network{v2net.Network_TCP},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&outbound.Config{
					Receiver: []*protocol.ServerEndpoint{
						{
							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
							Port:    uint32(serverPort),
							User: []*protocol.User{
								{
									Account: serial.ToTypedMessage(&vmess.Account{
										Id: userID.String(),
									}),
								},
							},
						},
					},
				}),
			},
		},
	}

	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
	assert.Error(InitializeServerConfig(clientConfig)).IsNil()

	for port := clientPort; port <= clientPort+clientPortRange; port++ {
		conn, err := net.DialTCP("tcp", nil, &net.TCPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: int(port),
		})
		assert.Error(err).IsNil()

		payload := "dokodemo request."
		nBytes, err := conn.Write([]byte(payload))
		assert.Error(err).IsNil()
		assert.Int(nBytes).Equals(len(payload))

		response := make([]byte, 1024)
		nBytes, err = conn.Read(response)
		assert.Error(err).IsNil()
		assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
		assert.Error(conn.Close()).IsNil()
	}

	CloseAllServers()
}

func TestDokodemoUDP(t *testing.T) {
	assert := assert.On(t)

	udpServer := udp.Server{
		MsgProcessor: xor,
	}
	dest, err := udpServer.Start()
	assert.Error(err).IsNil()
	defer udpServer.Close()

	userID := protocol.NewID(uuid.New())
	serverPort := pickPort()
	serverConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: v2net.SinglePortRange(serverPort),
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&inbound.Config{
					User: []*protocol.User{
						{
							Account: serial.ToTypedMessage(&vmess.Account{
								Id: userID.String(),
							}),
						},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&freedom.Config{}),
			},
		},
	}

	clientPort := uint32(pickPort())
	clientPortRange := uint32(5)
	clientConfig := &core.Config{
		Inbound: []*core.InboundConnectionConfig{
			{
				PortRange: &v2net.PortRange{From: clientPort, To: clientPort + clientPortRange},
				ListenOn:  v2net.NewIPOrDomain(v2net.LocalHostIP),
				Settings: serial.ToTypedMessage(&dokodemo.Config{
					Address: v2net.NewIPOrDomain(dest.Address),
					Port:    uint32(dest.Port),
					NetworkList: &v2net.NetworkList{
						Network: []v2net.Network{v2net.Network_UDP},
					},
				}),
			},
		},
		Outbound: []*core.OutboundConnectionConfig{
			{
				Settings: serial.ToTypedMessage(&outbound.Config{
					Receiver: []*protocol.ServerEndpoint{
						{
							Address: v2net.NewIPOrDomain(v2net.LocalHostIP),
							Port:    uint32(serverPort),
							User: []*protocol.User{
								{
									Account: serial.ToTypedMessage(&vmess.Account{
										Id: userID.String(),
									}),
								},
							},
						},
					},
				}),
			},
		},
	}

	assert.Error(InitializeServerConfig(serverConfig)).IsNil()
	assert.Error(InitializeServerConfig(clientConfig)).IsNil()

	for port := clientPort; port <= clientPort+clientPortRange; port++ {
		conn, err := net.DialUDP("udp", nil, &net.UDPAddr{
			IP:   []byte{127, 0, 0, 1},
			Port: int(port),
		})
		assert.Error(err).IsNil()

		payload := "dokodemo request."
		nBytes, err := conn.Write([]byte(payload))
		assert.Error(err).IsNil()
		assert.Int(nBytes).Equals(len(payload))

		response := make([]byte, 1024)
		nBytes, err = conn.Read(response)
		assert.Error(err).IsNil()
		assert.Bytes(response[:nBytes]).Equals(xor([]byte(payload)))
		assert.Error(conn.Close()).IsNil()
	}

	CloseAllServers()
}
<|endoftext|>


<commit_before>package gmq

import (
	"database/sql"
	"encoding/base64"
	_ "github.com/go-sql-driver/mysql"
)

type DbQueue struct {
	Name, Vendor, Dsn string
	conn              *sql.DB
}

func openConn(db *DbQueue) (err error) {
	db.conn, err = sql.Open(db.Vendor, db.Dsn)
	return err
}

func (db DbQueue) Create(name string) QueueInterface {
	dbq := DbQueue{Name: name}
	//TODO create table on DB and release object
	//  create table queue (
	//	id serial PRIMARY KEY NOT NULL AUTO_INCREMENT,
	//	message MEDIUMTEXT,
	//	processed BOOL DEFAULT FALSE,
	//	UNIQUE INDEX proc_idx USING BTREE (id, processed)
	//);
	return dbq
}

func (db DbQueue) Push(o []byte) error {
	if err := openConn(&db); err != nil {
		return err
	}
	defer db.conn.Close()
	_, err := db.conn.Exec("INSERT INTO "+db.Name+" VALUES(NULL,?,?)", base64.StdEncoding.EncodeToString(o), false)
	return err
}

func (db DbQueue) Pop() ([]byte, error) {
	if err := openConn(&db); err != nil {
		return nil, err
	}
	defer db.conn.Close()
	var decode string
	var id int64
	if err := db.conn.QueryRow("SELECT MIN(id) FROM " + db.Name).Scan(&id); err != nil {
		return nil, err
	}
	if id > 0 {
		if err := db.conn.QueryRow("SELECT message FROM "+db.Name+" WHERE id = ?", id).Scan(&decode); err != nil {
			return nil, err
		}
		if _, err := db.conn.Exec("UPDATE "+db.Name+" SET processed = 1 WHERE id = ?", id); err != nil {
			return nil, err
		}
	}
	db.sync()
	return base64.StdEncoding.DecodeString(decode)
}

func (db DbQueue) sync() {
	db.conn.Exec("DELETE FROM " + db.Name + " WHERE processed = 1")
}
<commit_msg>Added Create for dbqueue<commit_after>package gmq

import (
	"database/sql"
	"encoding/base64"
	_ "github.com/go-sql-driver/mysql"
)

type DbQueue struct {
	Name, Vendor, Dsn string
	conn              *sql.DB
}

func openConn(db *DbQueue) (err error) {
	db.conn, err = sql.Open(db.Vendor, db.Dsn)
	return err
}

func (db DbQueue) Create(name string) QueueInterface {
	dbq := DbQueue{Name: name}
	//TODO create table on DB
	//  create table queue (
	//	id serial PRIMARY KEY NOT NULL AUTO_INCREMENT,
	//	message MEDIUMTEXT,
	//	processed BOOL DEFAULT FALSE,
	//	UNIQUE INDEX proc_idx USING BTREE (id, processed)
	//);
	sql := "CREATE TABLE ? ( id serial PRIMARY KEY NOT NULL AUTO_INCREMENT, message MEDIUMTEXT,processed BOOL DEFAULT FALSE, UNIQUE INDEX proc_idx USING BTREE (id, processed));"
	openConn(&db)
	//err ignored here: will be thorwed later when accessing the table
	db.conn.Exec(sql, name)

	return dbq
}

func (db DbQueue) Push(o []byte) error {
	if err := openConn(&db); err != nil {
		return err
	}
	defer db.conn.Close()
	_, err := db.conn.Exec("INSERT INTO "+db.Name+" VALUES(NULL,?,?)", base64.StdEncoding.EncodeToString(o), false)
	return err
}

func (db DbQueue) Pop() ([]byte, error) {
	if err := openConn(&db); err != nil {
		return nil, err
	}
	defer db.conn.Close()
	var decode string
	var id int64
	if err := db.conn.QueryRow("SELECT MIN(id) FROM " + db.Name).Scan(&id); err != nil {
		return nil, err
	}
	if id > 0 {
		if err := db.conn.QueryRow("SELECT message FROM "+db.Name+" WHERE id = ?", id).Scan(&decode); err != nil {
			return nil, err
		}
		if _, err := db.conn.Exec("UPDATE "+db.Name+" SET processed = 1 WHERE id = ?", id); err != nil {
			return nil, err
		}
	}
	db.sync()
	return base64.StdEncoding.DecodeString(decode)
}

func (db DbQueue) sync() {
	db.conn.Exec("DELETE FROM " + db.Name + " WHERE processed = 1")
}
<|endoftext|>


<commit_before>package quotes

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/doenietzomoeilijk/go-chat-bot-plugins/authorization"
	"github.com/go-chat-bot/bot"
	_ "github.com/mattn/go-sqlite3" // Use sqlite3
)

var (
	db *sql.DB
)

// Quote holds a singular quote
type Quote struct {
	ID        uint      `db:"id"`
	Channel   string    `db:"channel"`
	Author    string    `db:"author"`
	Timestamp time.Time `db:"timestamp"`
	Content   string    `db:"content"`
}

/**
 * Set up our DB - make sure it exists and that it has the proper table.
 */
func setupDb() {
	var err error

	db, err = sql.Open("sqlite3", "quotes.db")
	if err != nil {
		log.Fatal(err)
	}

	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS quotes (
        id INTEGER NOT NULL PRIMARY KEY,
        channel VARCHAR(50) NOT NULL DEFAULT 'unknown',
        author VARCHAR(15) NOT NULL DEFAULT 'unknown',
        timestamp DATETIME NULL,
        deleted TINYINT UNSIGNED NOT NULL DEFAULT 0,
        content TEXT
    )`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS chan ON quotes(channel)`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS idel ON quotes(deleted)`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS cont ON quotes(content)`)
}

func addQuote(command *bot.Cmd) (msg string, err error) {
	var insertID int64

	author, err := authorization.Authorize(command.ChannelData, "author", command.User)
	if err != nil {
		return "", nil
	}

	quote := strings.Join(command.Args, " ")
	if quote == "" {
		return
	}

	res, err := db.Exec(
		`INSERT INTO quotes
        (channel, author, timestamp, content)
        VALUES (?, ?, CURRENT_TIMESTAMP, ?)`,
		command.Channel,
		author,
		quote)

	if err != nil {
		err = errors.New("could not insert quote")
		return
	}

	insertID, err = res.LastInsertId()
	if err == nil {
		msg = fmt.Sprintf("Quote inserted with id %d.", insertID)
		log.Println(msg)
	} else {
		log.Println("error while inserting quote", err)
		err = nil
	}

	return
}

func queryToQuote(w map[string]interface{}, num uint) (Q Quote) {
	fields := "id, channel, author, timestamp, content"
	query := "SELECT %s FROM quotes WHERE deleted = 0"
	var binds []interface{}
	var usedLike bool

	for where, bind := range w {
		query += fmt.Sprintf(" AND %s", where)
		binds = append(binds, bind)
		if strings.Contains(where, "LIKE") {
			usedLike = true
		}
	}

	var count int
	countRow := db.QueryRow(fmt.Sprintf(query, "COUNT(*)"), binds...)
	err := countRow.Scan(&count)

	if count == 0 || err != nil {
		return
	}

	if count > 1 {
		if num == 0 {
			num = uint(rand.Intn(count)) + 1
		}

		query += fmt.Sprintf(" LIMIT 1 OFFSET %d", num-1)
	}

	query = fmt.Sprintf(query, fields)

	row := db.QueryRow(query, binds...)
	err = row.Scan(&Q.ID, &Q.Channel, &Q.Author, &Q.Timestamp, &Q.Content)
	if count > 1 && usedLike {
		Q.Content += fmt.Sprintf(" (%d/%d)", num, count)
	}

	if err != nil {
		Q = Quote{}

	}

	return
}

// Fetch a quote from the database
func getQuote(command *bot.Cmd) (msg string, err error) {
	args := command.Args
	var lastArgNum uint

	if len(command.Args) > 0 {
		lastArg := args[len(args)-1]
		lan, err := strconv.Atoi(lastArg)
		if err != nil {
			lastArgNum = uint(0)
			err = nil
		} else {
			lastArgNum = uint(lan)
			args = args[:len(args)-1]

		}
	}

	m := make(map[string]interface{})
	m["channel = ?"] = command.Channel

	switch {
	case len(args) == 1 && args[0] == "-id":
		m["id = ?"] = lastArgNum
	case len(args) > 0:
		m["content LIKE ?"] = fmt.Sprintf("%%%s%%", strings.Join(args, " "))
	}

	Q := queryToQuote(m, lastArgNum)
	if Q.ID != 0 {
		msg = fmt.Sprintf("#%d: %s", Q.ID, Q.Content)
	}

	return
}

func init() {
	setupDb()

	bot.RegisterCommand(
		"addquote",
		"Add a quote to the bot",
		"",
		addQuote)

	bot.RegisterCommand(
		"quote",
		"Get a quote from the bot",
		"[-id <id>|<[querystring] [<nth match>]]",
		getQuote)

	bot.RegisterCommand(
		"q",
		"Alias for !quote",
		"",
		getQuote)

	// todo:
	// - lastquote
	// - delquote (passive, maybe?)
	// - quoteinfo
	// - quotehelp (passive, query only)
}
<commit_msg>Better logging.<commit_after>package quotes

import (
	"database/sql"
	"errors"
	"fmt"
	"log"
	"math/rand"
	"strconv"
	"strings"
	"time"

	"github.com/doenietzomoeilijk/go-chat-bot-plugins/authorization"
	"github.com/go-chat-bot/bot"
	_ "github.com/mattn/go-sqlite3" // Use sqlite3
)

var (
	db *sql.DB
)

// Quote holds a singular quote
type Quote struct {
	ID        uint      `db:"id"`
	Channel   string    `db:"channel"`
	Author    string    `db:"author"`
	Timestamp time.Time `db:"timestamp"`
	Content   string    `db:"content"`
}

/**
 * Set up our DB - make sure it exists and that it has the proper table.
 */
func setupDb() {
	var err error

	db, err = sql.Open("sqlite3", "quotes.db")
	if err != nil {
		log.Fatal(err)
	}

	_, err = db.Exec(`CREATE TABLE IF NOT EXISTS quotes (
        id INTEGER NOT NULL PRIMARY KEY,
        channel VARCHAR(50) NOT NULL DEFAULT 'unknown',
        author VARCHAR(15) NOT NULL DEFAULT 'unknown',
        timestamp DATETIME NULL,
        deleted TINYINT UNSIGNED NOT NULL DEFAULT 0,
        content TEXT
    )`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS chan ON quotes(channel)`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS idel ON quotes(deleted)`)
	_, err = db.Exec(`CREATE INDEX IF NOT EXISTS cont ON quotes(content)`)
}

func addQuote(command *bot.Cmd) (msg string, err error) {
	var insertID int64

	author, err := authorization.Authorize(command.ChannelData, "author", command.User)
	if err != nil {
		log.Println("Could not authorize:", err)
		return "", nil
	}

	quote := strings.Join(command.Args, " ")
	if quote == "" {
		return
	}

	res, err := db.Exec(
		`INSERT INTO quotes
        (channel, author, timestamp, content)
        VALUES (?, ?, CURRENT_TIMESTAMP, ?)`,
		command.Channel,
		author,
		quote)

	if err != nil {
		log.Println("Could not insert quote:", err)
		err = errors.New("could not insert quote")
		return
	}

	insertID, err = res.LastInsertId()
	if err == nil {
		msg = fmt.Sprintf("Quote inserted with id %d.", insertID)
		log.Println(msg)
	} else {
		log.Println("error while inserting quote", err)
		err = nil
	}

	return
}

func queryToQuote(w map[string]interface{}, num uint) (Q Quote) {
	fields := "id, channel, author, timestamp, content"
	query := "SELECT %s FROM quotes WHERE deleted = 0"
	var binds []interface{}
	var usedLike bool

	for where, bind := range w {
		query += fmt.Sprintf(" AND %s", where)
		binds = append(binds, bind)
		if strings.Contains(where, "LIKE") {
			usedLike = true
		}
	}

	var count int
	countRow := db.QueryRow(fmt.Sprintf(query, "COUNT(*)"), binds...)
	err := countRow.Scan(&count)

	if count == 0 || err != nil {
		return
	}

	if count > 1 {
		if num == 0 {
			num = uint(rand.Intn(count)) + 1
		}

		query += fmt.Sprintf(" LIMIT 1 OFFSET %d", num-1)
	}

	query = fmt.Sprintf(query, fields)

	row := db.QueryRow(query, binds...)
	err = row.Scan(&Q.ID, &Q.Channel, &Q.Author, &Q.Timestamp, &Q.Content)
	if count > 1 && usedLike {
		Q.Content += fmt.Sprintf(" (%d/%d)", num, count)
	}

	if err != nil {
		Q = Quote{}

	}

	return
}

// Fetch a quote from the database
func getQuote(command *bot.Cmd) (msg string, err error) {
	args := command.Args
	var lastArgNum uint

	if len(command.Args) > 0 {
		lastArg := args[len(args)-1]
		lan, err := strconv.Atoi(lastArg)
		if err != nil {
			lastArgNum = uint(0)
			err = nil
		} else {
			lastArgNum = uint(lan)
			args = args[:len(args)-1]

		}
	}

	m := make(map[string]interface{})
	m["channel = ?"] = command.Channel

	switch {
	case len(args) == 1 && args[0] == "-id":
		m["id = ?"] = lastArgNum
	case len(args) > 0:
		m["content LIKE ?"] = fmt.Sprintf("%%%s%%", strings.Join(args, " "))
	}

	Q := queryToQuote(m, lastArgNum)
	if Q.ID != 0 {
		msg = fmt.Sprintf("#%d: %s", Q.ID, Q.Content)
	}

	return
}

func init() {
	setupDb()

	bot.RegisterCommand(
		"addquote",
		"Add a quote to the bot",
		"",
		addQuote)

	bot.RegisterCommand(
		"quote",
		"Get a quote from the bot",
		"[-id <id>|<[querystring] [<nth match>]]",
		getQuote)

	bot.RegisterCommand(
		"q",
		"Alias for !quote",
		"",
		getQuote)

	// todo:
	// - lastquote
	// - delquote (passive, maybe?)
	// - quoteinfo
	// - quotehelp (passive, query only)
}
<|endoftext|>


<commit_before>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

import (
	"net/http"
	"strings"
)

// DEPRECATED, use DefaultResponseContentType(mime)
var DefaultResponseMimeType string

//PrettyPrintResponses controls the indentation feature of XML and JSON
//serialization in the response methods WriteEntity, WriteAsJson, and
//WriteAsXml.
var PrettyPrintResponses = true

// Response is a wrapper on the actual http ResponseWriter
// It provides several convenience methods to prepare and write response content.
type Response struct {
	http.ResponseWriter
	requestAccept string   // mime-type what the Http Request says it wants to receive
	routeProduces []string // mime-types what the Route says it can produce
	statusCode    int      // HTTP status code that has been written explicity (if zero then net/http has written 200)
	contentLength int      // number of bytes written for the response body
	prettyPrint   bool     // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
	err           error    // err property is kept when WriteError is called
}

// Creates a new response based on a http ResponseWriter.
func NewResponse(httpWriter http.ResponseWriter) *Response {
	return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types
}

// If Accept header matching fails, fall back to this type.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultResponseContentType(restful.MIME_JSON)
func DefaultResponseContentType(mime string) {
	DefaultResponseMimeType = mime
}

// InternalServerError writes the StatusInternalServerError header.
// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
func (r Response) InternalServerError() Response {
	r.WriteHeader(http.StatusInternalServerError)
	return r
}

// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
func (r *Response) PrettyPrint(bePretty bool) {
	r.prettyPrint = bePretty
}

// AddHeader is a shortcut for .Header().Add(header,value)
func (r Response) AddHeader(header string, value string) Response {
	r.Header().Add(header, value)
	return r
}

// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
func (r *Response) SetRequestAccepts(mime string) {
	r.requestAccept = mime
}

// EntityWriter returns the registered EntityWriter that the entity (requested resource)
// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say.
// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable.
func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
	for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
		mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
		if 0 == len(mime) || mime == "*/*" {
			for _, each := range r.routeProduces {
				if MIME_JSON == each {
					return entityAccessRegistry.AccessorAt(MIME_JSON)
				}
				if MIME_XML == each {
					return entityAccessRegistry.AccessorAt(MIME_XML)
				}
			}
		} else { // mime is not blank; see if we have a match in Produces
			for _, each := range r.routeProduces {
				if mime == each {
					if MIME_JSON == each {
						return entityAccessRegistry.AccessorAt(MIME_JSON)
					}
					if MIME_XML == each {
						return entityAccessRegistry.AccessorAt(MIME_XML)
					}
				}
			}
		}
	}
	writer, ok := entityAccessRegistry.AccessorAt(r.requestAccept)
	if !ok {
		// if not registered then fallback to the defaults (if set)
		if DefaultResponseMimeType == MIME_JSON {
			return entityAccessRegistry.AccessorAt(MIME_JSON)
		}
		if DefaultResponseMimeType == MIME_XML {
			return entityAccessRegistry.AccessorAt(MIME_XML)
		}
		if trace {
			traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
		}
	}
	return writer, ok
}

// WriteEntity calls WriteStatusWithEntity with Http Status OK (200).
func (r *Response) WriteEntity(value interface{}) error {
	return r.WriteStatusWithEntity(http.StatusOK, value)
}

// WriteEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters.
// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces.
// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead.
// If there is no writer available that can represent the value in the request MIME type then Http Status NotAcceptable is written.
// Current implementation ignores any q-parameters in the Accept Header.
// Returns an error if the value could not be send as the response.
func (r *Response) WriteStatusWithEntity(status int, value interface{}) error {
	if value == nil { // do not write a nil representation
		return nil
	}
	writer, ok := r.EntityWriter()
	if !ok {
		status = http.StatusNotAcceptable
		value = nil
	}
	return writer.Write(r, status, value)
}

// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
// It uses the standard encoding/xml package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteAsXml(value interface{}) error {
	return writeXML(r, http.StatusOK, MIME_XML, value)
}

// WriteAsJson is a convenience method for writing a value in json.
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteAsJson(value interface{}) error {
	return writeJSON(r, http.StatusOK, MIME_JSON, value)
}

// WriteJson is a convenience method for writing a value in Json with a given Content-Type.
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteJson(value interface{}, contentType string) error {
	return writeJSON(r, http.StatusOK, contentType, value)
}

// WriteError write the http status and the error string on the response.
func (r *Response) WriteError(httpStatus int, err error) error {
	r.err = err
	return r.WriteErrorString(httpStatus, err.Error())
}

// WriteServiceError is a convenience method for a responding with a status and a ServiceError
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
	return r.WriteStatusWithEntity(httpStatus, err)
}

// WriteErrorString is a convenience method for an error status with the actual error
func (r *Response) WriteErrorString(httpStatus int, errorReason string) error {
	r.WriteHeader(httpStatus)
	if _, err := r.Write([]byte(errorReason)); err != nil {
		return err
	}
	return nil
}

// WriteHeader is overridden to remember the Status Code that has been written.
func (r *Response) WriteHeader(httpStatus int) {
	r.statusCode = httpStatus
	r.ResponseWriter.WriteHeader(httpStatus)
}

// StatusCode returns the code that has been written using WriteHeader.
// If WriteHeader, WriteEntity or WriteAsXml has not been called (yet) then return 200 OK.
func (r Response) StatusCode() int {
	if 0 == r.statusCode {
		// no status code has been written yet; assume OK
		return http.StatusOK
	}
	return r.statusCode
}

// Write writes the data to the connection as part of an HTTP reply.
// Write is part of http.ResponseWriter interface.
func (r *Response) Write(bytes []byte) (int, error) {
	written, err := r.ResponseWriter.Write(bytes)
	r.contentLength += written
	return written, err
}

// ContentLength returns the number of bytes written for the response content.
// Note that this value is only correct if all data is written through the Response using its Write* methods.
// Data written directly using the underlying http.ResponseWriter is not accounted for.
func (r Response) ContentLength() int {
	return r.contentLength
}

// CloseNotify is part of http.CloseNotifier interface
func (r Response) CloseNotify() <-chan bool {
	return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

// Error returns the err created by WriteError
func (r Response) Error() error {
	return r.err
}
<commit_msg>add writeJson variants<commit_after>package restful

// Copyright 2013 Ernest Micklei. All rights reserved.
// Use of this source code is governed by a license
// that can be found in the LICENSE file.

import (
	"net/http"
	"strings"
)

// DEPRECATED, use DefaultResponseContentType(mime)
var DefaultResponseMimeType string

//PrettyPrintResponses controls the indentation feature of XML and JSON
//serialization in the response methods WriteEntity, WriteAsJson, and
//WriteAsXml.
var PrettyPrintResponses = true

// Response is a wrapper on the actual http ResponseWriter
// It provides several convenience methods to prepare and write response content.
type Response struct {
	http.ResponseWriter
	requestAccept string   // mime-type what the Http Request says it wants to receive
	routeProduces []string // mime-types what the Route says it can produce
	statusCode    int      // HTTP status code that has been written explicity (if zero then net/http has written 200)
	contentLength int      // number of bytes written for the response body
	prettyPrint   bool     // controls the indentation feature of XML and JSON serialization. It is initialized using var PrettyPrintResponses.
	err           error    // err property is kept when WriteError is called
}

// Creates a new response based on a http ResponseWriter.
func NewResponse(httpWriter http.ResponseWriter) *Response {
	return &Response{httpWriter, "", []string{}, http.StatusOK, 0, PrettyPrintResponses, nil} // empty content-types
}

// If Accept header matching fails, fall back to this type.
// Valid values are restful.MIME_JSON and restful.MIME_XML
// Example:
// 	restful.DefaultResponseContentType(restful.MIME_JSON)
func DefaultResponseContentType(mime string) {
	DefaultResponseMimeType = mime
}

// InternalServerError writes the StatusInternalServerError header.
// DEPRECATED, use WriteErrorString(http.StatusInternalServerError,reason)
func (r Response) InternalServerError() Response {
	r.WriteHeader(http.StatusInternalServerError)
	return r
}

// PrettyPrint changes whether this response must produce pretty (line-by-line, indented) JSON or XML output.
func (r *Response) PrettyPrint(bePretty bool) {
	r.prettyPrint = bePretty
}

// AddHeader is a shortcut for .Header().Add(header,value)
func (r Response) AddHeader(header string, value string) Response {
	r.Header().Add(header, value)
	return r
}

// SetRequestAccepts tells the response what Mime-type(s) the HTTP request said it wants to accept. Exposed for testing.
func (r *Response) SetRequestAccepts(mime string) {
	r.requestAccept = mime
}

// EntityWriter returns the registered EntityWriter that the entity (requested resource)
// can write according to what the request wants (Accept) and what the Route can produce or what the restful defaults say.
// If called before WriteEntity and WriteHeader then a false return value can be used to write a 406: Not Acceptable.
func (r *Response) EntityWriter() (EntityReaderWriter, bool) {
	for _, qualifiedMime := range strings.Split(r.requestAccept, ",") {
		mime := strings.Trim(strings.Split(qualifiedMime, ";")[0], " ")
		if 0 == len(mime) || mime == "*/*" {
			for _, each := range r.routeProduces {
				if MIME_JSON == each {
					return entityAccessRegistry.AccessorAt(MIME_JSON)
				}
				if MIME_XML == each {
					return entityAccessRegistry.AccessorAt(MIME_XML)
				}
			}
		} else { // mime is not blank; see if we have a match in Produces
			for _, each := range r.routeProduces {
				if mime == each {
					if MIME_JSON == each {
						return entityAccessRegistry.AccessorAt(MIME_JSON)
					}
					if MIME_XML == each {
						return entityAccessRegistry.AccessorAt(MIME_XML)
					}
				}
			}
		}
	}
	writer, ok := entityAccessRegistry.AccessorAt(r.requestAccept)
	if !ok {
		// if not registered then fallback to the defaults (if set)
		if DefaultResponseMimeType == MIME_JSON {
			return entityAccessRegistry.AccessorAt(MIME_JSON)
		}
		if DefaultResponseMimeType == MIME_XML {
			return entityAccessRegistry.AccessorAt(MIME_XML)
		}
		if trace {
			traceLogger.Printf("no registered EntityReaderWriter found for %s", r.requestAccept)
		}
	}
	return writer, ok
}

// WriteEntity calls WriteStatusWithEntity with Http Status OK (200) (DEPRECATED)
func (r *Response) WriteEntity(value interface{}) error {
	return r.WriteStatusAndEntity(http.StatusOK, value)
}

// WriteEntity marshals the value using the representation denoted by the Accept Header and the registered EntityWriters.
// If no Accept header is specified (or */*) then respond with the Content-Type as specified by the first in the Route.Produces.
// If an Accept header is specified then respond with the Content-Type as specified by the first in the Route.Produces that is matched with the Accept header.
// If the value is nil then no response is send except for the Http status. You may want to call WriteHeader(http.StatusNotFound) instead.
// If there is no writer available that can represent the value in the request MIME type then Http Status NotAcceptable is written.
// Current implementation ignores any q-parameters in the Accept Header.
// Returns an error if the value could not be send as the response.
func (r *Response) WriteStatusAndEntity(status int, value interface{}) error {
	writer, ok := r.EntityWriter()
	if !ok {
		status = http.StatusNotAcceptable
		value = nil
	}
	return writer.Write(r, status, value)
}

// WriteAsXml is a convenience method for writing a value in xml (requires Xml tags on the value)
// It uses the standard encoding/xml package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteAsXml(value interface{}) error {
	return writeXML(r, http.StatusOK, MIME_XML, value)
}

// WriteStatusAndXml is a convenience method for writing a status and value in xml (requires Xml tags on the value)
// It uses the standard encoding/xml package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteStatusAndXml(status int, value interface{}) error {
	return writeXML(r, status, MIME_XML, value)
}

// WriteAsJson is a convenience method for writing a value in json.
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteAsJson(value interface{}) error {
	return writeJSON(r, http.StatusOK, MIME_JSON, value)
}

// WriteJson is a convenience method for writing a value in Json with a given Content-Type.
// It uses the standard encoding/json package for marshalling the valuel ; not using a registered EntityReaderWriter.
func (r *Response) WriteJson(value interface{}, contentType string) error {
	return writeJSON(r, http.StatusOK, contentType, value)
}

// WriteStatusAndJson is a convenience method for writing the status and a value in Json with a given Content-Type.
// It uses the standard encoding/json package for marshalling the value ; not using a registered EntityReaderWriter.
func (r *Response) WriteStatusAndJson(status int, value interface{}, contentType string) error {
	return writeJSON(r, status, contentType, value)
}

// WriteError write the http status and the error string on the response.
func (r *Response) WriteError(httpStatus int, err error) error {
	r.err = err
	return r.WriteErrorString(httpStatus, err.Error())
}

// WriteServiceError is a convenience method for a responding with a status and a ServiceError
func (r *Response) WriteServiceError(httpStatus int, err ServiceError) error {
	return r.WriteStatusAndEntity(httpStatus, err)
}

// WriteErrorString is a convenience method for an error status with the actual error
func (r *Response) WriteErrorString(httpStatus int, errorReason string) error {
	r.WriteHeader(httpStatus)
	if _, err := r.Write([]byte(errorReason)); err != nil {
		return err
	}
	return nil
}

// WriteHeader is overridden to remember the Status Code that has been written.
func (r *Response) WriteHeader(httpStatus int) {
	r.statusCode = httpStatus
	r.ResponseWriter.WriteHeader(httpStatus)
}

// StatusCode returns the code that has been written using WriteHeader.
// If WriteHeader, WriteEntity or WriteAsXml has not been called (yet) then return 200 OK.
func (r Response) StatusCode() int {
	if 0 == r.statusCode {
		// no status code has been written yet; assume OK
		return http.StatusOK
	}
	return r.statusCode
}

// Write writes the data to the connection as part of an HTTP reply.
// Write is part of http.ResponseWriter interface.
func (r *Response) Write(bytes []byte) (int, error) {
	written, err := r.ResponseWriter.Write(bytes)
	r.contentLength += written
	return written, err
}

// ContentLength returns the number of bytes written for the response content.
// Note that this value is only correct if all data is written through the Response using its Write* methods.
// Data written directly using the underlying http.ResponseWriter is not accounted for.
func (r Response) ContentLength() int {
	return r.contentLength
}

// CloseNotify is part of http.CloseNotifier interface
func (r Response) CloseNotify() <-chan bool {
	return r.ResponseWriter.(http.CloseNotifier).CloseNotify()
}

// Error returns the err created by WriteError
func (r Response) Error() error {
	return r.err
}
<|endoftext|>


<commit_before>package fipple

import (
	"bytes"
	"encoding/json"
	"github.com/wsxiaoys/terminal/color"
	"net/http"
	"strings"
	"sync"
)

// Response represents the response from an http request and has methods to
// make testing easier.
type Response struct {
	*http.Response
	Body     string
	recorder *Recorder
	once     sync.Once
}

// readBody reads r.Response.Body into r.Body. If the content-type is json,
// the body is automatically indented.
func (r *Response) readBody() {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Response.Body)
	body := buf.String()
	// Detect Content-Type and auto-indent if json
	if strings.Contains(r.Header.Get("Content-Type"), "application/json") {
		indBuf := new(bytes.Buffer)
		json.Indent(indBuf, []byte(body), "", "\t")
		body = indBuf.String()
	}
	r.Body = body
}

// AssertOk causes a test error if response code != 200
func (r *Response) AssertOk() {
	r.AssertCode(200)
}

// AssertCode causes a test error if response code != the given code
func (r *Response) AssertCode(code int) {
	if r.StatusCode != code {
		r.PrintErrorOnce()
		r.recorder.t.Errorf("Expected response code %d but got: %d", code, r.StatusCode)
	}
}

// AssertBodyContains causes a test error if the response body does
// not contain the given string.
func (r *Response) AssertBodyContains(str string) {
	if !strings.Contains(r.Body, str) {
		r.PrintErrorOnce()
		r.recorder.t.Errorf("Expected response to contain `%s` but it did not.", str)
	}
}

// PrintError prints some information about the response via t.Errorf. This includes
// a message about the method and path for the sent request, and the entire content
// of the response body.
func (r *Response) PrintError() {
	body := r.Body
	if Colorize {
		body = r.colorBody()
	}
	r.recorder.t.Errorf("%s request to %s failed. Response was: \n%s",
		r.Request.Method,
		r.Request.URL.Path,
		body)
}

// PrintErrorOnce will only print the response if it has not already been printed.
// Useful in cases where there are multiple assertions called on the same response and
// we don't want to repeatedly print out the response body for each assertion failure.
func (r *Response) PrintErrorOnce() {
	r.once.Do(r.PrintError)
}

// colorBody returns a colorized version of the response body.
// By default the color is dark grey-ish.
func (r *Response) colorBody() string {
	return color.Sprintf("@{.}%s", r.Body)
}
<commit_msg>Print out a more accurate message if the body of a response is empty.<commit_after>package fipple

import (
	"bytes"
	"encoding/json"
	"github.com/wsxiaoys/terminal/color"
	"net/http"
	"strings"
	"sync"
)

// Response represents the response from an http request and has methods to
// make testing easier.
type Response struct {
	*http.Response
	Body     string
	recorder *Recorder
	once     sync.Once
}

// readBody reads r.Response.Body into r.Body. If the content-type is json,
// the body is automatically indented.
func (r *Response) readBody() {
	buf := new(bytes.Buffer)
	buf.ReadFrom(r.Response.Body)
	body := buf.String()
	// Detect Content-Type and auto-indent if json
	if strings.Contains(r.Header.Get("Content-Type"), "application/json") {
		indBuf := new(bytes.Buffer)
		json.Indent(indBuf, []byte(body), "", "\t")
		body = indBuf.String()
	}
	r.Body = body
}

// AssertOk causes a test error if response code != 200
func (r *Response) AssertOk() {
	r.AssertCode(200)
}

// AssertCode causes a test error if response code != the given code
func (r *Response) AssertCode(code int) {
	if r.StatusCode != code {
		r.PrintErrorOnce()
		r.recorder.t.Errorf("Expected response code %d but got: %d", code, r.StatusCode)
	}
}

// AssertBodyContains causes a test error if the response body does
// not contain the given string.
func (r *Response) AssertBodyContains(str string) {
	if !strings.Contains(r.Body, str) {
		r.PrintErrorOnce()
		r.recorder.t.Errorf("Expected response to contain `%s` but it did not.", str)
	}
}

// PrintError prints some information about the response via t.Errorf. This includes
// a message about the method and path for the sent request, and the entire content
// of the response body.
func (r *Response) PrintError() {
	body := r.Body
	if body == "" {
		r.recorder.t.Errorf("%s request to %s failed. Response was empty.",
			r.Request.Method,
			r.Request.URL.Path)
	} else {
		if Colorize {
			body = r.colorBody()
		}
		r.recorder.t.Errorf("%s request to %s failed. Response was: \n%s",
			r.Request.Method,
			r.Request.URL.Path,
			body)
	}
}

// PrintErrorOnce will only print the response if it has not already been printed.
// Useful in cases where there are multiple assertions called on the same response and
// we don't want to repeatedly print out the response body for each assertion failure.
func (r *Response) PrintErrorOnce() {
	r.once.Do(r.PrintError)
}

// colorBody returns a colorized version of the response body.
// By default the color is dark grey-ish.
func (r *Response) colorBody() string {
	return color.Sprintf("@{.}%s", r.Body)
}
<|endoftext|>


<commit_before>package restless

import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "labix.org/v2/mgo"
    "labix.org/v2/mgo/bson"
    "net/http"
)

func GetAll(c *mgo.Collection, ip interface{}) {
    c.Find(nil).All(ip)
}

func Insert(c *mgo.Collection, i interface{}) (string, error) {
    info, err := c.Upsert(bson.M{"_id": nil}, i)
    id := info.UpsertedId.(bson.ObjectId)
    return id.Hex(), err
}

func RemoveId(c *mgo.Collection, id bson.ObjectId) error {
    return c.RemoveId(id)
}

func GetId(c *mgo.Collection, i interface{}, id bson.ObjectId) error {
    return c.FindId(id).One(i)
}

func UpdateId(c *mgo.Collection, i interface{}, id bson.ObjectId) error {
    return c.UpdateId(id, i)
}

func GetGenHandler(s *mgo.Session, dbName string, colName string, cns Constructor) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var jdata []byte
        var err error

        ns := s.Clone()
        defer ns.Close()

        col := ns.DB(dbName).C(colName)

        switch r.Method {
        //TODO: Add ability to queary specifics
        case "GET":
            i := cns.Slice()
            GetAll(col, i)
            jdata, err = json.Marshal(i)

            w.Header().Add("Content-Type", "application/json")
            fmt.Fprintf(w, "[]%s=%s", colName, jdata)

        case "POST":
            var lastId string

            i := cns.Single()
            if err = r.ParseForm(); err != nil {
                http.Error(w, "Unable to parse form", http.StatusBadRequest)
                Log.Errorf("Parsing form : %s", err)
            }

            jString := []byte(r.PostForm.Get("json"))
            if err = json.Unmarshal(jString, i); err != nil {
                http.Error(w, "Unable to unmarshal data", http.StatusBadRequest)
                Log.Errorf("UnMarshal error : %s", err)
                return
            }

            if lastId, err = Insert(col, i); err != nil {
                http.Error(w, "Unable to unmarshal data", http.StatusInternalServerError)
                Log.Errorf("Insert Error : %#v", err)
                return
            }

            if jdata, err = json.Marshal(i); err != nil {
                http.Error(w, "Marshal error", http.StatusInternalServerError)
            }
            w.Header().Add("Location", fmt.Sprintf("%s/%s", r.URL, lastId))
            w.WriteHeader(http.StatusCreated)
        }
        return
    }
}

func GetIdHandler(s *mgo.Session, dbName string, colName string, cns Constructor) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var jdata []byte
        var err error
        var ids string

        ns := s.Clone()
        defer ns.Close()

        vars := mux.Vars(r)
        ids = vars["id"]
        Log.Debugf("Provided ID = %s", ids)

        col := ns.DB(dbName).C(colName)

        if !bson.IsObjectIdHex(ids) {
            http.Error(w, "Provided ID is unknown", http.StatusNotFound)
            return
        }

        id := bson.ObjectIdHex(ids)
        i := cns.Single()

        if err = GetId(col, i, id); err != nil {
            http.Error(w, "Provided ID is unknown", http.StatusNotFound)
            return
        }

        if jdata, err = json.Marshal(i); err != nil {
            http.Error(w, "", http.StatusBadRequest)
        }

        switch r.Method {
        case "GET":
            w.Header().Add("Content-Type", "application/json")
            fmt.Fprintf(w, "%s=%s", colName, jdata)

        case "PUT":
            if r.ParseForm(); err != nil {
                http.Error(w, "", http.StatusBadRequest)
            }

            if err = json.Unmarshal([]byte(r.PostForm.Get("json")), i); err != nil {
                http.Error(w, "", http.StatusBadRequest)
                Log.Errorf("UnMarshal error : %s", err)
            }

            if err = UpdateId(col, i, id); err != nil {
                http.Error(w, "Failed to update provided ID", http.StatusInternalServerError)
                Log.Errorf("UnMarshal error : %s", err)
            }

        case "DELETE":
            if err = RemoveId(col, id); err != nil {
                http.Error(w, "Failed to remove provided ID", http.StatusInternalServerError)
                Log.Errorf("Failed to remove id %s; error : %s", id, err)
            }
        }
        return
    }
}
<commit_msg>Found error<commit_after>package restless

import (
    "encoding/json"
    "fmt"
    "github.com/gorilla/mux"
    "labix.org/v2/mgo"
    "labix.org/v2/mgo/bson"
    "net/http"
)

func GetAll(c *mgo.Collection, ip interface{}) {
    c.Find(nil).All(ip)
}

func Insert(c *mgo.Collection, i interface{}) (string, error) {
    info, err := c.Upsert(bson.M{"_id": nil}, i)
    id := info.UpsertedId.(bson.ObjectId)
    return id.Hex(), err
}

func RemoveId(c *mgo.Collection, id bson.ObjectId) error {
    return c.RemoveId(id)
}

func GetId(c *mgo.Collection, i interface{}, id bson.ObjectId) error {
    return c.FindId(id).One(i)
}

func UpdateId(c *mgo.Collection, i interface{}, id bson.ObjectId) error {
    return c.UpdateId(id, i)
}

func GetGenHandler(s *mgo.Session, dbName string, colName string, cns Constructor) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var jdata []byte
        var err error

        ns := s.Clone()
        defer ns.Close()

        col := ns.DB(dbName).C(colName)

        switch r.Method {
        //TODO: Add ability to queary specifics
        case "GET":
            i := cns.Slice()
            GetAll(col, i)
            jdata, err = json.Marshal(i)

            w.Header().Add("Content-Type", "application/json")
            fmt.Fprintf(w, "[]%s=%s", colName, jdata)

        case "POST":
            var lastId string

            i := cns.Single()
            if err = r.ParseForm(); err != nil {
                http.Error(w, "Unable to parse form", http.StatusBadRequest)
                Log.Errorf("Parsing form : %s", err)
            }

            jString := []byte(r.PostForm.Get(colName))
            if err = json.Unmarshal(jString, i); err != nil {
                http.Error(w, "Unable to unmarshal data", http.StatusBadRequest)
                Log.Errorf("UnMarshal error : %s", err)
                return
            }

            if lastId, err = Insert(col, i); err != nil {
                http.Error(w, "Unable to unmarshal data", http.StatusInternalServerError)
                Log.Errorf("Insert Error : %#v", err)
                return
            }

            if jdata, err = json.Marshal(i); err != nil {
                http.Error(w, "Marshal error", http.StatusInternalServerError)
            }
            w.Header().Add("Location", fmt.Sprintf("%s/%s", r.URL, lastId))
            w.WriteHeader(http.StatusCreated)
        }
        return
    }
}

func GetIdHandler(s *mgo.Session, dbName string, colName string, cns Constructor) http.HandlerFunc {
    return func(w http.ResponseWriter, r *http.Request) {

        var jdata []byte
        var err error
        var ids string

        ns := s.Clone()
        defer ns.Close()

        vars := mux.Vars(r)
        ids = vars["id"]
        Log.Debugf("Provided ID = %s", ids)

        col := ns.DB(dbName).C(colName)

        if !bson.IsObjectIdHex(ids) {
            http.Error(w, "Provided ID is unknown", http.StatusNotFound)
            return
        }

        id := bson.ObjectIdHex(ids)
        i := cns.Single()

        if err = GetId(col, i, id); err != nil {
            http.Error(w, "Provided ID is unknown", http.StatusNotFound)
            return
        }

        if jdata, err = json.Marshal(i); err != nil {
            http.Error(w, "", http.StatusBadRequest)
        }

        switch r.Method {
        case "GET":
            w.Header().Add("Content-Type", "application/json")
            fmt.Fprintf(w, "%s=%s", colName, jdata)

        case "PUT":
            if r.ParseForm(); err != nil {
                http.Error(w, "", http.StatusBadRequest)
            }

            if err = json.Unmarshal([]byte(r.PostForm.Get(colName)), i); err != nil {
                http.Error(w, "", http.StatusBadRequest)
                Log.Errorf("UnMarshal error : %s", err)
            }

            if err = UpdateId(col, i, id); err != nil {
                http.Error(w, "Failed to update provided ID", http.StatusInternalServerError)
                Log.Errorf("UnMarshal error : %s", err)
            }

        case "DELETE":
            if err = RemoveId(col, id); err != nil {
                http.Error(w, "Failed to remove provided ID", http.StatusInternalServerError)
                Log.Errorf("Failed to remove id %s; error : %s", id, err)
            }
        }
        return
    }
}
<|endoftext|>


<commit_before>/*
Copyright 2016 The Kubernetes Authors.

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 cloud

import (
	"context"
	"errors"
	"fmt"
	"time"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	v1lister "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/record"
	cloudprovider "k8s.io/cloud-provider"
	cloudproviderapi "k8s.io/cloud-provider/api"
	cloudnodeutil "k8s.io/cloud-provider/node/helpers"
	"k8s.io/klog/v2"
)

const (
	deleteNodeEvent = "DeletingNode"
)

var ShutdownTaint = &v1.Taint{
	Key:    cloudproviderapi.TaintNodeShutdown,
	Effect: v1.TaintEffectNoSchedule,
}

// CloudNodeLifecycleController is responsible for deleting/updating kubernetes
// nodes that have been deleted/shutdown on the cloud provider
type CloudNodeLifecycleController struct {
	kubeClient clientset.Interface
	nodeLister v1lister.NodeLister
	recorder   record.EventRecorder

	cloud cloudprovider.Interface

	// Value controlling NodeController monitoring period, i.e. how often does NodeController
	// check node status posted from kubelet. This value should be lower than nodeMonitorGracePeriod
	// set in controller-manager
	nodeMonitorPeriod time.Duration
}

func NewCloudNodeLifecycleController(
	nodeInformer coreinformers.NodeInformer,
	kubeClient clientset.Interface,
	cloud cloudprovider.Interface,
	nodeMonitorPeriod time.Duration) (*CloudNodeLifecycleController, error) {

	eventBroadcaster := record.NewBroadcaster()
	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cloud-node-lifecycle-controller"})
	eventBroadcaster.StartStructuredLogging(0)

	klog.Info("Sending events to api server")
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})

	if kubeClient == nil {
		return nil, errors.New("kubernetes client is nil")
	}

	if cloud == nil {
		return nil, errors.New("no cloud provider provided")
	}

	_, instancesSupported := cloud.Instances()
	_, instancesV2Supported := cloud.InstancesV2()
	if !instancesSupported && !instancesV2Supported {
		return nil, errors.New("cloud provider does not support instances")
	}

	c := &CloudNodeLifecycleController{
		kubeClient:        kubeClient,
		nodeLister:        nodeInformer.Lister(),
		recorder:          recorder,
		cloud:             cloud,
		nodeMonitorPeriod: nodeMonitorPeriod,
	}

	return c, nil
}

// Run starts the main loop for this controller. Run is blocking so should
// be called via a goroutine
func (c *CloudNodeLifecycleController) Run(stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	// The following loops run communicate with the APIServer with a worst case complexity
	// of O(num_nodes) per cycle. These functions are justified here because these events fire
	// very infrequently. DO NOT MODIFY this to perform frequent operations.

	// Start a loop to periodically check if any nodes have been
	// deleted or shutdown from the cloudprovider
	wait.Until(c.MonitorNodes, c.nodeMonitorPeriod, stopCh)
}

// MonitorNodes checks to see if nodes in the cluster have been deleted
// or shutdown. If deleted, it deletes the node resource. If shutdown it
// applies a shutdown taint to the node
func (c *CloudNodeLifecycleController) MonitorNodes() {
	nodes, err := c.nodeLister.List(labels.Everything())
	if err != nil {
		klog.Errorf("error listing nodes from cache: %s", err)
		return
	}

	for _, node := range nodes {
		// Default NodeReady status to v1.ConditionUnknown
		status := v1.ConditionUnknown
		if _, c := cloudnodeutil.GetNodeCondition(&node.Status, v1.NodeReady); c != nil {
			status = c.Status
		}

		if status == v1.ConditionTrue {
			// if taint exist remove taint
			err = cloudnodeutil.RemoveTaintOffNode(c.kubeClient, node.Name, node, ShutdownTaint)
			if err != nil {
				klog.Errorf("error patching node taints: %v", err)
			}
			continue
		}

		// At this point the node has NotReady status, we need to check if the node has been removed
		// from the cloud provider. If node cannot be found in cloudprovider, then delete the node
		exists, err := ensureNodeExistsByProviderID(context.TODO(), c.cloud, node)
		if err != nil {
			klog.Errorf("error checking if node %s exists: %v", node.Name, err)
			continue
		}

		if !exists {
			// Current node does not exist, we should delete it, its taints do not matter anymore

			klog.V(2).Infof("deleting node since it is no longer present in cloud provider: %s", node.Name)

			ref := &v1.ObjectReference{
				Kind:      "Node",
				Name:      node.Name,
				UID:       types.UID(node.UID),
				Namespace: "",
			}

			c.recorder.Eventf(ref, v1.EventTypeNormal,
				fmt.Sprintf("Deleting node %v because it does not exist in the cloud provider", node.Name),
				"Node %s event: %s", node.Name, deleteNodeEvent)

			if err := c.kubeClient.CoreV1().Nodes().Delete(context.TODO(), node.Name, metav1.DeleteOptions{}); err != nil {
				klog.Errorf("unable to delete node %q: %v", node.Name, err)
			}
		} else {
			// Node exists. We need to check this to get taint working in similar in all cloudproviders
			// current problem is that shutdown nodes are not working in similar way ie. all cloudproviders
			// does not delete node from kubernetes cluster when instance it is shutdown see issue #46442
			shutdown, err := shutdownInCloudProvider(context.TODO(), c.cloud, node)
			if err != nil {
				klog.Errorf("error checking if node %s is shutdown: %v", node.Name, err)
			}

			if shutdown && err == nil {
				// if node is shutdown add shutdown taint
				err = cloudnodeutil.AddOrUpdateTaintOnNode(c.kubeClient, node.Name, ShutdownTaint)
				if err != nil {
					klog.Errorf("failed to apply shutdown taint to node %s, it may have been deleted.", node.Name)
				}
			}
		}
	}
}

// shutdownInCloudProvider returns true if the node is shutdown on the cloud provider
func shutdownInCloudProvider(ctx context.Context, cloud cloudprovider.Interface, node *v1.Node) (bool, error) {
	if instanceV2, ok := cloud.InstancesV2(); ok {
		return instanceV2.InstanceShutdown(ctx, node)
	}

	instances, ok := cloud.Instances()
	if !ok {
		return false, errors.New("cloud provider does not support instances")
	}

	shutdown, err := instances.InstanceShutdownByProviderID(ctx, node.Spec.ProviderID)
	if err == cloudprovider.NotImplemented {
		return false, nil
	}

	return shutdown, err
}

// ensureNodeExistsByProviderID checks if the instance exists by the provider id,
// If provider id in spec is empty it calls instanceId with node name to get provider id
func ensureNodeExistsByProviderID(ctx context.Context, cloud cloudprovider.Interface, node *v1.Node) (bool, error) {
	if instanceV2, ok := cloud.InstancesV2(); ok {
		return instanceV2.InstanceExists(ctx, node)
	}

	instances, ok := cloud.Instances()
	if !ok {
		return false, errors.New("instances interface not supported in the cloud provider")
	}

	providerID := node.Spec.ProviderID
	if providerID == "" {
		var err error
		providerID, err = instances.InstanceID(ctx, types.NodeName(node.Name))
		if err != nil {
			if err == cloudprovider.InstanceNotFound {
				return false, nil
			}
			return false, err
		}

		if providerID == "" {
			klog.Warningf("Cannot find valid providerID for node name %q, assuming non existence", node.Name)
			return false, nil
		}
	}

	return instances.InstanceExistsByProviderID(ctx, providerID)
}
<commit_msg>Using UpperCamelCase event reason - DeletingNode, instead of verbose msg<commit_after>/*
Copyright 2016 The Kubernetes Authors.

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 cloud

import (
	"context"
	"errors"
	"time"

	"k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"k8s.io/apimachinery/pkg/types"
	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
	"k8s.io/apimachinery/pkg/util/wait"
	coreinformers "k8s.io/client-go/informers/core/v1"
	clientset "k8s.io/client-go/kubernetes"
	"k8s.io/client-go/kubernetes/scheme"
	v1core "k8s.io/client-go/kubernetes/typed/core/v1"
	v1lister "k8s.io/client-go/listers/core/v1"
	"k8s.io/client-go/tools/record"
	cloudprovider "k8s.io/cloud-provider"
	cloudproviderapi "k8s.io/cloud-provider/api"
	cloudnodeutil "k8s.io/cloud-provider/node/helpers"
	"k8s.io/klog/v2"
)

const (
	deleteNodeEvent = "DeletingNode"
)

var ShutdownTaint = &v1.Taint{
	Key:    cloudproviderapi.TaintNodeShutdown,
	Effect: v1.TaintEffectNoSchedule,
}

// CloudNodeLifecycleController is responsible for deleting/updating kubernetes
// nodes that have been deleted/shutdown on the cloud provider
type CloudNodeLifecycleController struct {
	kubeClient clientset.Interface
	nodeLister v1lister.NodeLister
	recorder   record.EventRecorder

	cloud cloudprovider.Interface

	// Value controlling NodeController monitoring period, i.e. how often does NodeController
	// check node status posted from kubelet. This value should be lower than nodeMonitorGracePeriod
	// set in controller-manager
	nodeMonitorPeriod time.Duration
}

func NewCloudNodeLifecycleController(
	nodeInformer coreinformers.NodeInformer,
	kubeClient clientset.Interface,
	cloud cloudprovider.Interface,
	nodeMonitorPeriod time.Duration) (*CloudNodeLifecycleController, error) {

	eventBroadcaster := record.NewBroadcaster()
	recorder := eventBroadcaster.NewRecorder(scheme.Scheme, v1.EventSource{Component: "cloud-node-lifecycle-controller"})
	eventBroadcaster.StartStructuredLogging(0)

	klog.Info("Sending events to api server")
	eventBroadcaster.StartRecordingToSink(&v1core.EventSinkImpl{Interface: kubeClient.CoreV1().Events("")})

	if kubeClient == nil {
		return nil, errors.New("kubernetes client is nil")
	}

	if cloud == nil {
		return nil, errors.New("no cloud provider provided")
	}

	_, instancesSupported := cloud.Instances()
	_, instancesV2Supported := cloud.InstancesV2()
	if !instancesSupported && !instancesV2Supported {
		return nil, errors.New("cloud provider does not support instances")
	}

	c := &CloudNodeLifecycleController{
		kubeClient:        kubeClient,
		nodeLister:        nodeInformer.Lister(),
		recorder:          recorder,
		cloud:             cloud,
		nodeMonitorPeriod: nodeMonitorPeriod,
	}

	return c, nil
}

// Run starts the main loop for this controller. Run is blocking so should
// be called via a goroutine
func (c *CloudNodeLifecycleController) Run(stopCh <-chan struct{}) {
	defer utilruntime.HandleCrash()

	// The following loops run communicate with the APIServer with a worst case complexity
	// of O(num_nodes) per cycle. These functions are justified here because these events fire
	// very infrequently. DO NOT MODIFY this to perform frequent operations.

	// Start a loop to periodically check if any nodes have been
	// deleted or shutdown from the cloudprovider
	wait.Until(c.MonitorNodes, c.nodeMonitorPeriod, stopCh)
}

// MonitorNodes checks to see if nodes in the cluster have been deleted
// or shutdown. If deleted, it deletes the node resource. If shutdown it
// applies a shutdown taint to the node
func (c *CloudNodeLifecycleController) MonitorNodes() {
	nodes, err := c.nodeLister.List(labels.Everything())
	if err != nil {
		klog.Errorf("error listing nodes from cache: %s", err)
		return
	}

	for _, node := range nodes {
		// Default NodeReady status to v1.ConditionUnknown
		status := v1.ConditionUnknown
		if _, c := cloudnodeutil.GetNodeCondition(&node.Status, v1.NodeReady); c != nil {
			status = c.Status
		}

		if status == v1.ConditionTrue {
			// if taint exist remove taint
			err = cloudnodeutil.RemoveTaintOffNode(c.kubeClient, node.Name, node, ShutdownTaint)
			if err != nil {
				klog.Errorf("error patching node taints: %v", err)
			}
			continue
		}

		// At this point the node has NotReady status, we need to check if the node has been removed
		// from the cloud provider. If node cannot be found in cloudprovider, then delete the node
		exists, err := ensureNodeExistsByProviderID(context.TODO(), c.cloud, node)
		if err != nil {
			klog.Errorf("error checking if node %s exists: %v", node.Name, err)
			continue
		}

		if !exists {
			// Current node does not exist, we should delete it, its taints do not matter anymore

			klog.V(2).Infof("deleting node since it is no longer present in cloud provider: %s", node.Name)

			ref := &v1.ObjectReference{
				Kind:      "Node",
				Name:      node.Name,
				UID:       types.UID(node.UID),
				Namespace: "",
			}

			c.recorder.Eventf(ref, v1.EventTypeNormal, deleteNodeEvent,
				"Deleting node %s because it does not exist in the cloud provider", node.Name)

			if err := c.kubeClient.CoreV1().Nodes().Delete(context.TODO(), node.Name, metav1.DeleteOptions{}); err != nil {
				klog.Errorf("unable to delete node %q: %v", node.Name, err)
			}
		} else {
			// Node exists. We need to check this to get taint working in similar in all cloudproviders
			// current problem is that shutdown nodes are not working in similar way ie. all cloudproviders
			// does not delete node from kubernetes cluster when instance it is shutdown see issue #46442
			shutdown, err := shutdownInCloudProvider(context.TODO(), c.cloud, node)
			if err != nil {
				klog.Errorf("error checking if node %s is shutdown: %v", node.Name, err)
			}

			if shutdown && err == nil {
				// if node is shutdown add shutdown taint
				err = cloudnodeutil.AddOrUpdateTaintOnNode(c.kubeClient, node.Name, ShutdownTaint)
				if err != nil {
					klog.Errorf("failed to apply shutdown taint to node %s, it may have been deleted.", node.Name)
				}
			}
		}
	}
}

// shutdownInCloudProvider returns true if the node is shutdown on the cloud provider
func shutdownInCloudProvider(ctx context.Context, cloud cloudprovider.Interface, node *v1.Node) (bool, error) {
	if instanceV2, ok := cloud.InstancesV2(); ok {
		return instanceV2.InstanceShutdown(ctx, node)
	}

	instances, ok := cloud.Instances()
	if !ok {
		return false, errors.New("cloud provider does not support instances")
	}

	shutdown, err := instances.InstanceShutdownByProviderID(ctx, node.Spec.ProviderID)
	if err == cloudprovider.NotImplemented {
		return false, nil
	}

	return shutdown, err
}

// ensureNodeExistsByProviderID checks if the instance exists by the provider id,
// If provider id in spec is empty it calls instanceId with node name to get provider id
func ensureNodeExistsByProviderID(ctx context.Context, cloud cloudprovider.Interface, node *v1.Node) (bool, error) {
	if instanceV2, ok := cloud.InstancesV2(); ok {
		return instanceV2.InstanceExists(ctx, node)
	}

	instances, ok := cloud.Instances()
	if !ok {
		return false, errors.New("instances interface not supported in the cloud provider")
	}

	providerID := node.Spec.ProviderID
	if providerID == "" {
		var err error
		providerID, err = instances.InstanceID(ctx, types.NodeName(node.Name))
		if err != nil {
			if err == cloudprovider.InstanceNotFound {
				return false, nil
			}
			return false, err
		}

		if providerID == "" {
			klog.Warningf("Cannot find valid providerID for node name %q, assuming non existence", node.Name)
			return false, nil
		}
	}

	return instances.InstanceExistsByProviderID(ctx, providerID)
}
<|endoftext|>


<commit_before>package ui

import (
	"image"
	"image/color"
	"time"

	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
)

var enableClockPane = config.Bool(true, "led.clock.enabled")

type ClockPane struct{}

func NewClockPane() *ClockPane {
	return &ClockPane{}
}

func (p *ClockPane) IsEnabled() bool {
	return enableClockPane
}

func (p *ClockPane) Gesture(gesture *gestic.GestureMessage) {

}

func (p *ClockPane) Render() (*image.RGBA, error) {
	img := image.NewRGBA(image.Rect(0, 0, 16, 16))

	text := time.Now().Format("15:04")

	width := O4b03b.Font.DrawString(img, 0, 0, text, color.Black)

	start := 8 - int((float64(width) / float64(2)))

	O4b03b.Font.DrawString(img, start, 5, text, color.White)

	return img, nil
}

func (p *ClockPane) IsDirty() bool {
	return true
}
<commit_msg>Add tap alarm (double tap to reset) to clock<commit_after>package ui

import (
	"fmt"
	"image"
	"image/color"
	"time"

	"github.com/ninjasphere/gestic-tools/go-gestic-sdk"
	"github.com/ninjasphere/go-ninja/config"
	"github.com/ninjasphere/sphere-go-led-controller/fonts/O4b03b"
)

var enableClockPane = config.Bool(true, "led.clock.enabled")
var enableAlarm = config.Bool(true, "led.clock.alarmEnabled")

type ClockPane struct {
	alarm       *time.Time
	timer       *time.Timer
	tapThrottle *throttle
}

func NewClockPane() *ClockPane {
	var pane *ClockPane
	pane = &ClockPane{
		timer: time.AfterFunc(time.Minute, func() {
			pane.alarm = nil
		}),
		tapThrottle: &throttle{delay: time.Millisecond * 500},
	}
	pane.timer.Stop()

	return pane
}

func (p *ClockPane) IsEnabled() bool {
	return enableClockPane
}

func (p *ClockPane) Gesture(gesture *gestic.GestureMessage) {
	if !enableAlarm {
		return
	}

	if gesture.Tap.Active() && p.tapThrottle.try() {
		if p.alarm == nil {
			x := time.Now().Add(time.Minute)
			p.alarm = &x
		} else {
			x := p.alarm.Add(time.Minute)
			p.alarm = &x
		}

		p.timer.Reset(p.alarm.Sub(time.Now()))
	}

	if gesture.DoubleTap.Active() {
		p.alarm = nil
		p.timer.Stop()
	}
}

func (p *ClockPane) Render() (*image.RGBA, error) {
	img := image.NewRGBA(image.Rect(0, 0, 16, 16))

	var text string
	if p.alarm != nil {
		duration := p.alarm.Sub(time.Now())
		text = fmt.Sprintf("%0d:%0d", int(duration.Minutes()), int(duration.Seconds())-(int(duration.Minutes())*60))
	} else {
		text = time.Now().Format("15:04")
	}
	width := O4b03b.Font.DrawString(img, 0, 0, text, color.Black)
	start := 8 - int((float64(width) / float64(2)))

	O4b03b.Font.DrawString(img, start, 5, text, color.White)

	return img, nil
}

func (p *ClockPane) IsDirty() bool {
	return true
}
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"golang.org/x/net/http2"
	"golang.org/x/net/http2/hpack"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/protocol"
)

var supportedVersions = map[protocol.VersionNumber]bool{
	30: true,
	32: true,
}

func main() {
	path := os.Getenv("GOPATH") + "/src/github.com/lucas-clemente/quic-go/example/"

	server, err := quic.NewServer(path+"cert.der", path+"key.der", handleStream)
	if err != nil {
		panic(err)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello world!"))
	})

	err = server.ListenAndServe("localhost:6121")
	if err != nil {
		panic(err)
	}
}

type responseWriter struct {
	header       http.Header
	headerStream *quic.Stream
	session      *quic.Session
	status       int
	dataStreamID protocol.StreamID
}

func (w *responseWriter) Header() http.Header {
	return w.header
}

func (w *responseWriter) WriteHeader(status int) {
	w.status = status
}

func (w *responseWriter) Write(p []byte) (int, error) {
	if w.status == 0 {
		w.WriteHeader(200)
	}

	var headers bytes.Buffer
	enc := hpack.NewEncoder(&headers)
	enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(w.status)})
	// enc.WriteField(hpack.HeaderField{Name: "content-length", Value: strconv.Itoa(len(p))})
	// enc.WriteField(hpack.HeaderField{Name: "content-type", Value: http.DetectContentType(p)})

	for k, v := range w.header {
		enc.WriteField(hpack.HeaderField{Name: k, Value: v[0]})
	}

	h2framer := http2.NewFramer(w.headerStream, nil)
	h2framer.WriteHeaders(http2.HeadersFrameParam{
		StreamID:      uint32(w.dataStreamID),
		EndHeaders:    true,
		BlockFragment: headers.Bytes(),
	})

	if len(p) != 0 {
		dataStream, err := w.session.NewStream(w.dataStreamID)
		if err != nil {
			return 0, fmt.Errorf("error creating data stream: %s\n", err.Error())
		}
		defer dataStream.Close()
		return dataStream.Write(p)
	}

	return 0, nil
}

func handleStream(session *quic.Session, headerStream *quic.Stream) {
	hpackDecoder := hpack.NewDecoder(1024, nil)
	h2framer := http2.NewFramer(nil, headerStream)
	h2framer.ReadMetaHeaders = hpackDecoder

	go func() {
		for {
			h2frame, err := h2framer.ReadFrame()
			if err != nil {
				fmt.Printf("invalid http2 frame: %s\n", err.Error())
				continue
			}
			h2headersFrame := h2frame.(*http2.MetaHeadersFrame)
			fmt.Printf("Request: %s %s://%s%s\n", h2headersFrame.PseudoValue("method"), h2headersFrame.PseudoValue("scheme"), h2headersFrame.PseudoValue("authority"), h2headersFrame.PseudoValue("path"))

			req, err := http.NewRequest(h2headersFrame.PseudoValue("method"), h2headersFrame.PseudoValue("path"), nil)
			if err != nil {
				fmt.Printf("invalid http2 frame: %s\n", err.Error())
				continue
			}

			responseWriter := &responseWriter{
				header:       http.Header{},
				headerStream: headerStream,
				dataStreamID: protocol.StreamID(h2headersFrame.StreamID),
				session:      session,
			}

			go http.DefaultServeMux.ServeHTTP(responseWriter, req)
		}
	}()
}
<commit_msg>don't use the h2framer's built-in header decoding, it errors with chrome<commit_after>package main

import (
	"bytes"
	"fmt"
	"net/http"
	"os"
	"strconv"

	"golang.org/x/net/http2"
	"golang.org/x/net/http2/hpack"

	"github.com/lucas-clemente/quic-go"
	"github.com/lucas-clemente/quic-go/protocol"
)

var supportedVersions = map[protocol.VersionNumber]bool{
	30: true,
	32: true,
}

func main() {
	path := os.Getenv("GOPATH") + "/src/github.com/lucas-clemente/quic-go/example/"

	server, err := quic.NewServer(path+"cert.der", path+"key.der", handleStream)
	if err != nil {
		panic(err)
	}

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		w.Write([]byte("Hello world!"))
	})

	err = server.ListenAndServe("localhost:6121")
	if err != nil {
		panic(err)
	}
}

type responseWriter struct {
	header       http.Header
	headerStream *quic.Stream
	session      *quic.Session
	status       int
	dataStreamID protocol.StreamID
}

func (w *responseWriter) Header() http.Header {
	return w.header
}

func (w *responseWriter) WriteHeader(status int) {
	w.status = status
}

func (w *responseWriter) Write(p []byte) (int, error) {
	if w.status == 0 {
		w.WriteHeader(200)
	}

	var headers bytes.Buffer
	enc := hpack.NewEncoder(&headers)
	enc.WriteField(hpack.HeaderField{Name: ":status", Value: strconv.Itoa(w.status)})
	// enc.WriteField(hpack.HeaderField{Name: "content-length", Value: strconv.Itoa(len(p))})
	// enc.WriteField(hpack.HeaderField{Name: "content-type", Value: http.DetectContentType(p)})

	for k, v := range w.header {
		enc.WriteField(hpack.HeaderField{Name: k, Value: v[0]})
	}

	h2framer := http2.NewFramer(w.headerStream, nil)
	h2framer.WriteHeaders(http2.HeadersFrameParam{
		StreamID:      uint32(w.dataStreamID),
		EndHeaders:    true,
		BlockFragment: headers.Bytes(),
	})

	if len(p) != 0 {
		dataStream, err := w.session.NewStream(w.dataStreamID)
		if err != nil {
			return 0, fmt.Errorf("error creating data stream: %s\n", err.Error())
		}
		defer dataStream.Close()
		return dataStream.Write(p)
	}

	return 0, nil
}

func handleStream(session *quic.Session, headerStream *quic.Stream) {
	hpackDecoder := hpack.NewDecoder(1024, nil)
	h2framer := http2.NewFramer(nil, headerStream)

	go func() {
		for {
			h2frame, err := h2framer.ReadFrame()
			if err != nil {
				fmt.Printf("invalid http2 frame: %s\n", err.Error())
				continue
			}
			h2headersFrame := h2frame.(*http2.HeadersFrame)
			if !h2headersFrame.HeadersEnded() {
				fmt.Printf("http2 header continuation not implemented")
				continue
			}
			headers, err := hpackDecoder.DecodeFull(h2headersFrame.HeaderBlockFragment())
			if err != nil {
				fmt.Printf("invalid http2 headers encoding: %s\n", err.Error())
				continue
			}

			headersMap := map[string]string{}
			for _, h := range headers {
				headersMap[h.Name] = h.Value
			}

			fmt.Printf("Request: %s %s://%s%s on stream %d\n", headersMap[":method"], headersMap[":scheme"], headersMap[":authority"], headersMap[":path"], h2headersFrame.StreamID)

			req, err := http.NewRequest(headersMap[":method"], headersMap[":path"], nil)
			if err != nil {
				fmt.Printf("invalid http2 frame: %s\n", err.Error())
				continue
			}

			responseWriter := &responseWriter{
				header:       http.Header{},
				headerStream: headerStream,
				dataStreamID: protocol.StreamID(h2headersFrame.StreamID),
				session:      session,
			}

			go http.DefaultServeMux.ServeHTTP(responseWriter, req)
		}
	}()
}
<|endoftext|>


<commit_before>package main

import (
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_chain "github.com/pierrre/imageserver/cache/chain"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_prefix "github.com/pierrre/imageserver/cache/prefix"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_merge "github.com/pierrre/imageserver/http/parser/merge"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

func main() {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	cache := imageserver_cache_chain.ChainCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		&imageserver_cache_redis.RedisCache{
			Pool: &redigo.Pool{
				Dial: func() (redigo.Conn, error) {
					return redigo.Dial("tcp", "localhost:6379")
				},
				MaxIdle: 50,
			},
			Expire: time.Duration(7 * 24 * time.Hour),
		},
	}

	imageServer := &imageserver.Server{
		Cache: &imageserver_cache_prefix.PrefixCache{
			Prefix: "processed:",
			Cache:  cache,
		},
		Provider: &imageserver_provider_cache.CacheProvider{
			Cache: &imageserver_cache_prefix.PrefixCache{
				Prefix: "source:",
				Cache:  cache,
			},
			Provider: &imageserver_provider_http.HttpProvider{},
		},
		Processor: imageserver_processor_limit.New(16, &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
			Executable: "gm",
			AllowedFormats: []string{
				"jpeg",
				"png",
				"bmp",
				"gif",
			},
			DefaultQualities: map[string]string{
				"jpeg": "85",
			},
		}),
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_merge.MergeParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			log.Println(err)
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			log.Println(request.Method, request.URL, statusCode, contentSize, err)
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}
<commit_msg>improve example logs<commit_after>package main

import (
	redigo "github.com/garyburd/redigo/redis"
	"github.com/pierrre/imageserver"
	imageserver_cache_chain "github.com/pierrre/imageserver/cache/chain"
	imageserver_cache_memory "github.com/pierrre/imageserver/cache/memory"
	imageserver_cache_prefix "github.com/pierrre/imageserver/cache/prefix"
	imageserver_cache_redis "github.com/pierrre/imageserver/cache/redis"
	imageserver_http "github.com/pierrre/imageserver/http"
	imageserver_http_parser_graphicsmagick "github.com/pierrre/imageserver/http/parser/graphicsmagick"
	imageserver_http_parser_merge "github.com/pierrre/imageserver/http/parser/merge"
	imageserver_http_parser_source "github.com/pierrre/imageserver/http/parser/source"
	imageserver_processor_graphicsmagick "github.com/pierrre/imageserver/processor/graphicsmagick"
	imageserver_processor_limit "github.com/pierrre/imageserver/processor/limit"
	imageserver_provider_cache "github.com/pierrre/imageserver/provider/cache"
	imageserver_provider_http "github.com/pierrre/imageserver/provider/http"
	"log"
	"net/http"
	"os"
	"strconv"
	"time"
)

func main() {
	hostname, err := os.Hostname()
	if err != nil {
		panic(err)
	}

	cache := imageserver_cache_chain.ChainCache{
		imageserver_cache_memory.New(10 * 1024 * 1024),
		&imageserver_cache_redis.RedisCache{
			Pool: &redigo.Pool{
				Dial: func() (redigo.Conn, error) {
					return redigo.Dial("tcp", "localhost:6379")
				},
				MaxIdle: 50,
			},
			Expire: time.Duration(7 * 24 * time.Hour),
		},
	}

	imageServer := &imageserver.Server{
		Cache: &imageserver_cache_prefix.PrefixCache{
			Prefix: "processed:",
			Cache:  cache,
		},
		Provider: &imageserver_provider_cache.CacheProvider{
			Cache: &imageserver_cache_prefix.PrefixCache{
				Prefix: "source:",
				Cache:  cache,
			},
			Provider: &imageserver_provider_http.HttpProvider{},
		},
		Processor: imageserver_processor_limit.New(16, &imageserver_processor_graphicsmagick.GraphicsMagickProcessor{
			Executable: "gm",
			AllowedFormats: []string{
				"jpeg",
				"png",
				"bmp",
				"gif",
			},
			DefaultQualities: map[string]string{
				"jpeg": "85",
			},
		}),
	}

	httpImageServer := &imageserver_http.Server{
		Parser: &imageserver_http_parser_merge.MergeParser{
			&imageserver_http_parser_source.SourceParser{},
			&imageserver_http_parser_graphicsmagick.GraphicsMagickParser{},
		},
		ImageServer: imageServer,
		Expire:      time.Duration(7 * 24 * time.Hour),
		RequestFunc: func(request *http.Request) error {
			url := request.URL
			query := url.Query()
			errorCodeString := query.Get("error")
			if len(errorCodeString) == 0 {
				return nil
			}
			errorCode, err := strconv.Atoi(errorCodeString)
			if err != nil {
				return imageserver.NewError(err.Error())
			}
			return imageserver_http.NewError(errorCode)
		},
		HeaderFunc: func(header http.Header, request *http.Request, err error) {
			header.Set("X-Hostname", hostname)
		},
		ErrorFunc: func(err error, request *http.Request) {
			log.Println(err)
		},
		ResponseFunc: func(request *http.Request, statusCode int, contentSize int64, err error) {
			var errString string
			if err != nil {
				errString = err.Error()
			}
			log.Println(request.Method, strconv.Quote(request.URL.String()), statusCode, contentSize, strconv.Quote(errString))
		},
	}

	http.Handle("/", httpImageServer)
	err = http.ListenAndServe(":8080", nil)
	if err != nil {
		panic(err)
	}
}
<|endoftext|>


<commit_before>//  Copyright (c) 2013 Couchbase, Inc.
//  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 (
	"fmt"

	"github.com/couchbaselabs/dparval"
)

func main() {

	// read some JSON
	bytes := []byte(`{"type":"test"}`)

	// create a Value object
	doc := dparval.NewValueFromBytes(bytes)

	// attempt to access a nested Value
	docType, err := doc.Path("type")
	if err != nil {
		panic("no property type exists")
	}

	// convert docType to a native go value
	docTypeValue := docType.Value()

	// display the value
	fmt.Printf("document type is %v\n", docTypeValue)
}
<commit_msg>Example program demonstrats accessing array value.<commit_after>//  Copyright (c) 2013 Couchbase, Inc.
//  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 (
	"fmt"

	"github.com/couchbaselabs/dparval"
)

func main() {

	// read some JSON
	bytes := []byte(`{"type":["test", "this"]}`)

	// create a Value object
	doc := dparval.NewValueFromBytes(bytes)

	// attempt to access a nested Value
	docType, err := doc.Path("type")
	if err != nil {
		panic("no property type exists")
	}

	// convert docType to a native go value
	docTypeValue := docType.Value()

	// display the value
	fmt.Printf("document type is %v\n", docTypeValue)

	docType, err = docType.Index(1)
	if err != nil {
		panic("no index exists")
	}
	fmt.Printf("index 1 of type is %v\n", docType.Value())
}
<|endoftext|>