<commit_before>package recipes

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"reflect"
	"time"

	"github.com/elvtechnology/gocqltable"

	r "github.com/elvtechnology/gocqltable/reflect"
)

type CRUD struct {
	gocqltable.TableInterface
}

func (t CRUD) Insert(row interface{}) error {
	return t.insert(row, nil)
}

func (t CRUD) InsertWithTTL(row interface{}, ttl *time.Time) error {
	return t.insert(row, ttl)
}

func (t CRUD) insert(row interface{}, ttl *time.Time) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	// TODO: Test and remove
	// where := []string{}
	// for _, key := range append(rowKeys, rangeKeys...) {
	// 	where = append(where, key+" = ?")
	// }

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	fields := []string{}
	placeholders := []string{}
	vals := []interface{}{}
	for key, value := range m {
		// Check for empty row- or range keys
		for _, rowKey := range append(rowKeys, rangeKeys...) {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				if value == nil {
					return errors.New(fmt.Sprintf("Inserting row failed due to missing key value (for key %q)", rowKey))
				}
				break
			}
		}
		// Append to insertion slices
		fields = append(fields, strings.ToLower(fmt.Sprintf("%q", key)))
		placeholders = append(placeholders, "?")
		vals = append(vals, value)
	}

	options := ""
	if ttl != nil {
		options = "USING TTL ?"
		vals = append(vals, int(ttl.Sub(time.Now().UTC()).Seconds()+.5))
	}

	err := t.Query(fmt.Sprintf(`INSERT INTO %q.%q (%s) VALUES (%s) %s`, t.Keyspace().Name(), t.Name(), strings.Join(fields, ", "), strings.Join(placeholders, ", "), options), vals...).Exec()
	if err != nil {
		for _, v := range vals {
			log.Printf("%T %v", v, v)
		}
		return err
	}

	return nil

}

func (t CRUD) Get(ids ...interface{}) (interface{}, error) {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	if len(ids) < len(rowKeys)+len(rangeKeys) {
		return nil, errors.New(fmt.Sprintf("To few key-values to query for row (%d of the required %d)", len(ids), len(rowKeys)+len(rangeKeys)))
	}

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	row, err := t.Query(fmt.Sprintf(`SELECT * FROM %q.%q WHERE %s LIMIT 1`, t.Keyspace().Name(), t.Name(), strings.Join(where, " AND ")), ids...).FetchRow()
	if err != nil {
		return nil, err
	}

	return row, nil

}

func (t CRUD) List(ids ...interface{}) (interface{}, error) {
	return t.Range(ids...).Fetch()
}

func (t CRUD) Update(row interface{}) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	ids := []interface{}{}
	set := []string{}
	vals := []interface{}{}

	for _, rowKey := range append(rowKeys, rangeKeys...) {
		for key, value := range m {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				ids = append(ids, value)
				break
			}
		}
	}

	for key, value := range m {
		isAKey := false
		for _, rowKey := range append(rowKeys, rangeKeys...) {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				isAKey = true
				break
			}
		}
		if !isAKey {
			set = append(set, strings.ToLower(key)+" = ?")
			vals = append(vals, value)
		}
	}

	if len(ids) < len(rowKeys) {
		return errors.New(fmt.Sprintf("To few key-values to query for row (%d of the required minimum of %d)", len(ids), len(rowKeys)))
	}

	err := t.Query(fmt.Sprintf(`UPDATE %q.%q SET %s WHERE %s`, t.Keyspace().Name(), t.Name(), strings.Join(set, ", "), strings.Join(where, " AND ")), append(vals, ids...)...).Exec()
	if err != nil {
		return err
	}
	return nil

}

func (t CRUD) Delete(row interface{}) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	ids := []interface{}{}
	for _, rowKey := range append(rowKeys, rangeKeys...) {
		for key, value := range m {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				ids = append(ids, value)
				break
			}
		}
	}

	if len(ids) < len(rowKeys)+len(rangeKeys) {
		return errors.New(fmt.Sprintf("To few key-values to delete row (%d of the required %d)", len(ids), len(rowKeys)+len(rangeKeys)))
	}

	err := t.Query(fmt.Sprintf(`DELETE FROM %q.%q WHERE %s`, t.Keyspace().Name(), t.Name(), strings.Join(where, " AND ")), ids...).Exec()
	if err != nil {
		return err
	}
	return nil

}

func (t CRUD) Range(ids ...interface{}) Range {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	rangeObj := Range{
		table: t,
	}

	numAppended := 0
	for idx, key := range append(rowKeys, rangeKeys...) {
		if len(ids) == numAppended {
			break
		}
		rangeObj = rangeObj.EqualTo(key, ids[idx])
		numAppended += 1
	}

	return rangeObj
}

type Range struct {
	table gocqltable.TableInterface

	where     []string
	whereVals []interface{}
	order     string
	limit     *int
	filtering bool
}

func (r Range) LessThan(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" < ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) LessThanOrEqual(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" <= ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) MoreThan(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" > ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) MoreThanOrEqual(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" >= ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) EqualTo(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" = ?")
	r.whereVals = append(r.whereVals, value)
	return r
}

func (r Range) OrderBy(fieldAndDirection string) Range {
	r.order = fieldAndDirection
	return r
}

func (r Range) Limit(l int) Range {
	r.limit = &l
	return r
}

func (r Range) Fetch() (interface{}, error) {

	where := r.where
	whereVals := r.whereVals
	order := r.order
	limit := r.limit
	filtering := r.filtering

	whereString := ""
	if len(where) > 0 {
		whereString = "WHERE " + strings.Join(where, " AND ")
	}

	orderString := ""
	if order != "" {
		orderString = fmt.Sprintf("ORDER BY %v", order)
	}

	limitString := ""
	if limit != nil {
		limitString = "LIMIT " + strconv.Itoa(*limit)
	}

	filteringString := ""
	if filtering {
		filteringString = "ALLOW FILTERING"
	}

	iter := r.table.Query(fmt.Sprintf(`SELECT * FROM %q.%q %s %s %s %s`, r.table.Keyspace().Name(), r.table.Name(), whereString, orderString, limitString, filteringString), whereVals...).Fetch()

	result := reflect.Zero(reflect.SliceOf(reflect.PtrTo(reflect.TypeOf(r.table.Row())))) // Create a zero-value slice of pointers to our model type
	for row := range iter.Range() {
		result = reflect.Append(result, reflect.ValueOf(row)) // Append the rows to our slice
	}

	if err := iter.Close(); err != nil {
		return nil, err
	}

	return result.Interface(), nil

}
<commit_msg>Fixed a number-of-ids passed mistake for CRUD updates<commit_after>package recipes

import (
	"errors"
	"fmt"
	"log"
	"strconv"
	"strings"
	"reflect"
	"time"

	"github.com/elvtechnology/gocqltable"

	r "github.com/elvtechnology/gocqltable/reflect"
)

type CRUD struct {
	gocqltable.TableInterface
}

func (t CRUD) Insert(row interface{}) error {
	return t.insert(row, nil)
}

func (t CRUD) InsertWithTTL(row interface{}, ttl *time.Time) error {
	return t.insert(row, ttl)
}

func (t CRUD) insert(row interface{}, ttl *time.Time) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	// TODO: Test and remove
	// where := []string{}
	// for _, key := range append(rowKeys, rangeKeys...) {
	// 	where = append(where, key+" = ?")
	// }

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	fields := []string{}
	placeholders := []string{}
	vals := []interface{}{}
	for key, value := range m {
		// Check for empty row- or range keys
		for _, rowKey := range append(rowKeys, rangeKeys...) {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				if value == nil {
					return errors.New(fmt.Sprintf("Inserting row failed due to missing key value (for key %q)", rowKey))
				}
				break
			}
		}
		// Append to insertion slices
		fields = append(fields, strings.ToLower(fmt.Sprintf("%q", key)))
		placeholders = append(placeholders, "?")
		vals = append(vals, value)
	}

	options := ""
	if ttl != nil {
		options = "USING TTL ?"
		vals = append(vals, int(ttl.Sub(time.Now().UTC()).Seconds()+.5))
	}

	err := t.Query(fmt.Sprintf(`INSERT INTO %q.%q (%s) VALUES (%s) %s`, t.Keyspace().Name(), t.Name(), strings.Join(fields, ", "), strings.Join(placeholders, ", "), options), vals...).Exec()
	if err != nil {
		for _, v := range vals {
			log.Printf("%T %v", v, v)
		}
		return err
	}

	return nil

}

func (t CRUD) Get(ids ...interface{}) (interface{}, error) {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	if len(ids) < len(rowKeys)+len(rangeKeys) {
		return nil, errors.New(fmt.Sprintf("To few key-values to query for row (%d of the required %d)", len(ids), len(rowKeys)+len(rangeKeys)))
	}

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	row, err := t.Query(fmt.Sprintf(`SELECT * FROM %q.%q WHERE %s LIMIT 1`, t.Keyspace().Name(), t.Name(), strings.Join(where, " AND ")), ids...).FetchRow()
	if err != nil {
		return nil, err
	}

	return row, nil

}

func (t CRUD) List(ids ...interface{}) (interface{}, error) {
	return t.Range(ids...).Fetch()
}

func (t CRUD) Update(row interface{}) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	ids := []interface{}{}
	set := []string{}
	vals := []interface{}{}

	for _, rowKey := range append(rowKeys, rangeKeys...) {
		for key, value := range m {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				ids = append(ids, value)
				break
			}
		}
	}

	for key, value := range m {
		isAKey := false
		for _, rowKey := range append(rowKeys, rangeKeys...) {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				isAKey = true
				break
			}
		}
		if !isAKey {
			set = append(set, strings.ToLower(key)+" = ?")
			vals = append(vals, value)
		}
	}

	if len(ids) < len(rowKeys)+len(rangeKeys) {
		return errors.New(fmt.Sprintf("To few key-values to update row (%d of the required minimum of %d)", len(ids), len(rowKeys)+len(rangeKeys)))
	}

	fmt.Println(fmt.Sprintf(`UPDATE %q.%q SET %s WHERE %s`, t.Keyspace().Name(), t.Name(), strings.Join(set, ", "), strings.Join(where, " AND ")))
	fmt.Println(vals)
	fmt.Println(ids)
	err := t.Query(fmt.Sprintf(`UPDATE %q.%q SET %s WHERE %s`, t.Keyspace().Name(), t.Name(), strings.Join(set, ", "), strings.Join(where, " AND ")), append(vals, ids...)...).Exec()
	if err != nil {
		return err
	}
	return nil

}

func (t CRUD) Delete(row interface{}) error {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	where := []string{}
	for _, key := range append(rowKeys, rangeKeys...) {
		where = append(where, key+" = ?")
	}

	m, ok := r.StructToMap(row)
	if !ok {
		panic("Unable to get map from struct during update")
	}

	ids := []interface{}{}
	for _, rowKey := range append(rowKeys, rangeKeys...) {
		for key, value := range m {
			if strings.ToLower(key) == strings.ToLower(rowKey) {
				ids = append(ids, value)
				break
			}
		}
	}

	if len(ids) < len(rowKeys)+len(rangeKeys) {
		return errors.New(fmt.Sprintf("To few key-values to delete row (%d of the required %d)", len(ids), len(rowKeys)+len(rangeKeys)))
	}

	err := t.Query(fmt.Sprintf(`DELETE FROM %q.%q WHERE %s`, t.Keyspace().Name(), t.Name(), strings.Join(where, " AND ")), ids...).Exec()
	if err != nil {
		return err
	}
	return nil

}

func (t CRUD) Range(ids ...interface{}) Range {

	rowKeys := t.RowKeys()
	rangeKeys := t.RangeKeys()

	rangeObj := Range{
		table: t,
	}

	numAppended := 0
	for idx, key := range append(rowKeys, rangeKeys...) {
		if len(ids) == numAppended {
			break
		}
		rangeObj = rangeObj.EqualTo(key, ids[idx])
		numAppended += 1
	}

	return rangeObj
}

type Range struct {
	table gocqltable.TableInterface

	where     []string
	whereVals []interface{}
	order     string
	limit     *int
	filtering bool
}

func (r Range) LessThan(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" < ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) LessThanOrEqual(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" <= ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) MoreThan(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" > ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) MoreThanOrEqual(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" >= ?")
	r.whereVals = append(r.whereVals, value)
	r.filtering = true
	return r
}

func (r Range) EqualTo(rangeKey string, value interface{}) Range {
	r.where = append(r.where, fmt.Sprintf("%q", strings.ToLower(rangeKey))+" = ?")
	r.whereVals = append(r.whereVals, value)
	return r
}

func (r Range) OrderBy(fieldAndDirection string) Range {
	r.order = fieldAndDirection
	return r
}

func (r Range) Limit(l int) Range {
	r.limit = &l
	return r
}

func (r Range) Fetch() (interface{}, error) {

	where := r.where
	whereVals := r.whereVals
	order := r.order
	limit := r.limit
	filtering := r.filtering

	whereString := ""
	if len(where) > 0 {
		whereString = "WHERE " + strings.Join(where, " AND ")
	}

	orderString := ""
	if order != "" {
		orderString = fmt.Sprintf("ORDER BY %v", order)
	}

	limitString := ""
	if limit != nil {
		limitString = "LIMIT " + strconv.Itoa(*limit)
	}

	filteringString := ""
	if filtering {
		filteringString = "ALLOW FILTERING"
	}

	iter := r.table.Query(fmt.Sprintf(`SELECT * FROM %q.%q %s %s %s %s`, r.table.Keyspace().Name(), r.table.Name(), whereString, orderString, limitString, filteringString), whereVals...).Fetch()

	result := reflect.Zero(reflect.SliceOf(reflect.PtrTo(reflect.TypeOf(r.table.Row())))) // Create a zero-value slice of pointers to our model type
	for row := range iter.Range() {
		result = reflect.Append(result, reflect.ValueOf(row)) // Append the rows to our slice
	}

	if err := iter.Close(); err != nil {
		return nil, err
	}

	return result.Interface(), nil

}
<|endoftext|>


<commit_before>package xormrediscache

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/go-xorm/core"
	"hash/crc32"
	"log"
	"reflect"
	// "strconv"
	"time"
	"unsafe"
)

const (
	DEFAULT_EXPIRATION = time.Duration(0)
	FOREVER_EXPIRATION = time.Duration(-1)
)

// Wraps the Redis client to meet the Cache interface.
type RedisCacher struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCacher(host string, password string, defaultExpiration time.Duration) *RedisCacher {
	var pool = &redis.Pool{
		MaxIdle:     5,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			// the redis protocol should probably be made sett-able
			c, err := redis.Dial("tcp", host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return &RedisCacher{pool, defaultExpiration}
}

func exists(conn redis.Conn, key string) bool {
	existed, _ := redis.Bool(conn.Do("EXISTS", key))
	return existed
}

func (c *RedisCacher) getBeanKey(tableName string, id string) string {

	beanKey := fmt.Sprintf("xorm:bean:%s:%s", tableName, id)
	log.Printf("[xorm/redis_cacher] getBeanKey: [%s]", beanKey)
	return beanKey
}

func (c *RedisCacher) getSqlKey(tableName string, sql string) string {
	// hash sql to minimize key length
	crc := crc32.ChecksumIEEE([]byte(sql))

	sqlKey := fmt.Sprintf("xorm:sql:%s:%d", tableName, crc)
	log.Printf("[xorm/redis_cacher] getSqlKey: [%s]", sqlKey)
	return sqlKey
}

func (c *RedisCacher) Flush() error {
	// conn := c.pool.Get()
	// defer conn.Close()
	// _, err := conn.Do("FLUSHALL")
	// return err
	return c.delObject("xorm:*")
}

func (c *RedisCacher) getObject(key string) interface{} {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return nil
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] redis.Bytes failed: %s", err)
		return nil
	}

	value, err := deserialize(item)

	return value
}

func (c *RedisCacher) getObject2(key string, ptr interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return err
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] redis.Bytes failed: %s", err)
		return err
	}
	err = deserialize2(item, ptr)
	return err
}

func (c *RedisCacher) GetIds(tableName, sql string) interface{} {
	log.Printf("[xorm/redis_cacher] GetIds|tableName:%s|sql:%s", tableName, sql)

	return c.getObject(c.getSqlKey(tableName, sql))
}

func (c *RedisCacher) GetBean(tableName string, id string) interface{} {
	log.Printf("[xorm/redis_cacher] GetBean|tableName:%s|id:%s", tableName, id)
	return c.getObject(c.getBeanKey(tableName, id))
}

func (c *RedisCacher) GetBean2(tableName string, id string, ptr interface{}) error {
	log.Printf("[xorm/redis_cacher] GetBean|tableName:%s|id:%s", tableName, id)
	return c.getObject2(c.getBeanKey(tableName, id), ptr)
}

func (c *RedisCacher) putObject(key string, value interface{}) {
	c.invoke(c.pool.Get().Do, key, value, c.defaultExpiration)
}

func (c *RedisCacher) PutIds(tableName, sql string, ids interface{}) {
	log.Printf("[xorm/redis_cacher] PutIds|tableName:%s|sql:%s|type:%v", tableName, sql, reflect.TypeOf(ids))

	c.putObject(c.getSqlKey(tableName, sql), ids)
}

func (c *RedisCacher) PutBean(tableName string, id string, obj interface{}) {
	log.Printf("[xorm/redis_cacher] PutBean|tableName:%s|id:%s|type:%v", tableName, id, reflect.TypeOf(obj))
	c.putObject(c.getBeanKey(tableName, id), obj)
}

func (c *RedisCacher) delObject(key string) error {
	log.Printf("[xorm/redis_cacher] delObject key:[%s]", key)

	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		log.Printf("[xorm/redis_cacher] delObject: %v", core.ErrCacheMiss)
		return core.ErrCacheMiss
	}
	_, err := conn.Do("DEL", key)
	return err
}

func (c *RedisCacher) delObjects(key string) error {

	log.Printf("[xorm/redis_cacher] delObjects key:[%s]", key)

	conn := c.pool.Get()
	defer conn.Close()

	keys, err := conn.Do("KEYS", key)
	log.Printf("[xorm/redis_cacher] delObjects keys: %v", keys)

	if err == nil {
		for _, key := range keys.([]interface{}) {
			conn.Do("DEL", key)
		}
	}
	return err
}

func (c *RedisCacher) DelIds(tableName, sql string) {
	c.delObject(c.getSqlKey(tableName, sql))
}

func (c *RedisCacher) DelBean(tableName string, id string) {
	c.delObject(c.getBeanKey(tableName, id))
}

func (c *RedisCacher) ClearIds(tableName string) {
	c.delObjects(c.getSqlKey(tableName, "*"))
}

func (c *RedisCacher) ClearBeans(tableName string) {
	c.delObjects(c.getBeanKey(tableName, "*"))
}

func (c *RedisCacher) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT_EXPIRATION:
		expires = c.defaultExpiration
	case FOREVER_EXPIRATION:
		expires = time.Duration(0)
	}

	b, err := serialize(value)
	if err != nil {
		return err
	}
	conn := c.pool.Get()
	defer conn.Close()
	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	} else {
		_, err := f("SET", key, b)
		return err
	}
}

func serialize(value interface{}) ([]byte, error) {

	err := RegisterGobConcreteType(value)
	if err != nil {
		return nil, err
	}

	if reflect.TypeOf(value).Kind() == reflect.Struct {
		return nil, fmt.Errorf("serialize func only take pointer of a struct")
	}

	var b bytes.Buffer
	encoder := gob.NewEncoder(&b)

	log.Printf("[xorm/redis_cacher] serialize type:%v", reflect.TypeOf(value))
	err = encoder.Encode(&value)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] gob encoding '%s' failed: %s", value, err)
		return nil, err
	}
	return b.Bytes(), nil
}

func deserialize(byt []byte) (ptr interface{}, err error) {
	b := bytes.NewBuffer(byt)
	decoder := gob.NewDecoder(b)

	var p interface{}
	err = decoder.Decode(&p)
	if err != nil {
		log.Fatal("[xorm/redis_cacher] decode:", err)
		return
	}

	v := reflect.ValueOf(p)
	log.Printf("[xorm/redis_cacher] deserialize type:%v", v.Type())
	if v.Kind() == reflect.Struct {

		// !nashtsai! TODO following implementation will new an instance and make a copy,
		// hence performance degration
		var pp interface{} = &p
		datas := reflect.ValueOf(pp).Elem().InterfaceData()

		sp := reflect.NewAt(v.Type(),
			unsafe.Pointer(datas[1])).Interface()
		ptr = sp
		vv := reflect.ValueOf(ptr)
		log.Printf("[xorm/redis_cacher] deserialize convert ptr type:%v | CanAddr:%t", vv.Type(), vv.CanAddr())
		// --
	} else {
		ptr = p
	}
	return
}

func deserialize2(byt []byte, ptr interface{}) (err error) {
	b := bytes.NewBuffer(byt)
	decoder := gob.NewDecoder(b)

	log.Printf("[xorm/redis_cacher] deserialize2 type b4 decode:%v", reflect.TypeOf(ptr))

	err = decoder.Decode(ptr)
	if err != nil {
		return
	}
	log.Printf("[xorm/redis_cacher] deserialize2 type:%v", reflect.TypeOf(ptr))

	return
}

func RegisterGobConcreteType(value interface{}) error {

	t := reflect.TypeOf(value)

	log.Printf("[xorm/redis_cacher] RegisterGobConcreteType:%v", t)

	switch t.Kind() {
	case reflect.Ptr:
		v := reflect.ValueOf(value)
		i := v.Elem().Interface()
		gob.Register(i)
	case reflect.Struct, reflect.Map, reflect.Slice:
		gob.Register(value)
	case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		// do nothing since already registered known type
	default:
		return fmt.Errorf("unhandled type: %v", t)
	}
	return nil
}
<commit_msg>tidy up logging<commit_after>package xormrediscache

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"github.com/garyburd/redigo/redis"
	"github.com/go-xorm/core"
	"hash/crc32"
	"log"
	"reflect"
	// "strconv"
	"time"
	"unsafe"
)

const (
	DEFAULT_EXPIRATION = time.Duration(0)
	FOREVER_EXPIRATION = time.Duration(-1)
)

// Wraps the Redis client to meet the Cache interface.
type RedisCacher struct {
	pool              *redis.Pool
	defaultExpiration time.Duration
}

// until redigo supports sharding/clustering, only one host will be in hostList
func NewRedisCacher(host string, password string, defaultExpiration time.Duration) *RedisCacher {
	var pool = &redis.Pool{
		MaxIdle:     5,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			// the redis protocol should probably be made sett-able
			c, err := redis.Dial("tcp", host)
			if err != nil {
				return nil, err
			}
			if len(password) > 0 {
				if _, err := c.Do("AUTH", password); err != nil {
					c.Close()
					return nil, err
				}
			} else {
				// check with PING
				if _, err := c.Do("PING"); err != nil {
					c.Close()
					return nil, err
				}
			}
			return c, err
		},
		// custom connection test method
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			if _, err := c.Do("PING"); err != nil {
				return err
			}
			return nil
		},
	}
	return &RedisCacher{pool, defaultExpiration}
}

func exists(conn redis.Conn, key string) bool {
	existed, _ := redis.Bool(conn.Do("EXISTS", key))
	return existed
}

func (c *RedisCacher) getBeanKey(tableName string, id string) string {
	return fmt.Sprintf("xorm:bean:%s:%s", tableName, id)
}

func (c *RedisCacher) getSqlKey(tableName string, sql string) string {
	// hash sql to minimize key length
	crc := crc32.ChecksumIEEE([]byte(sql))
	return fmt.Sprintf("xorm:sql:%s:%d", tableName, crc)
}

func (c *RedisCacher) Flush() error {
	// conn := c.pool.Get()
	// defer conn.Close()
	// _, err := conn.Do("FLUSHALL")
	// return err
	return c.delObject("xorm:*")
}

func (c *RedisCacher) getObject(key string) interface{} {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return nil
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] redis.Bytes failed: %s", err)
		return nil
	}

	value, err := deserialize(item)

	return value
}

func (c *RedisCacher) getObject2(key string, ptr interface{}) error {
	conn := c.pool.Get()
	defer conn.Close()
	raw, err := conn.Do("GET", key)
	if raw == nil {
		return err
	}
	item, err := redis.Bytes(raw, err)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] redis.Bytes failed: %s", err)
		return err
	}
	err = deserialize2(item, ptr)
	return err
}

func (c *RedisCacher) GetIds(tableName, sql string) interface{} {
	sqlKey := c.getSqlKey(tableName, sql)
	log.Printf("[xorm/redis_cacher] GetIds|tableName:%s|sql:%s|key:%s", tableName, sql, sqlKey)
	return c.getObject(sqlKey)
}

func (c *RedisCacher) GetBean(tableName string, id string) interface{} {
	beanKey := c.getBeanKey(tableName, id)
	log.Printf("[xorm/redis_cacher] GetBean|tableName:%s|id:%s|key:%s", tableName, id, beanKey)
	return c.getObject(beanKey)
}

func (c *RedisCacher) GetBean2(tableName string, id string, ptr interface{}) error {
	beanKey := c.getBeanKey(tableName, id)
	log.Printf("[xorm/redis_cacher] GetBean|tableName:%s|id:%s|key:%s", tableName, id, beanKey)
	return c.getObject2(beanKey, ptr)
}

func (c *RedisCacher) putObject(key string, value interface{}) {
	c.invoke(c.pool.Get().Do, key, value, c.defaultExpiration)
}

func (c *RedisCacher) PutIds(tableName, sql string, ids interface{}) {
	sqlKey := c.getSqlKey(tableName, sql)
	log.Printf("[xorm/redis_cacher] PutIds|tableName:%s|sql:%s|key:%s|obj:%s|type:%v", tableName, sql, sqlKey, ids, reflect.TypeOf(ids))
	c.putObject(sqlKey, ids)
}

func (c *RedisCacher) PutBean(tableName string, id string, obj interface{}) {
	beanKey := c.getBeanKey(tableName, id)
	log.Printf("[xorm/redis_cacher] PutBean|tableName:%s|id:%s|key:%s|type:%v", tableName, id, beanKey, reflect.TypeOf(obj))
	c.putObject(beanKey, obj)
}

func (c *RedisCacher) delObject(key string) error {
	log.Printf("[xorm/redis_cacher] delObject key:[%s]", key)

	conn := c.pool.Get()
	defer conn.Close()
	if !exists(conn, key) {
		log.Printf("[xorm/redis_cacher] delObject: %v", core.ErrCacheMiss)
		return core.ErrCacheMiss
	}
	_, err := conn.Do("DEL", key)
	return err
}

func (c *RedisCacher) delObjects(key string) error {

	log.Printf("[xorm/redis_cacher] delObjects key:[%s]", key)

	conn := c.pool.Get()
	defer conn.Close()

	keys, err := conn.Do("KEYS", key)
	log.Printf("[xorm/redis_cacher] delObjects keys: %v", keys)

	if err == nil {
		for _, key := range keys.([]interface{}) {
			conn.Do("DEL", key)
		}
	}
	return err
}

func (c *RedisCacher) DelIds(tableName, sql string) {
	c.delObject(c.getSqlKey(tableName, sql))
}

func (c *RedisCacher) DelBean(tableName string, id string) {
	c.delObject(c.getBeanKey(tableName, id))
}

func (c *RedisCacher) ClearIds(tableName string) {
	c.delObjects(c.getSqlKey(tableName, "*"))
}

func (c *RedisCacher) ClearBeans(tableName string) {
	c.delObjects(c.getBeanKey(tableName, "*"))
}

func (c *RedisCacher) invoke(f func(string, ...interface{}) (interface{}, error),
	key string, value interface{}, expires time.Duration) error {

	switch expires {
	case DEFAULT_EXPIRATION:
		expires = c.defaultExpiration
	case FOREVER_EXPIRATION:
		expires = time.Duration(0)
	}

	b, err := serialize(value)
	if err != nil {
		return err
	}
	conn := c.pool.Get()
	defer conn.Close()
	if expires > 0 {
		_, err := f("SETEX", key, int32(expires/time.Second), b)
		return err
	} else {
		_, err := f("SET", key, b)
		return err
	}
}

func serialize(value interface{}) ([]byte, error) {

	err := RegisterGobConcreteType(value)
	if err != nil {
		return nil, err
	}

	if reflect.TypeOf(value).Kind() == reflect.Struct {
		return nil, fmt.Errorf("serialize func only take pointer of a struct")
	}

	var b bytes.Buffer
	encoder := gob.NewEncoder(&b)

	log.Printf("[xorm/redis_cacher] serialize type:%v", reflect.TypeOf(value))
	err = encoder.Encode(&value)
	if err != nil {
		log.Fatalf("[xorm/redis_cacher] gob encoding '%s' failed: %s", value, err)
		return nil, err
	}
	return b.Bytes(), nil
}

func deserialize(byt []byte) (ptr interface{}, err error) {
	b := bytes.NewBuffer(byt)
	decoder := gob.NewDecoder(b)

	var p interface{}
	err = decoder.Decode(&p)
	if err != nil {
		log.Fatal("[xorm/redis_cacher] decode:", err)
		return
	}

	v := reflect.ValueOf(p)
	log.Printf("[xorm/redis_cacher] deserialize type:%v", v.Type())
	if v.Kind() == reflect.Struct {

		// !nashtsai! TODO following implementation will new an instance and make a copy,
		// hence performance degration
		var pp interface{} = &p
		datas := reflect.ValueOf(pp).Elem().InterfaceData()

		sp := reflect.NewAt(v.Type(),
			unsafe.Pointer(datas[1])).Interface()
		ptr = sp
		vv := reflect.ValueOf(ptr)
		log.Printf("[xorm/redis_cacher] deserialize convert ptr type:%v | CanAddr:%t", vv.Type(), vv.CanAddr())
		// --
	} else {
		ptr = p
	}
	return
}

func deserialize2(byt []byte, ptr interface{}) (err error) {
	b := bytes.NewBuffer(byt)
	decoder := gob.NewDecoder(b)

	log.Printf("[xorm/redis_cacher] deserialize2 type b4 decode:%v", reflect.TypeOf(ptr))

	err = decoder.Decode(ptr)
	if err != nil {
		return
	}
	log.Printf("[xorm/redis_cacher] deserialize2 type:%v", reflect.TypeOf(ptr))

	return
}

func RegisterGobConcreteType(value interface{}) error {

	t := reflect.TypeOf(value)

	log.Printf("[xorm/redis_cacher] RegisterGobConcreteType:%v", t)

	switch t.Kind() {
	case reflect.Ptr:
		v := reflect.ValueOf(value)
		i := v.Elem().Interface()
		gob.Register(i)
	case reflect.Struct, reflect.Map, reflect.Slice:
		gob.Register(value)
	case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Bool, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
		// do nothing since already registered known type
	default:
		return fmt.Errorf("unhandled type: %v", t)
	}
	return nil
}
<|endoftext|>


<commit_before>package oauth2

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseAccessTokenRequestMinimal(t *testing.T) {
	r := newRequestWithAuth("foo", "", map[string]string{
		"grant_type": "password",
		"scope":      "foo",
	})

	req, err := ParseAccessTokenRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "password", req.GrantType.String())
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "", req.ClientSecret)
	assert.Equal(t, Scope{"foo"}, req.Scope)
	assert.Equal(t, "", req.Username)
	assert.Equal(t, "", req.Password)
	assert.Equal(t, "", req.RefreshToken)
	assert.Equal(t, "", req.RedirectURI)
	assert.Equal(t, "", req.Code)
	assert.False(t, req.Confidential())
}

func TestParseAccessTokenRequestFull(t *testing.T) {
	r := newRequestWithAuth("foo", "bar", map[string]string{
		"grant_type":    "password",
		"scope":         "foo bar",
		"username":      "baz",
		"password":      "qux",
		"refresh_token": "bla",
		"redirect_uri":  "http://example.com",
		"code":          "blaa",
	})

	req, err := ParseAccessTokenRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "password", req.GrantType.String())
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "bar", req.ClientSecret)
	assert.Equal(t, Scope([]string{"foo", "bar"}), req.Scope)
	assert.Equal(t, "baz", req.Username)
	assert.Equal(t, "qux", req.Password)
	assert.Equal(t, "bla", req.RefreshToken)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "blaa", req.Code)
	assert.True(t, req.Confidential())
}

func TestParseAccessTokenRequestErrors(t *testing.T) {
	r1, _ := http.NewRequest("GET", "", nil)
	r2, _ := http.NewRequest("POST", "", nil)

	matrix := []*http.Request{
		r1,
		r2,
		newRequest(nil),
		newRequest(map[string]string{
			"grant_type": "password",
		}),
		newRequest(map[string]string{
			"grant_type": "password",
			"scope":      "foo",
		}),
		newRequestWithAuth("foo", "bar", map[string]string{
			"grant_type":   "password",
			"scope":        "foo",
			"redirect_uri": "blaa%blupp",
		}),
		newRequestWithAuth("foo", "bar", map[string]string{
			"grant_type":   "password",
			"scope":        "foo",
			"redirect_uri": "foo",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAccessTokenRequest(i)
		assert.Nil(t, req)
		assert.Error(t, err)
	}
}

func TestParseAuthorizationRequestMinimal(t *testing.T) {
	r := newRequest(map[string]string{
		"client_id":     "foo",
		"scope":         "foo",
		"response_type": "token",
		"redirect_uri":  "http://example.com",
	})

	req, err := ParseAuthorizationRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "token", req.ResponseType.String())
	assert.Equal(t, Scope{"foo"}, req.Scope)
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "", req.State)
}

func TestParseAuthorizationRequestFull(t *testing.T) {
	r := newRequest(map[string]string{
		"client_id":     "foo",
		"scope":         "foo bar",
		"response_type": "token",
		"redirect_uri":  "http://example.com",
		"state":         "baz",
	})

	req, err := ParseAuthorizationRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "token", req.ResponseType.String())
	assert.Equal(t, Scope([]string{"foo", "bar"}), req.Scope)
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "baz", req.State)
}

func TestParseAuthorizationRequestErrors(t *testing.T) {
	r1, _ := http.NewRequest("PUT", "", nil)
	r2, _ := http.NewRequest("POST", "", nil)

	matrix := []*http.Request{
		r1,
		r2,
		newRequest(nil),
		newRequest(map[string]string{
			"response_type": "token",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
			"client_id":     "foo",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
			"client_id":     "foo",
			"redirect_uri":  "foo",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAuthorizationRequest(i)
		assert.Nil(t, req)
		assert.Error(t, err)
	}
}

func TestAuthorizationRequestValidate(t *testing.T) {
	matrix := []*http.Request{
		newRequest(map[string]string{
			"response_type": "foo", // <- invalid
			"scope":         "foo",
			"client_id":     "foo",
			"redirect_uri":  "http://example.com",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAuthorizationRequest(i)
		assert.NotNil(t, req)
		assert.NoError(t, err)

		err = req.Validate()
		assert.Error(t, err)
	}
}
<commit_msg>validate validate method<commit_after>package oauth2

import (
	"net/http"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestParseAccessTokenRequestMinimal(t *testing.T) {
	r := newRequestWithAuth("foo", "", map[string]string{
		"grant_type": "password",
		"scope":      "foo",
	})

	req, err := ParseAccessTokenRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "password", req.GrantType.String())
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "", req.ClientSecret)
	assert.Equal(t, Scope{"foo"}, req.Scope)
	assert.Equal(t, "", req.Username)
	assert.Equal(t, "", req.Password)
	assert.Equal(t, "", req.RefreshToken)
	assert.Equal(t, "", req.RedirectURI)
	assert.Equal(t, "", req.Code)
	assert.False(t, req.Confidential())
}

func TestParseAccessTokenRequestFull(t *testing.T) {
	r := newRequestWithAuth("foo", "bar", map[string]string{
		"grant_type":    "password",
		"scope":         "foo bar",
		"username":      "baz",
		"password":      "qux",
		"refresh_token": "bla",
		"redirect_uri":  "http://example.com",
		"code":          "blaa",
	})

	req, err := ParseAccessTokenRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "password", req.GrantType.String())
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "bar", req.ClientSecret)
	assert.Equal(t, Scope([]string{"foo", "bar"}), req.Scope)
	assert.Equal(t, "baz", req.Username)
	assert.Equal(t, "qux", req.Password)
	assert.Equal(t, "bla", req.RefreshToken)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "blaa", req.Code)
	assert.True(t, req.Confidential())
}

func TestParseAccessTokenRequestErrors(t *testing.T) {
	r1, _ := http.NewRequest("GET", "", nil)
	r2, _ := http.NewRequest("POST", "", nil)

	matrix := []*http.Request{
		r1,
		r2,
		newRequest(nil),
		newRequest(map[string]string{
			"grant_type": "password",
		}),
		newRequest(map[string]string{
			"grant_type": "password",
			"scope":      "foo",
		}),
		newRequestWithAuth("foo", "bar", map[string]string{
			"grant_type":   "password",
			"scope":        "foo",
			"redirect_uri": "blaa%blupp",
		}),
		newRequestWithAuth("foo", "bar", map[string]string{
			"grant_type":   "password",
			"scope":        "foo",
			"redirect_uri": "foo",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAccessTokenRequest(i)
		assert.Nil(t, req)
		assert.Error(t, err)
	}
}

func TestParseAuthorizationRequestMinimal(t *testing.T) {
	r := newRequest(map[string]string{
		"client_id":     "foo",
		"scope":         "foo",
		"response_type": "token",
		"redirect_uri":  "http://example.com",
	})

	req, err := ParseAuthorizationRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "token", req.ResponseType.String())
	assert.Equal(t, Scope{"foo"}, req.Scope)
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "", req.State)
	assert.NoError(t, req.Validate())
}

func TestParseAuthorizationRequestFull(t *testing.T) {
	r := newRequest(map[string]string{
		"client_id":     "foo",
		"scope":         "foo bar",
		"response_type": "token",
		"redirect_uri":  "http://example.com",
		"state":         "baz",
	})

	req, err := ParseAuthorizationRequest(r)
	assert.NoError(t, err)
	assert.Equal(t, "token", req.ResponseType.String())
	assert.Equal(t, Scope([]string{"foo", "bar"}), req.Scope)
	assert.Equal(t, "foo", req.ClientID)
	assert.Equal(t, "http://example.com", req.RedirectURI)
	assert.Equal(t, "baz", req.State)
	assert.NoError(t, req.Validate())
}

func TestParseAuthorizationRequestErrors(t *testing.T) {
	r1, _ := http.NewRequest("PUT", "", nil)
	r2, _ := http.NewRequest("POST", "", nil)

	matrix := []*http.Request{
		r1,
		r2,
		newRequest(nil),
		newRequest(map[string]string{
			"response_type": "token",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
			"client_id":     "foo",
		}),
		newRequest(map[string]string{
			"response_type": "token",
			"scope":         "foo",
			"client_id":     "foo",
			"redirect_uri":  "foo",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAuthorizationRequest(i)
		assert.Nil(t, req)
		assert.Error(t, err)
	}
}

func TestAuthorizationRequestValidate(t *testing.T) {
	matrix := []*http.Request{
		newRequest(map[string]string{
			"response_type": "foo", // <- invalid
			"scope":         "foo",
			"client_id":     "foo",
			"redirect_uri":  "http://example.com",
		}),
	}

	for _, i := range matrix {
		req, err := ParseAuthorizationRequest(i)
		assert.NotNil(t, req)
		assert.NoError(t, err)

		err = req.Validate()
		assert.Error(t, err)
	}
}
<|endoftext|>


<commit_before>package sdk

/*
   Copyright 2016 Alexander I.Grafov <grafov@gmail.com>
   Copyright 2016-2019 The Grafana SDK 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.

   ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"
)

// DefaultHTTPClient initialized Grafana with appropriate conditions.
// It allows you globally redefine HTTP client.
var DefaultHTTPClient = http.DefaultClient

// Client uses Grafana REST API for interacting with Grafana server.
type Client struct {
	baseURL   string
	key       string
	basicAuth bool
	client    *http.Client
}

// StatusMessage reflects status message as it returned by Grafana REST API.
type StatusMessage struct {
	ID      *uint   `json:"id"`
	OrgID   *uint   `json:"orgId"`
	Message *string `json:"message"`
	Slug    *string `json:"slug"`
	Version *int    `json:"version"`
	Status  *string `json:"status"`
	UID     *string `json:"uid"`
	URL     *string `json:"url"`
}

// NewClient initializes client for interacting with an instance of Grafana server;
// apiKeyOrBasicAuth accepts either 'username:password' basic authentication credentials,
// or a Grafana API key
func NewClient(apiURL, apiKeyOrBasicAuth string, client *http.Client) *Client {
	key := ""
	basicAuth := strings.Contains(apiKeyOrBasicAuth, ":")
	baseURL, _ := url.Parse(apiURL)
	if !basicAuth {
		key = fmt.Sprintf("Bearer %s", apiKeyOrBasicAuth)
	} else {
		parts := strings.Split(apiKeyOrBasicAuth, ":")
		baseURL.User = url.UserPassword(parts[0], parts[1])
	}
	return &Client{baseURL: baseURL.String(), basicAuth: basicAuth, key: key, client: client}
}

func (r *Client) get(ctx context.Context, query string, params url.Values) ([]byte, int, error) {
	return r.doRequest(ctx, "GET", query, params, nil)
}

func (r *Client) patch(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "PATCH", query, params, bytes.NewBuffer(body))
}

func (r *Client) put(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "PUT", query, params, bytes.NewBuffer(body))
}

func (r *Client) post(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "POST", query, params, bytes.NewBuffer(body))
}

func (r *Client) delete(ctx context.Context, query string) ([]byte, int, error) {
	return r.doRequest(ctx, "DELETE", query, nil, nil)
}

func (r *Client) doRequest(ctx context.Context, method, query string, params url.Values, buf io.Reader) ([]byte, int, error) {
	u, _ := url.Parse(r.baseURL)
	u.Path = path.Join(u.Path, query)
	if params != nil {
		u.RawQuery = params.Encode()
	}
	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, 0, err
	}
	req = req.WithContext(ctx)
	if !r.basicAuth {
		req.Header.Set("Authorization", r.key)
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "autograf")
	resp, err := r.client.Do(req)
	if err != nil {
		return nil, 0, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	return data, resp.StatusCode, err
}
<commit_msg>Handle URL parse error (#155)<commit_after>package sdk

/*
   Copyright 2016 Alexander I.Grafov <grafov@gmail.com>
   Copyright 2016-2019 The Grafana SDK 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.

   ॐ तारे तुत्तारे तुरे स्व
*/

import (
	"bytes"
	"context"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"path"
	"strings"
)

// DefaultHTTPClient initialized Grafana with appropriate conditions.
// It allows you globally redefine HTTP client.
var DefaultHTTPClient = http.DefaultClient

// Client uses Grafana REST API for interacting with Grafana server.
type Client struct {
	baseURL   string
	key       string
	basicAuth bool
	client    *http.Client
}

// StatusMessage reflects status message as it returned by Grafana REST API.
type StatusMessage struct {
	ID      *uint   `json:"id"`
	OrgID   *uint   `json:"orgId"`
	Message *string `json:"message"`
	Slug    *string `json:"slug"`
	Version *int    `json:"version"`
	Status  *string `json:"status"`
	UID     *string `json:"uid"`
	URL     *string `json:"url"`
}

// NewClient initializes client for interacting with an instance of Grafana server;
// apiKeyOrBasicAuth accepts either 'username:password' basic authentication credentials,
// or a Grafana API key
func NewClient(apiURL, apiKeyOrBasicAuth string, client *http.Client) (*Client, error) {
	key := ""
	basicAuth := strings.Contains(apiKeyOrBasicAuth, ":")
	baseURL, err := url.Parse(apiURL)
	if err != nil {
		return nil, err
	}
	if !basicAuth {
		key = fmt.Sprintf("Bearer %s", apiKeyOrBasicAuth)
	} else {
		parts := strings.Split(apiKeyOrBasicAuth, ":")
		baseURL.User = url.UserPassword(parts[0], parts[1])
	}
	return &Client{baseURL: baseURL.String(), basicAuth: basicAuth, key: key, client: client}, nil
}

func (r *Client) get(ctx context.Context, query string, params url.Values) ([]byte, int, error) {
	return r.doRequest(ctx, "GET", query, params, nil)
}

func (r *Client) patch(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "PATCH", query, params, bytes.NewBuffer(body))
}

func (r *Client) put(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "PUT", query, params, bytes.NewBuffer(body))
}

func (r *Client) post(ctx context.Context, query string, params url.Values, body []byte) ([]byte, int, error) {
	return r.doRequest(ctx, "POST", query, params, bytes.NewBuffer(body))
}

func (r *Client) delete(ctx context.Context, query string) ([]byte, int, error) {
	return r.doRequest(ctx, "DELETE", query, nil, nil)
}

func (r *Client) doRequest(ctx context.Context, method, query string, params url.Values, buf io.Reader) ([]byte, int, error) {
	u, _ := url.Parse(r.baseURL)
	u.Path = path.Join(u.Path, query)
	if params != nil {
		u.RawQuery = params.Encode()
	}
	req, err := http.NewRequest(method, u.String(), buf)
	if err != nil {
		return nil, 0, err
	}
	req = req.WithContext(ctx)
	if !r.basicAuth {
		req.Header.Set("Authorization", r.key)
	}
	req.Header.Set("Accept", "application/json")
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("User-Agent", "autograf")
	resp, err := r.client.Do(req)
	if err != nil {
		return nil, 0, err
	}
	data, err := ioutil.ReadAll(resp.Body)
	resp.Body.Close()
	return data, resp.StatusCode, err
}
<|endoftext|>


<commit_before>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"testing"
	"time"

	pb "github.com/golang/protobuf/proto"

	"upspin.io/cache"
	"upspin.io/cloud/https"
	"upspin.io/config"
	"upspin.io/errors"
	"upspin.io/factotum"
	"upspin.io/log"
	prototest "upspin.io/rpc/testdata"
	"upspin.io/test/testutil"
	"upspin.io/upspin"
)

var (
	joePublic = upspin.PublicKey("p256\n104278369061367353805983276707664349405797936579880352274235000127123465616334\n26941412685198548642075210264642864401950753555952207894712845271039438170192\n")
	joeUser   = upspin.UserName("joe@blow.com")
	srv       *server
	cli       *client
)

var payloads = []string{
	"The wren",
	"Earns his living",
	"Noiselessly.",
	// - Kobayahsi Issa
}

func lookup(user upspin.UserName) (upspin.PublicKey, error) {
	if user == joeUser {
		return upspin.PublicKey(joePublic), nil
	}
	return "", errors.E(errors.NotExist, errors.Str("No user here"))
}

func pickPort() (port string) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	_, port, err = net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Fatalf("Failed to parse listener address: %v", err)
	}
	listener.Close()
	return port
}

type server struct {
	t         *testing.T
	iteration int
}

func startServer(t *testing.T) (port string) {
	srv = &server{t: t}
	port = pickPort()

	cfg := config.SetUserName(config.New(), "server@upspin.io")
	cfg = config.SetKeyEndpoint(cfg, upspin.Endpoint{Transport: upspin.InProcess})
	http.Handle("/api/Server/", NewServer(cfg, Service{
		Name: "Server",
		Methods: map[string]Method{
			"Echo": srv.Echo,
		},
		UnauthenticatedMethods: map[string]UnauthenticatedMethod{
			"UnauthenticatedEcho": srv.UnauthenticatedEcho,
		},
		Streams: map[string]Stream{
			"Count": srv.Count,
		},
		Lookup: lookup,
	}))

	ready := make(chan struct{})
	go https.ListenAndServe(ready, "test", fmt.Sprintf("localhost:%s", port), nil)
	<-ready
	return port
}

func (s *server) UnauthenticatedEcho(reqBytes []byte) (pb.Message, error) {
	var req prototest.EchoRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: UnauthenticatedEcho response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

func (s *server) Echo(session Session, reqBytes []byte) (pb.Message, error) {
	var req prototest.EchoRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	if session.User() != joeUser {
		s.t.Fatalf("Expected user %q, got %q", joeUser, session.User())
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: Echo response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

func (s *server) Count(session Session, reqBytes []byte, done <-chan struct{}) (<-chan pb.Message, error) {
	var req prototest.CountRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	log.Printf("Server: Count request: %d", req.Start)

	out := make(chan pb.Message)
	go func() {
		defer close(out)
		for i := req.Start; i < req.Start+req.Count; i++ {
			resp := &prototest.CountResponse{
				Number: i,
			}
			select {
			case out <- resp:
			case <-done:
				return
			}
		}
	}()
	return out, nil
}

type client struct {
	Client   // For sessions, Ping, and Close.
	reqCount int
}

func (c *client) UnauthenticatedEcho(t *testing.T, payload string) (response string) {
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	resp := new(prototest.EchoResponse)
	log.Printf("Client: UnauthenticatedEcho request: %q", req.Payload)
	if err := c.Invoke("Server/UnauthenticatedEcho", req, resp, nil, nil); err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func (c *client) Echo(t *testing.T, payload string) (response string) {
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	resp := new(prototest.EchoResponse)
	log.Printf("Client: Echo request: %q", req.Payload)
	if err := c.Invoke("Server/Echo", req, resp, nil, nil); err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func (c *client) Count(t *testing.T, start, count int32) {
	req := &prototest.CountRequest{
		Start: start,
		Count: count,
	}
	stream := make(countStream)
	done := make(chan struct{})
	go func() {
		defer close(done)
		for i := int32(0); ; i++ {
			resp, ok := <-stream
			if !ok {
				if i == count {
					break
				}
				t.Fatalf("stream closed after receiving %v items, want %v", i, count)
			}
			log.Printf("Client: Count response: %d", resp.Number)
			if got, want := resp.Number, start+int32(i); got != want {
				t.Fatalf("stream message out of order, got %v want %v", got, want)
			}
		}
	}()
	if err := c.Invoke("Server/Count", req, nil, stream, done); err != nil {
		t.Fatal("Count:", err)
	}
}

type countStream chan prototest.CountResponse

func (s countStream) Send(b []byte, done <-chan struct{}) error {
	var e prototest.CountResponse
	if err := pb.Unmarshal(b, &e); err != nil {
		return err
	}
	select {
	case s <- e:
	case <-done:
	}
	return nil
}

func (s countStream) Close() {
	close(s)
}

func (s countStream) Error(err error) {
}

func startClient(port string, user upspin.UserName) {
	cfg := config.SetUserName(config.New(), user)

	userDir := "test"
	if user == joeUser {
		userDir = "joe"
	}
	f, err := factotum.NewFromDir(testutil.Repo("key", "testdata", userDir))
	if err != nil {
		log.Fatal(err)
	}
	cfg = config.SetFactotum(cfg, f)

	pem, err := ioutil.ReadFile("testdata/cert.pem")
	if err != nil {
		log.Fatal(err)
	}
	pool := cfg.CertPool()
	if ok := pool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("could not add certificates to pool")
	}
	cfg = config.SetCertPool(cfg, pool)

	// Try a few times because the server may not be up yet.
	var authClient Client
	for i := 0; i < 10; i++ {
		authClient, err = NewClient(cfg, upspin.NetAddr("localhost:"+port), Secure, upspin.Endpoint{})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	if err != nil {
		log.Fatal(err)
	}
	cli = &client{
		Client: authClient,
	}
}

func TestAll(t *testing.T) {
	port := startServer(t)
	startClient(port, joeUser)

	// Inject testing into the server.
	srv.t = t

	// Test authenticated method.
	srv.iteration = 0
	cli.reqCount = 0
	for i := range payloads {
		response := cli.Echo(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}

	// Test authenticated stream.
	cli.Count(t, 0, 5)

	// Test that the client retries authentication properly
	// when the server forgets the auth token.
	srv.iteration = 0
	// Ensure we have an auth token.
	response := cli.Echo(t, payloads[0])
	if response != payloads[0] {
		t.Errorf("Payload %d: Expected response %q, got %q", 0, payloads[0], response)
	}
	// Server forgets all auth tokens.
	sessionCache = cache.NewLRU(100)
	// Try again and it works.
	response = cli.Echo(t, payloads[1])
	if response != payloads[1] {
		t.Errorf("Payload %d: Expected response %q, got %q", 1, payloads[1], response)
	}

	// Test unauthenticated method.
	startClient(port, "unknown@user.com")
	srv.iteration = 0
	cli.reqCount = 0
	for i := range payloads {
		response := cli.UnauthenticatedEcho(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}
}
<commit_msg>rpc: fix test broken by CL/8140<commit_after>// Copyright 2016 The Upspin Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"crypto/x509"
	"fmt"
	"io/ioutil"
	"net"
	"net/http"
	"testing"
	"time"

	pb "github.com/golang/protobuf/proto"

	"upspin.io/cache"
	"upspin.io/cloud/https"
	"upspin.io/config"
	"upspin.io/errors"
	"upspin.io/factotum"
	"upspin.io/log"
	prototest "upspin.io/rpc/testdata"
	"upspin.io/test/testutil"
	"upspin.io/upspin"
)

var (
	joePublic = upspin.PublicKey("p256\n104278369061367353805983276707664349405797936579880352274235000127123465616334\n26941412685198548642075210264642864401950753555952207894712845271039438170192\n")
	joeUser   = upspin.UserName("joe@blow.com")
	srv       *server
	cli       *client
)

var payloads = []string{
	"The wren",
	"Earns his living",
	"Noiselessly.",
	// - Kobayahsi Issa
}

func lookup(user upspin.UserName) (upspin.PublicKey, error) {
	if user == joeUser {
		return upspin.PublicKey(joePublic), nil
	}
	return "", errors.E(errors.NotExist, errors.Str("No user here"))
}

func pickPort() (port string) {
	listener, err := net.Listen("tcp", "localhost:0")
	if err != nil {
		log.Fatalf("Failed to listen: %v", err)
	}
	_, port, err = net.SplitHostPort(listener.Addr().String())
	if err != nil {
		log.Fatalf("Failed to parse listener address: %v", err)
	}
	listener.Close()
	return port
}

type server struct {
	t         *testing.T
	iteration int
}

func startServer(t *testing.T) (port string) {
	srv = &server{t: t}
	port = pickPort()

	cfg := config.SetUserName(config.New(), "server@upspin.io")
	cfg = config.SetKeyEndpoint(cfg, upspin.Endpoint{Transport: upspin.InProcess})
	http.Handle("/api/Server/", NewServer(cfg, Service{
		Name: "Server",
		Methods: map[string]Method{
			"Echo": srv.Echo,
		},
		UnauthenticatedMethods: map[string]UnauthenticatedMethod{
			"UnauthenticatedEcho": srv.UnauthenticatedEcho,
		},
		Streams: map[string]Stream{
			"Count": srv.Count,
		},
		Lookup: lookup,
	}))

	ready := make(chan struct{})
	go https.ListenAndServe(ready, "test", fmt.Sprintf("localhost:%s", port), nil)
	<-ready
	return port
}

func (s *server) UnauthenticatedEcho(reqBytes []byte) (pb.Message, error) {
	var req prototest.EchoRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: UnauthenticatedEcho response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

func (s *server) Echo(session Session, reqBytes []byte) (pb.Message, error) {
	var req prototest.EchoRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	if session.User() != joeUser {
		s.t.Fatalf("Expected user %q, got %q", joeUser, session.User())
	}
	if req.Payload == payloads[s.iteration] {
		resp := &prototest.EchoResponse{
			Payload: payloads[s.iteration],
		}
		log.Printf("Server: Echo response: %q", resp.Payload)
		s.iteration++
		return resp, nil
	}
	s.t.Fatalf("iteration %d: invalid request %q", s.iteration, req.Payload)
	return nil, nil // not reached
}

func (s *server) Count(session Session, reqBytes []byte, done <-chan struct{}) (<-chan pb.Message, error) {
	var req prototest.CountRequest
	if err := pb.Unmarshal(reqBytes, &req); err != nil {
		return nil, err
	}
	log.Printf("Server: Count request: %d", req.Start)

	out := make(chan pb.Message)
	go func() {
		defer close(out)
		for i := req.Start; i < req.Start+req.Count; i++ {
			resp := &prototest.CountResponse{
				Number: i,
			}
			select {
			case out <- resp:
			case <-done:
				return
			}
		}
	}()
	return out, nil
}

type client struct {
	Client   // For sessions, Ping, and Close.
	reqCount int
}

func (c *client) UnauthenticatedEcho(t *testing.T, payload string) (response string) {
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	resp := new(prototest.EchoResponse)
	log.Printf("Client: UnauthenticatedEcho request: %q", req.Payload)
	if err := c.Invoke("Server/UnauthenticatedEcho", req, resp, nil, nil); err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func (c *client) Echo(t *testing.T, payload string) (response string) {
	req := &prototest.EchoRequest{
		Payload: payload,
	}
	resp := new(prototest.EchoResponse)
	log.Printf("Client: Echo request: %q", req.Payload)
	if err := c.Invoke("Server/Echo", req, resp, nil, nil); err != nil {
		t.Fatal(err)
	}
	c.reqCount++
	return resp.Payload
}

func (c *client) Count(t *testing.T, start, count int32) {
	req := &prototest.CountRequest{
		Start: start,
		Count: count,
	}
	stream := make(countStream)
	done := make(chan struct{})
	go func() {
		defer close(done)
		for i := int32(0); ; i++ {
			resp, ok := <-stream
			if !ok {
				if i == count {
					break
				}
				t.Fatalf("stream closed after receiving %v items, want %v", i, count)
			}
			log.Printf("Client: Count response: %d", resp.Number)
			if got, want := resp.Number, start+int32(i); got != want {
				t.Fatalf("stream message out of order, got %v want %v", got, want)
			}
		}
	}()
	if err := c.Invoke("Server/Count", req, nil, stream, done); err != nil {
		t.Fatal("Count:", err)
	}
}

type countStream chan prototest.CountResponse

func (s countStream) Send(b []byte, done <-chan struct{}) error {
	var e prototest.CountResponse
	if err := pb.Unmarshal(b, &e); err != nil {
		return err
	}
	select {
	case s <- e:
	case <-done:
	}
	return nil
}

func (s countStream) Close() {
	close(s)
}

func (s countStream) Error(err error) {
}

func startClient(port string, user upspin.UserName) {
	cfg := config.SetUserName(config.New(), user)

	userDir := "test"
	if user == joeUser {
		userDir = "joe"
	}
	f, err := factotum.NewFromDir(testutil.Repo("key", "testdata", userDir))
	if err != nil {
		log.Fatal(err)
	}
	cfg = config.SetFactotum(cfg, f)

	pem, err := ioutil.ReadFile("testdata/cert.pem")
	if err != nil {
		log.Fatal(err)
	}
	pool := x509.NewCertPool()
	if ok := pool.AppendCertsFromPEM(pem); !ok {
		log.Fatal("could not add certificates to pool")
	}
	cfg = config.SetCertPool(cfg, pool)

	// Try a few times because the server may not be up yet.
	var authClient Client
	for i := 0; i < 10; i++ {
		authClient, err = NewClient(cfg, upspin.NetAddr("localhost:"+port), Secure, upspin.Endpoint{})
		if err == nil {
			break
		}
		time.Sleep(50 * time.Millisecond)
	}
	if err != nil {
		log.Fatal(err)
	}
	cli = &client{
		Client: authClient,
	}
}

func TestAll(t *testing.T) {
	port := startServer(t)
	startClient(port, joeUser)

	// Inject testing into the server.
	srv.t = t

	// Test authenticated method.
	srv.iteration = 0
	cli.reqCount = 0
	for i := range payloads {
		response := cli.Echo(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}

	// Test authenticated stream.
	cli.Count(t, 0, 5)

	// Test that the client retries authentication properly
	// when the server forgets the auth token.
	srv.iteration = 0
	// Ensure we have an auth token.
	response := cli.Echo(t, payloads[0])
	if response != payloads[0] {
		t.Errorf("Payload %d: Expected response %q, got %q", 0, payloads[0], response)
	}
	// Server forgets all auth tokens.
	sessionCache = cache.NewLRU(100)
	// Try again and it works.
	response = cli.Echo(t, payloads[1])
	if response != payloads[1] {
		t.Errorf("Payload %d: Expected response %q, got %q", 1, payloads[1], response)
	}

	// Test unauthenticated method.
	startClient(port, "unknown@user.com")
	srv.iteration = 0
	cli.reqCount = 0
	for i := range payloads {
		response := cli.UnauthenticatedEcho(t, payloads[i])
		if response != payloads[i] {
			t.Errorf("Payload %d: Expected response %q, got %q", i, payloads[i], response)
		}
	}
	if srv.iteration != len(payloads) {
		t.Errorf("Expected server to be on iteration %d, was on %d", len(payloads), srv.iteration)
	}
	if cli.reqCount != srv.iteration {
		t.Errorf("Expected client to be on iteration %d, was on %d", srv.iteration, cli.reqCount)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"fmt"
	"net"
	"sync"
	"time"

	"v.io/v23/naming"
)

// DialerFunc is the function used to create net.Conn objects given a
// protocol-specific string representation of an address.
type DialerFunc func(protocol, address string, timeout time.Duration) (net.Conn, error)

// ResolverFunc is the function used for protocol-specific address normalization.
// e.g. the TCP resolve performs DNS resolution.
type ResolverFunc func(protocol, address string) (string, string, error)

// ListenerFunc is the function used to create net.Listener objects given a
// protocol-specific string representation of the address a server will listen on.
type ListenerFunc func(protocol, address string) (net.Listener, error)

// RegisterProtocol makes available a Dialer, Resolver, and Listener to RegisteredNetwork.
// If the protocol represents other actual protocols, you need to specify all the
// actual protocols. E.g, "wsh" represents "tcp4", "tcp6", "ws4", and "ws6".
//
// Implementations of the Manager interface are expected to use this registry
// in order to expand the reach of the types of network protocols they can
// handle.
//
// Successive calls to RegisterProtocol replace the contents of a previous
// call to it and returns trues if a previous value was replaced, false otherwise.
func RegisterProtocol(protocol string, dialer DialerFunc, resolver ResolverFunc, listener ListenerFunc, p ...string) bool {
	// This is for handling the common case where protocol is a "singleton", to
	// make it easier to specify.
	if len(p) == 0 {
		p = []string{protocol}
	}
	registryLock.Lock()
	defer registryLock.Unlock()
	_, present := registry[protocol]
	registry[protocol] = registryEntry{dialer, resolver, listener, p}
	return present
}

// RegisterUnknownProtocol registers a Dialer, Resolver, and Listener for endpoints with
// no specified protocol.
//
// The desired protocol provided in the first argument will be passed to the
// Dialer and Listener as the actual protocol to use when dialing or listening.
//
// The protocol itself must have already been registered before RegisterUnknownProtocol
// is called, otherwise we'll panic.
func RegisterUnknownProtocol(protocol string, dialer DialerFunc, resolver ResolverFunc, listener ListenerFunc) bool {
	var p []string
	registryLock.RLock()
	r, present := registry[protocol]
	if !present {
		panic(fmt.Sprintf("%s not registered", protocol))
	}
	p = r.p
	registryLock.RUnlock()
	wrappedDialer := func(_, address string, timeout time.Duration) (net.Conn, error) {
		return dialer(protocol, address, timeout)
	}
	wrappedResolver := func(_, address string) (string, string, error) {
		return resolver(protocol, address)
	}
	wrappedListener := func(_, address string) (net.Listener, error) {
		return listener(protocol, address)
	}
	return RegisterProtocol(naming.UnknownProtocol, wrappedDialer, wrappedResolver, wrappedListener, p...)
}

// RegisteredProtocol returns the Dialer, Resolver, and Listener registered with a
// previous call to RegisterProtocol.
func RegisteredProtocol(protocol string) (DialerFunc, ResolverFunc, ListenerFunc, []string) {
	registryLock.RLock()
	e := registry[protocol]
	registryLock.RUnlock()
	return e.d, e.r, e.l, e.p
}

// RegisteredProtocols returns the list of protocols that have been previously
// registered using RegisterProtocol. The underlying implementation will
// support additional protocols such as those supported by the native RPC stack.
func RegisteredProtocols() []string {
	registryLock.RLock()
	defer registryLock.RUnlock()
	p := make([]string, 0, len(registry))
	for k, _ := range registry {
		p = append(p, k)
	}
	return p
}

type registryEntry struct {
	d DialerFunc
	r ResolverFunc
	l ListenerFunc
	p []string
}

var (
	registryLock sync.RWMutex
	registry     = make(map[string]registryEntry)
)
<commit_msg>v23: Add ctx to RegisteredProtocol dial, resolve, and listen functions<commit_after>// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package rpc

import (
	"fmt"
	"net"
	"sync"
	"time"

	"v.io/v23/context"
	"v.io/v23/naming"
)

// DialerFunc is the function used to create net.Conn objects given a
// protocol-specific string representation of an address.
type DialerFunc func(ctx *context.T, protocol, address string, timeout time.Duration) (net.Conn, error)

// ResolverFunc is the function used for protocol-specific address normalization.
// e.g. the TCP resolve performs DNS resolution.
type ResolverFunc func(ctx *context.T, protocol, address string) (string, string, error)

// ListenerFunc is the function used to create net.Listener objects given a
// protocol-specific string representation of the address a server will listen on.
type ListenerFunc func(ctx *context.T, protocol, address string) (net.Listener, error)

// RegisterProtocol makes available a Dialer, Resolver, and Listener to RegisteredNetwork.
// If the protocol represents other actual protocols, you need to specify all the
// actual protocols. E.g, "wsh" represents "tcp4", "tcp6", "ws4", and "ws6".
//
// Implementations of the Manager interface are expected to use this registry
// in order to expand the reach of the types of network protocols they can
// handle.
//
// Successive calls to RegisterProtocol replace the contents of a previous
// call to it and returns trues if a previous value was replaced, false otherwise.
func RegisterProtocol(protocol string, dialer DialerFunc, resolver ResolverFunc, listener ListenerFunc, p ...string) bool {
	// This is for handling the common case where protocol is a "singleton", to
	// make it easier to specify.
	if len(p) == 0 {
		p = []string{protocol}
	}
	registryLock.Lock()
	defer registryLock.Unlock()
	_, present := registry[protocol]
	registry[protocol] = registryEntry{dialer, resolver, listener, p}
	return present
}

// RegisterUnknownProtocol registers a Dialer, Resolver, and Listener for endpoints with
// no specified protocol.
//
// The desired protocol provided in the first argument will be passed to the
// Dialer and Listener as the actual protocol to use when dialing or listening.
//
// The protocol itself must have already been registered before RegisterUnknownProtocol
// is called, otherwise we'll panic.
func RegisterUnknownProtocol(protocol string, dialer DialerFunc, resolver ResolverFunc, listener ListenerFunc) bool {
	var p []string
	registryLock.RLock()
	r, present := registry[protocol]
	if !present {
		panic(fmt.Sprintf("%s not registered", protocol))
	}
	p = r.p
	registryLock.RUnlock()
	wrappedDialer := func(ctx *context.T, _, address string, timeout time.Duration) (net.Conn, error) {
		return dialer(ctx, protocol, address, timeout)
	}
	wrappedResolver := func(ctx *context.T, _, address string) (string, string, error) {
		return resolver(ctx, protocol, address)
	}
	wrappedListener := func(ctx *context.T, _, address string) (net.Listener, error) {
		return listener(ctx, protocol, address)
	}
	return RegisterProtocol(naming.UnknownProtocol, wrappedDialer, wrappedResolver, wrappedListener, p...)
}

// RegisteredProtocol returns the Dialer, Resolver, and Listener registered with a
// previous call to RegisterProtocol.
func RegisteredProtocol(protocol string) (DialerFunc, ResolverFunc, ListenerFunc, []string) {
	registryLock.RLock()
	e := registry[protocol]
	registryLock.RUnlock()
	return e.d, e.r, e.l, e.p
}

// RegisteredProtocols returns the list of protocols that have been previously
// registered using RegisterProtocol. The underlying implementation will
// support additional protocols such as those supported by the native RPC stack.
func RegisteredProtocols() []string {
	registryLock.RLock()
	defer registryLock.RUnlock()
	p := make([]string, 0, len(registry))
	for k, _ := range registry {
		p = append(p, k)
	}
	return p
}

type registryEntry struct {
	d DialerFunc
	r ResolverFunc
	l ListenerFunc
	p []string
}

var (
	registryLock sync.RWMutex
	registry     = make(map[string]registryEntry)
)
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"github.com/Jeffail/gabs"
)

// Load and parse guest configuration from JSON format.
func loadGuestConfig(path string) (config *gabs.Container, err error) {
	src, err := os.Open(path);
	if err != nil {
		return
	}
	defer src.Close()
	config, err = gabs.ParseJSONBuffer(src)
	return
}

// Save guest configuration to path from JSON format.
func saveGuestConfig(config *gabs.Container, path string) (err error) {
	s := config.String()
	dst, err := os.Create(path)
	if err != nil {
		return
	}
	defer dst.Close()
	_, err = dst.WriteString(s)
	return
}

// Merge ("generate?") guest network configuration from host configuration.
func mergeNetConfig(netconfig *netConfig, guest *gabs.Container) (err error) {
	if guest.ExistsP("hostname") {
		log.Print("Guest already defines hostname, not overriden")
	} else {
		guest.SetP(netconfig.hostname, "hostname")
	}
	if guest.ExistsP("net") {
		return fmt.Errorf("Guest already defines net configuration")
	}
	addrs, _ := guest.ArrayOfSizeP(1, "net.interfaces.vioif0.addrs")
	addr, _ := addrs.ObjectI(0)
	addr.Set("inet", "type")
	addr.Set("static", "method")
	addr.Set(netconfig.ipAddress, "addr")
	gateways, _ := guest.ArrayOfSizeP(1, "net.gateways")
	gw, _ := gateways.ObjectI(0)
	gw.Set("inet", "type")
	gw.Set(netconfig.gateway, "addr")
	dns, _ := guest.ObjectP("net.dns")
	if netconfig.dnsServers != nil {
		dns.Set(netconfig.dnsServers, "nameservers")
	}
	if netconfig.dnsSearch != nil {
		dns.Set(netconfig.dnsSearch, "search")
	}
	return
}

// Merge guest volume/block device configuration with any volumes found in
// host container.
func mergeVolumeConfig(volumeconfig []volumeConfig, guest *gabs.Container) (err error) {
	var mounts *gabs.Container
	if guest.ExistsP("mount") {
		mounts = guest.S("mount")
	} else {
		mounts, _ = guest.ObjectP("mount")
	}
	mmap, _ := mounts.ChildrenMap()
	for _, mount := range mmap {
		var source string
		var path string
		var ok bool
		if source, ok = mount.Path("source").Data().(string); !ok {
			continue
		}
		if path, ok = mount.Path("path").Data().(string); !ok {
			continue
		}
		if source == "blk" && strings.HasPrefix(path, "/dev/ld") {
			return fmt.Errorf("Guest configuration defines " +
				"/dev/ld* block devices, cannot merge with " +
				"host volumes")
		}
	}
	blkIndex := 0
	for _, v := range volumeconfig {
		mp := "/" + v.name
		obj, _ := guest.Object("mount", mp)
		obj.Set("blk", "source")
		obj.Set(fmt.Sprintf("/dev/ld%va", blkIndex), "path")
		blkIndex += 1
	}
	return
}
<commit_msg>Use netbsd.sysctl to set hostname<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"strings"
	"github.com/Jeffail/gabs"
)

// Load and parse guest configuration from JSON format.
func loadGuestConfig(path string) (config *gabs.Container, err error) {
	src, err := os.Open(path);
	if err != nil {
		return
	}
	defer src.Close()
	config, err = gabs.ParseJSONBuffer(src)
	return
}

// Save guest configuration to path from JSON format.
func saveGuestConfig(config *gabs.Container, path string) (err error) {
	s := config.String()
	dst, err := os.Create(path)
	if err != nil {
		return
	}
	defer dst.Close()
	_, err = dst.WriteString(s)
	return
}

// Merge ("generate?") guest network configuration from host configuration.
func mergeNetConfig(netconfig *netConfig, guest *gabs.Container) (err error) {
	if guest.Exists("netbsd", "sysctl", "kern.hostname") {
		log.Print("Guest already defines hostname, not overriden")
	} else {
		_, err := guest.Set(netconfig.hostname, "netbsd", "sysctl", "kern.hostname")
		if err != nil {
			return err
		}
	}
	if guest.ExistsP("net") {
		return fmt.Errorf("Guest already defines net configuration")
	}
	addrs, _ := guest.ArrayOfSizeP(1, "net.interfaces.vioif0.addrs")
	addr, _ := addrs.ObjectI(0)
	addr.Set("inet", "type")
	addr.Set("static", "method")
	addr.Set(netconfig.ipAddress, "addr")
	gateways, _ := guest.ArrayOfSizeP(1, "net.gateways")
	gw, _ := gateways.ObjectI(0)
	gw.Set("inet", "type")
	gw.Set(netconfig.gateway, "addr")
	dns, _ := guest.ObjectP("net.dns")
	if netconfig.dnsServers != nil {
		dns.Set(netconfig.dnsServers, "nameservers")
	}
	if netconfig.dnsSearch != nil {
		dns.Set(netconfig.dnsSearch, "search")
	}
	return
}

// Merge guest volume/block device configuration with any volumes found in
// host container.
func mergeVolumeConfig(volumeconfig []volumeConfig, guest *gabs.Container) (err error) {
	var mounts *gabs.Container
	if guest.ExistsP("mount") {
		mounts = guest.S("mount")
	} else {
		mounts, _ = guest.ObjectP("mount")
	}
	mmap, _ := mounts.ChildrenMap()
	for _, mount := range mmap {
		var source string
		var path string
		var ok bool
		if source, ok = mount.Path("source").Data().(string); !ok {
			continue
		}
		if path, ok = mount.Path("path").Data().(string); !ok {
			continue
		}
		if source == "blk" && strings.HasPrefix(path, "/dev/ld") {
			return fmt.Errorf("Guest configuration defines " +
				"/dev/ld* block devices, cannot merge with " +
				"host volumes")
		}
	}
	blkIndex := 0
	for _, v := range volumeconfig {
		mp := "/" + v.name
		obj, _ := guest.Object("mount", mp)
		obj.Set("blk", "source")
		obj.Set(fmt.Sprintf("/dev/ld%va", blkIndex), "path")
		blkIndex += 1
	}
	return
}
<|endoftext|>


<commit_before>package runner

import (
	"sync"
	"sync/atomic"
)

// Queue runs function scheduled in a seperate gorountine. Normally you don't
// need to explicitly create or use Queue, Par / Tables implicitly create queues
// and schedule user-defined Saws to some of them.
type Queue struct {
	// TODO(yuheng): potential contetion hotspot, current benchmark doesn't show
	// problem. Find other solution if it's actually troublesome.
	waitGroup *sync.WaitGroup
	chn       chan func()
}

func (q *Queue) run() {
	for f := range q.chn {
		f()
		q.waitGroup.Done()
	}
}

func (q *Queue) close() {
	close(q.chn)
}

// Schedule a function to run on queue.
func (q *Queue) Sched(f func()) {
	q.waitGroup.Add(1)
	q.chn <- f
}

// Par manages a set of queues, when Sched, it puts task into one of them using
// round-robin
type Par struct {
	round  uint32
	queues []*Queue
}

func (par *Par) Sched(f func(), hash int) {
	var shard int
	if hash >= 0 {
		shard = hash % len(par.queues)
	} else {
		shard = int(atomic.AddUint32(&par.round, 1)) % len(par.queues)
	}
	par.queues[shard].Sched(f)
}

// QueueGroup manages a set of queues running colloaborated tasks.
type QueueGroup struct {
	queues    []*Queue
	waitGroup sync.WaitGroup
	mu        sync.Mutex
}

// New creates a queue managed by this QueueGroup.
func (group *QueueGroup) New(bufferSize int) *Queue {
	group.mu.Lock()
	defer group.mu.Unlock()
	queue := &Queue{
		waitGroup: &group.waitGroup,
		chn:       make(chan func(), bufferSize),
	}
	go queue.run()
	group.queues = append(group.queues, queue)
	return queue
}

// NewPar creates a par with all its queues managed by this QueueGroup
func (group *QueueGroup) NewPar(numShards, bufferSize int) *Par {
	queues := make([]*Queue, numShards)
	for i := 0; i < numShards; i++ {
		queues[i] = group.New(bufferSize)
	}
	return &Par{queues: queues}
}

// Join waits until all pending tasks in queues done, then close and cleanup
// all queues it manages
func (group *QueueGroup) Join() {
	group.mu.Lock()
	defer group.mu.Unlock()

	group.waitGroup.Wait()
	for _, q := range group.queues {
		q.close()
	}
	group.queues = nil
}
<commit_msg>update outdated docs<commit_after>package runner

import (
	"sync"
	"sync/atomic"
)

// Default schedule strategy of Par.
const SchedRoundRobin = -1

// Queue runs function scheduled in a seperate gorountine. Normally you don't
// need to explicitly create or use Queue, Par / Tables implicitly create queues
// and schedule user-defined Saws to some of them.
type Queue struct {
	// TODO(yuheng): potential contetion hotspot, current benchmark doesn't show
	// problem. Find other solution if it's actually troublesome.
	waitGroup *sync.WaitGroup
	chn       chan func()
}

func (q *Queue) run() {
	for f := range q.chn {
		f()
		q.waitGroup.Done()
	}
}

func (q *Queue) close() {
	close(q.chn)
}

// Schedule a function to run on queue.
func (q *Queue) Sched(f func()) {
	q.waitGroup.Add(1)
	q.chn <- f
}

// Par manages a set of queues, when Sched, it puts task into one of them using
// hash or round-robin
type Par struct {
	round  uint32
	queues []*Queue
}

// Schedule a function to run in one of Par's queues, returns after inserted in
// queue. when hash < 0, schedule select queue by round-robin, otherwise, it
// selects specific queue by hash. hash is just an optimization to minimize
// contention, caller should not relie on queue selecting behavior.
func (par *Par) Sched(f func(), hash int) {
	var shard int
	if hash >= 0 {
		shard = hash % len(par.queues)
	} else {
		shard = int(atomic.AddUint32(&par.round, 1)) % len(par.queues)
	}
	par.queues[shard].Sched(f)
}

// QueueGroup manages a set of queues running colloaborated tasks.
type QueueGroup struct {
	queues    []*Queue
	waitGroup sync.WaitGroup
	mu        sync.Mutex
}

// New creates a queue managed by this QueueGroup.
func (group *QueueGroup) New(bufferSize int) *Queue {
	group.mu.Lock()
	defer group.mu.Unlock()
	queue := &Queue{
		waitGroup: &group.waitGroup,
		chn:       make(chan func(), bufferSize),
	}
	go queue.run()
	group.queues = append(group.queues, queue)
	return queue
}

// NewPar creates a par with all its queues managed by this QueueGroup
func (group *QueueGroup) NewPar(numShards, bufferSize int) *Par {
	queues := make([]*Queue, numShards)
	for i := 0; i < numShards; i++ {
		queues[i] = group.New(bufferSize)
	}
	return &Par{queues: queues}
}

// Join waits until all pending tasks in queues done, then close and cleanup
// all queues it manages
func (group *QueueGroup) Join() {
	group.mu.Lock()
	defer group.mu.Unlock()

	group.waitGroup.Wait()
	for _, q := range group.queues {
		q.close()
	}
	group.queues = nil
}
<|endoftext|>


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

package main

import (
	"flag"
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3"
	"os"
)

var bucketName = flag.String("bucket", "", "Bucket name.")
var region = flag.String("region", "", "Region endpoint server.")

func main() {
	flag.Parse()

	if *bucketName == "" {
		fmt.Println("You must set the -bucket flag.")
		os.Exit(1)
	}

	if *region == "" {
		fmt.Println("You must set the -region flag.")
		os.Exit(1)
	}

	// Read in the access key.
	accessKey := aws.AccessKey{}
	accessKey.Id = readPassword("Access key ID: ")
	accessKey.Secret = readPassword("Access key secret: ")

	// Create a bucket object.
	_, err := s3.OpenBucket(*bucketName, s3.Region(*region), accessKey)
	if err != nil {
		fmt.Println("Opening bucket:", err)
		os.Exit(1)
	}
}

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

package main

import (
	"bytes"
	"flag"
	"fmt"
	"github.com/jacobsa/aws"
	"github.com/jacobsa/aws/s3"
	"os"
)

var keyId = flag.String("key_id", "", "Access key ID.")
var bucketName = flag.String("bucket", "", "Bucket name.")
var region = flag.String("region", "", "Region endpoint server.")

func main() {
	flag.Parse()

	if *keyId == "" {
		fmt.Println("You must set the -key_id flag.")
		os.Exit(1)
	}

	if *bucketName == "" {
		fmt.Println("You must set the -bucket flag.")
		os.Exit(1)
	}

	if *region == "" {
		fmt.Println("You must set the -region flag.")
		os.Exit(1)
	}

	// Read in the access key.
	accessKey := aws.AccessKey{Id: *keyId}
	accessKey.Secret = readPassword("Access key secret: ")

	// Open a bucket.
	bucket, err := s3.OpenBucket(*bucketName, s3.Region(*region), accessKey)
	if err != nil {
		fmt.Println("Opening bucket:", err)
		os.Exit(1)
	}

	// Attempt to create an object.
	data := []byte("taco")
	data = append(data, 0x00)
	data = append(data, []byte("burrito")...)

	if err := bucket.StoreObject("some_taco", data); err != nil {
		fmt.Println("StoreObject:", err)
		os.Exit(1)
	}

	// Read the object back.
	dataRead, err := bucket.GetObject("some_taco")
	if err != nil {
		fmt.Println("GetObject:", err)
		os.Exit(1)
	}

	// Make sure the result is identical.
	if !bytes.Equal(data, dataRead) {
		fmt.Printf("Mismatch; %x vs. %x\n", data, dataRead)
		os.Exit(1)
	}

	// Attempt to load a non-existent object.
	_, err = bucket.GetObject("other_name")
	fmt.Println("404 error:", err)
}

<|endoftext|>