<commit_before>package simpleredis

import (
	"errors"
	"strconv"
	"strings"

	"github.com/garyburd/redigo/redis"
)

// Common for each of the redis datastructures used here
type redisDatastructure struct {
	pool    *ConnectionPool
	id      string
	dbindex int
}

type (
	// A pool of readily available Redis connections
	ConnectionPool redis.Pool

	List     redisDatastructure
	Set      redisDatastructure
	HashMap  redisDatastructure
	KeyValue redisDatastructure
)

const (
	// Version number. Stable API within major version numbers.
	Version = 1.0
	// The default [url]:port that Redis is running at
	defaultRedisServer = ":6379"
)

var (
	// How many connections should stay ready for requests, at a maximum?
	// When an idle connection is used, new idle connections are created.
	maxIdleConnections = 3
)

/* --- Helper functions --- */

// Connect to the local instance of Redis at port 6379
func newRedisConnection() (redis.Conn, error) {
	return newRedisConnectionTo(defaultRedisServer)
}

// Connect to host:port, host may be omitted, so ":6379" is valid.
// Will not try to AUTH with any given password (password@host:port).
func newRedisConnectionTo(hostColonPort string) (redis.Conn, error) {
	// Discard the password, if provided
	if _, theRest, ok := twoFields(hostColonPort, "@"); ok {
		hostColonPort = theRest
	}
	return redis.Dial("tcp", hostColonPort)
}

// Get a string from a list of results at a given position
func getString(bi []interface{}, i int) string {
	return string(bi[i].([]uint8))
}

// Test if the local Redis server is up and running
func TestConnection() (err error) {
	return TestConnectionHost(defaultRedisServer)
}

// Test if a given Redis server at host:port is up and running.
// Does not try to PING or AUTH.
func TestConnectionHost(hostColonPort string) (err error) {
	// Connect to the given host:port
	conn, err := newRedisConnectionTo(hostColonPort)
	defer conn.Close()
	defer func() {
		if r := recover(); r != nil {
			err = errors.New("Could not connect to redis server: " + hostColonPort)
		}
	}()
	return err
}

/* --- ConnectionPool functions --- */

// Create a new connection pool
func NewConnectionPool() *ConnectionPool {
	// The second argument is the maximum number of idle connections
	redisPool := redis.NewPool(newRedisConnection, maxIdleConnections)
	pool := ConnectionPool(*redisPool)
	return &pool
}

// Split a string into two parts, given a delimiter.
// Returns the two parts and true if it works out.
func twoFields(s, delim string) (string, string, bool) {
	if strings.Count(s, delim) != 1 {
		return s, "", false
	}
	fields := strings.Split(s, delim)
	return fields[0], fields[1], true
}

// Create a new connection pool given a host:port string.
// A password may be supplied as well, on the form "password@host:port".
func NewConnectionPoolHost(hostColonPort string) *ConnectionPool {
	// Create a redis Pool
	redisPool := redis.NewPool(
		// Anonymous function for calling new RedisConnectionTo with the host:port
		func() (redis.Conn, error) {
			conn, err := newRedisConnectionTo(hostColonPort)
			if err != nil {
				return nil, err
			}
			// If a password is given, use it to authenticate
			if password, _, ok := twoFields(hostColonPort, "@"); ok {
				if password != "" {
					if _, err := conn.Do("AUTH", password); err != nil {
						conn.Close()
						return nil, err
					}
				}
			}
			return conn, err
		},
		// Maximum number of idle connections to the redis database
		maxIdleConnections)
	pool := ConnectionPool(*redisPool)
	return &pool
}

// Set the number of maximum *idle* connections standing ready when
// creating new connection pools. When an idle connection is used,
// a new idle connection is created. The default is 3 and should be fine
// for most cases.
func SetMaxIdleConnections(maximum int) {
	maxIdleConnections = maximum
}

// Get one of the available connections from the connection pool, given a database index
func (pool *ConnectionPool) Get(dbindex int) redis.Conn {
	redisPool := redis.Pool(*pool)
	conn := redisPool.Get()
	// The default database index is 0
	if dbindex != 0 {
		// SELECT is not critical, ignore the return values
		conn.Do("SELECT", strconv.Itoa(dbindex))
	}
	return conn
}

// Ping the server by sending a PING command
func (pool *ConnectionPool) Ping() (pong bool) {
	redisPool := redis.Pool(*pool)
	conn := redisPool.Get()
	_, err := conn.Do("PING")
	return err == nil
}

// Close down the connection pool
func (pool *ConnectionPool) Close() {
	redisPool := redis.Pool(*pool)
	redisPool.Close()
}

/* --- List functions --- */

// Create a new list
func NewList(pool *ConnectionPool, id string) *List {
	return &List{pool, id, 0}
}

// Select a different database
func (rl *List) SelectDatabase(dbindex int) {
	rl.dbindex = dbindex
}

// Add an element to the list
func (rl *List) Add(value string) error {
	conn := rl.pool.Get(rl.dbindex)
	_, err := conn.Do("RPUSH", rl.id, value)
	return err
}

// Get all elements of a list
func (rl *List) GetAll() ([]string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "0", "-1"))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Get the last element of a list
func (rl *List) GetLast() (string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "-1", "-1"))
	if len(result) == 1 {
		return getString(result, 0), err
	}
	return "", err
}

// Get the last N elements of a list
func (rl *List) GetLastN(n int) ([]string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "-"+strconv.Itoa(n), "-1"))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Remove this list
func (rl *List) Remove() error {
	conn := rl.pool.Get(rl.dbindex)
	_, err := conn.Do("DEL", rl.id)
	return err
}

/* --- Set functions --- */

// Create a new set
func NewSet(pool *ConnectionPool, id string) *Set {
	return &Set{pool, id, 0}
}

// Select a different database
func (rs *Set) SelectDatabase(dbindex int) {
	rs.dbindex = dbindex
}

// Add an element to the set
func (rs *Set) Add(value string) error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("SADD", rs.id, value)
	return err
}

// Check if a given value is in the set
func (rs *Set) Has(value string) (bool, error) {
	conn := rs.pool.Get(rs.dbindex)
	retval, err := conn.Do("SISMEMBER", rs.id, value)
	if err != nil {
		panic(err)
	}
	return redis.Bool(retval, err)
}

// Get all elements of the set
func (rs *Set) GetAll() ([]string, error) {
	conn := rs.pool.Get(rs.dbindex)
	result, err := redis.Values(conn.Do("SMEMBERS", rs.id))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Remove an element from the set
func (rs *Set) Del(value string) error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("SREM", rs.id, value)
	return err
}

// Remove this set
func (rs *Set) Remove() error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("DEL", rs.id)
	return err
}

/* --- HashMap functions --- */

// Create a new hashmap
func NewHashMap(pool *ConnectionPool, id string) *HashMap {
	return &HashMap{pool, id, 0}
}

// Select a different database
func (rh *HashMap) SelectDatabase(dbindex int) {
	rh.dbindex = dbindex
}

// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (rh *HashMap) Set(elementid, key, value string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("HSET", rh.id+":"+elementid, key, value)
	return err
}

// Get a value from a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (rh *HashMap) Get(elementid, key string) (string, error) {
	conn := rh.pool.Get(rh.dbindex)
	result, err := redis.String(conn.Do("HGET", rh.id+":"+elementid, key))
	if err != nil {
		return "", err
	}
	return result, nil
}

// Check if a given elementid + key is in the hash map
func (rh *HashMap) Has(elementid, key string) (bool, error) {
	conn := rh.pool.Get(rh.dbindex)
	retval, err := conn.Do("HEXISTS", rh.id+":"+elementid, key)
	if err != nil {
		panic(err)
	}
	return redis.Bool(retval, err)
}

// Check if a given elementid exists as a hash map at all
func (rh *HashMap) Exists(elementid string) (bool, error) {
	// TODO: key is not meant to be a wildcard, check for "*"
	return hasKey(rh.pool, rh.id+":"+elementid, rh.dbindex)
}

// Get all elementid's for all hash elements
func (rh *HashMap) GetAll() ([]string, error) {
	conn := rh.pool.Get(rh.dbindex)
	result, err := redis.Values(conn.Do("KEYS", rh.id+":*"))
	strs := make([]string, len(result))
	idlen := len(rh.id)
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)[idlen+1:]
	}
	return strs, err
}

// Remove a key for an entry in a hashmap (for instance the email field for a user)
func (rh *HashMap) DelKey(elementid, key string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("HDEL", rh.id+":"+elementid, key)
	return err
}

// Remove an element (for instance a user)
func (rh *HashMap) Del(elementid string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("DEL", rh.id+":"+elementid)
	return err
}

// Remove this hashmap
func (rh *HashMap) Remove() error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("DEL", rh.id)
	return err
}

/* --- KeyValue functions --- */

// Create a new key/value
func NewKeyValue(pool *ConnectionPool, id string) *KeyValue {
	return &KeyValue{pool, id, 0}
}

// Select a different database
func (rkv *KeyValue) SelectDatabase(dbindex int) {
	rkv.dbindex = dbindex
}

// Set a key and value
func (rkv *KeyValue) Set(key, value string) error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("SET", rkv.id+":"+key, value)
	return err
}

// Get a value given a key
func (rkv *KeyValue) Get(key string) (string, error) {
	conn := rkv.pool.Get(rkv.dbindex)
	result, err := redis.String(conn.Do("GET", rkv.id+":"+key))
	if err != nil {
		return "", err
	}
	return result, nil
}

// Remove a key
func (rkv *KeyValue) Del(key string) error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("DEL", rkv.id+":"+key)
	return err
}

// Remove this key/value
func (rkv *KeyValue) Remove() error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("DEL", rkv.id)
	return err
}

// --- Generic redis functions ---

// Check if a key exists. The key can be a wildcard (ie. "user*").
func hasKey(pool *ConnectionPool, wildcard string, dbindex int) (bool, error) {
	conn := pool.Get(dbindex)
	result, err := redis.Values(conn.Do("KEYS", wildcard))
	if err != nil {
		return false, err
	}
	return len(result) > 0, nil
}
<commit_msg>Minor change<commit_after>package simpleredis

import (
	"errors"
	"strconv"
	"strings"

	"github.com/garyburd/redigo/redis"
)

// Common for each of the redis datastructures used here
type redisDatastructure struct {
	pool    *ConnectionPool
	id      string
	dbindex int
}

type (
	// A pool of readily available Redis connections
	ConnectionPool redis.Pool

	List     redisDatastructure
	Set      redisDatastructure
	HashMap  redisDatastructure
	KeyValue redisDatastructure
)

const (
	// Version number. Stable API within major version numbers.
	Version = 1.0
	// The default [url]:port that Redis is running at
	defaultRedisServer = ":6379"
)

var (
	// How many connections should stay ready for requests, at a maximum?
	// When an idle connection is used, new idle connections are created.
	maxIdleConnections = 3
)

/* --- Helper functions --- */

// Connect to the local instance of Redis at port 6379
func newRedisConnection() (redis.Conn, error) {
	return newRedisConnectionTo(defaultRedisServer)
}

// Connect to host:port, host may be omitted, so ":6379" is valid.
// Will not try to AUTH with any given password (password@host:port).
func newRedisConnectionTo(hostColonPort string) (redis.Conn, error) {
	// Discard the password, if provided
	if _, theRest, ok := twoFields(hostColonPort, "@"); ok {
		return redis.Dial("tcp", theRest)
	}
	return redis.Dial("tcp", hostColonPort)
}

// Get a string from a list of results at a given position
func getString(bi []interface{}, i int) string {
	return string(bi[i].([]uint8))
}

// Test if the local Redis server is up and running
func TestConnection() (err error) {
	return TestConnectionHost(defaultRedisServer)
}

// Test if a given Redis server at host:port is up and running.
// Does not try to PING or AUTH.
func TestConnectionHost(hostColonPort string) (err error) {
	// Connect to the given host:port
	conn, err := newRedisConnectionTo(hostColonPort)
	defer conn.Close()
	defer func() {
		if r := recover(); r != nil {
			err = errors.New("Could not connect to redis server: " + hostColonPort)
		}
	}()
	return err
}

/* --- ConnectionPool functions --- */

// Create a new connection pool
func NewConnectionPool() *ConnectionPool {
	// The second argument is the maximum number of idle connections
	redisPool := redis.NewPool(newRedisConnection, maxIdleConnections)
	pool := ConnectionPool(*redisPool)
	return &pool
}

// Split a string into two parts, given a delimiter.
// Returns the two parts and true if it works out.
func twoFields(s, delim string) (string, string, bool) {
	if strings.Count(s, delim) != 1 {
		return s, "", false
	}
	fields := strings.Split(s, delim)
	return fields[0], fields[1], true
}

// Create a new connection pool given a host:port string.
// A password may be supplied as well, on the form "password@host:port".
func NewConnectionPoolHost(hostColonPort string) *ConnectionPool {
	// Create a redis Pool
	redisPool := redis.NewPool(
		// Anonymous function for calling new RedisConnectionTo with the host:port
		func() (redis.Conn, error) {
			conn, err := newRedisConnectionTo(hostColonPort)
			if err != nil {
				return nil, err
			}
			// If a password is given, use it to authenticate
			if password, _, ok := twoFields(hostColonPort, "@"); ok {
				if password != "" {
					if _, err := conn.Do("AUTH", password); err != nil {
						conn.Close()
						return nil, err
					}
				}
			}
			return conn, err
		},
		// Maximum number of idle connections to the redis database
		maxIdleConnections)
	pool := ConnectionPool(*redisPool)
	return &pool
}

// Set the number of maximum *idle* connections standing ready when
// creating new connection pools. When an idle connection is used,
// a new idle connection is created. The default is 3 and should be fine
// for most cases.
func SetMaxIdleConnections(maximum int) {
	maxIdleConnections = maximum
}

// Get one of the available connections from the connection pool, given a database index
func (pool *ConnectionPool) Get(dbindex int) redis.Conn {
	redisPool := redis.Pool(*pool)
	conn := redisPool.Get()
	// The default database index is 0
	if dbindex != 0 {
		// SELECT is not critical, ignore the return values
		conn.Do("SELECT", strconv.Itoa(dbindex))
	}
	return conn
}

// Ping the server by sending a PING command
func (pool *ConnectionPool) Ping() (pong bool) {
	redisPool := redis.Pool(*pool)
	conn := redisPool.Get()
	_, err := conn.Do("PING")
	return err == nil
}

// Close down the connection pool
func (pool *ConnectionPool) Close() {
	redisPool := redis.Pool(*pool)
	redisPool.Close()
}

/* --- List functions --- */

// Create a new list
func NewList(pool *ConnectionPool, id string) *List {
	return &List{pool, id, 0}
}

// Select a different database
func (rl *List) SelectDatabase(dbindex int) {
	rl.dbindex = dbindex
}

// Add an element to the list
func (rl *List) Add(value string) error {
	conn := rl.pool.Get(rl.dbindex)
	_, err := conn.Do("RPUSH", rl.id, value)
	return err
}

// Get all elements of a list
func (rl *List) GetAll() ([]string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "0", "-1"))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Get the last element of a list
func (rl *List) GetLast() (string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "-1", "-1"))
	if len(result) == 1 {
		return getString(result, 0), err
	}
	return "", err
}

// Get the last N elements of a list
func (rl *List) GetLastN(n int) ([]string, error) {
	conn := rl.pool.Get(rl.dbindex)
	result, err := redis.Values(conn.Do("LRANGE", rl.id, "-"+strconv.Itoa(n), "-1"))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Remove this list
func (rl *List) Remove() error {
	conn := rl.pool.Get(rl.dbindex)
	_, err := conn.Do("DEL", rl.id)
	return err
}

/* --- Set functions --- */

// Create a new set
func NewSet(pool *ConnectionPool, id string) *Set {
	return &Set{pool, id, 0}
}

// Select a different database
func (rs *Set) SelectDatabase(dbindex int) {
	rs.dbindex = dbindex
}

// Add an element to the set
func (rs *Set) Add(value string) error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("SADD", rs.id, value)
	return err
}

// Check if a given value is in the set
func (rs *Set) Has(value string) (bool, error) {
	conn := rs.pool.Get(rs.dbindex)
	retval, err := conn.Do("SISMEMBER", rs.id, value)
	if err != nil {
		panic(err)
	}
	return redis.Bool(retval, err)
}

// Get all elements of the set
func (rs *Set) GetAll() ([]string, error) {
	conn := rs.pool.Get(rs.dbindex)
	result, err := redis.Values(conn.Do("SMEMBERS", rs.id))
	strs := make([]string, len(result))
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)
	}
	return strs, err
}

// Remove an element from the set
func (rs *Set) Del(value string) error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("SREM", rs.id, value)
	return err
}

// Remove this set
func (rs *Set) Remove() error {
	conn := rs.pool.Get(rs.dbindex)
	_, err := conn.Do("DEL", rs.id)
	return err
}

/* --- HashMap functions --- */

// Create a new hashmap
func NewHashMap(pool *ConnectionPool, id string) *HashMap {
	return &HashMap{pool, id, 0}
}

// Select a different database
func (rh *HashMap) SelectDatabase(dbindex int) {
	rh.dbindex = dbindex
}

// Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (rh *HashMap) Set(elementid, key, value string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("HSET", rh.id+":"+elementid, key, value)
	return err
}

// Get a value from a hashmap given the element id (for instance a user id) and the key (for instance "password")
func (rh *HashMap) Get(elementid, key string) (string, error) {
	conn := rh.pool.Get(rh.dbindex)
	result, err := redis.String(conn.Do("HGET", rh.id+":"+elementid, key))
	if err != nil {
		return "", err
	}
	return result, nil
}

// Check if a given elementid + key is in the hash map
func (rh *HashMap) Has(elementid, key string) (bool, error) {
	conn := rh.pool.Get(rh.dbindex)
	retval, err := conn.Do("HEXISTS", rh.id+":"+elementid, key)
	if err != nil {
		panic(err)
	}
	return redis.Bool(retval, err)
}

// Check if a given elementid exists as a hash map at all
func (rh *HashMap) Exists(elementid string) (bool, error) {
	// TODO: key is not meant to be a wildcard, check for "*"
	return hasKey(rh.pool, rh.id+":"+elementid, rh.dbindex)
}

// Get all elementid's for all hash elements
func (rh *HashMap) GetAll() ([]string, error) {
	conn := rh.pool.Get(rh.dbindex)
	result, err := redis.Values(conn.Do("KEYS", rh.id+":*"))
	strs := make([]string, len(result))
	idlen := len(rh.id)
	for i := 0; i < len(result); i++ {
		strs[i] = getString(result, i)[idlen+1:]
	}
	return strs, err
}

// Remove a key for an entry in a hashmap (for instance the email field for a user)
func (rh *HashMap) DelKey(elementid, key string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("HDEL", rh.id+":"+elementid, key)
	return err
}

// Remove an element (for instance a user)
func (rh *HashMap) Del(elementid string) error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("DEL", rh.id+":"+elementid)
	return err
}

// Remove this hashmap
func (rh *HashMap) Remove() error {
	conn := rh.pool.Get(rh.dbindex)
	_, err := conn.Do("DEL", rh.id)
	return err
}

/* --- KeyValue functions --- */

// Create a new key/value
func NewKeyValue(pool *ConnectionPool, id string) *KeyValue {
	return &KeyValue{pool, id, 0}
}

// Select a different database
func (rkv *KeyValue) SelectDatabase(dbindex int) {
	rkv.dbindex = dbindex
}

// Set a key and value
func (rkv *KeyValue) Set(key, value string) error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("SET", rkv.id+":"+key, value)
	return err
}

// Get a value given a key
func (rkv *KeyValue) Get(key string) (string, error) {
	conn := rkv.pool.Get(rkv.dbindex)
	result, err := redis.String(conn.Do("GET", rkv.id+":"+key))
	if err != nil {
		return "", err
	}
	return result, nil
}

// Remove a key
func (rkv *KeyValue) Del(key string) error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("DEL", rkv.id+":"+key)
	return err
}

// Remove this key/value
func (rkv *KeyValue) Remove() error {
	conn := rkv.pool.Get(rkv.dbindex)
	_, err := conn.Do("DEL", rkv.id)
	return err
}

// --- Generic redis functions ---

// Check if a key exists. The key can be a wildcard (ie. "user*").
func hasKey(pool *ConnectionPool, wildcard string, dbindex int) (bool, error) {
	conn := pool.Get(dbindex)
	result, err := redis.Values(conn.Do("KEYS", wildcard))
	if err != nil {
		return false, err
	}
	return len(result) > 0, nil
}
<|endoftext|>


<commit_before>package cli

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
)

type generateFlag struct {
	Usage string
}

func (f generateFlag) String() string {
	return fmt.Sprintf("--generate, -g\t%v", f.Usage)
}

func (f generateFlag) Apply(set *flag.FlagSet) {
	set.Bool("g", false, f.Usage)
	set.Bool("generate", false, f.Usage)
}

func generateNewTask() (fileName string, err error) {
	sourceDir, err := os.Getwd()
	if err != nil {
		return
	}

	pkgName := filepath.Base(sourceDir)
	fileName = fmt.Sprintf("%s_task.go", pkgName)
  outfile := filepath.Join(sourceDir, fileName)
	f, err := os.Create(outfile)
	if err != nil {
		return
	}
	defer f.Close()

	w := exampleWriter{Pkg: pkgName}
	err = w.Write(f)

	return
}
<commit_msg>go fmt<commit_after>package cli

import (
	"flag"
	"fmt"
	"os"
	"path/filepath"
)

type generateFlag struct {
	Usage string
}

func (f generateFlag) String() string {
	return fmt.Sprintf("--generate, -g\t%v", f.Usage)
}

func (f generateFlag) Apply(set *flag.FlagSet) {
	set.Bool("g", false, f.Usage)
	set.Bool("generate", false, f.Usage)
}

func generateNewTask() (fileName string, err error) {
	sourceDir, err := os.Getwd()
	if err != nil {
		return
	}

	pkgName := filepath.Base(sourceDir)
	fileName = fmt.Sprintf("%s_task.go", pkgName)
	outfile := filepath.Join(sourceDir, fileName)
	f, err := os.Create(outfile)
	if err != nil {
		return
	}
	defer f.Close()

	w := exampleWriter{Pkg: pkgName}
	err = w.Write(f)

	return
}
<|endoftext|>


<commit_before>package interaction

import (
	"errors"
	"fmt"

	"github.com/skygeario/skygear-server/pkg/auth/dependency/identity"
	"github.com/skygeario/skygear-server/pkg/core/authn"
	"github.com/skygeario/skygear-server/pkg/core/skyerr"
)

func (p *Provider) PerformAction(i *Interaction, step Step, action Action) error {
	state, err := p.GetInteractionState(i)
	if err != nil {
		return err
	}

	var stepState *StepState
	for _, s := range state.Steps {
		if s.Step == step {
			stepState = &s
			break
		}
	}
	if stepState == nil {
		return ErrInvalidStep
	}

	switch intent := i.Intent.(type) {
	case *IntentLogin:
		return p.performActionLogin(i, intent, stepState, state, action)
	case *IntentSignup:
		return p.performActionSignup(i, intent, stepState, state, action)
	}
	panic(fmt.Sprintf("interaction: unknown intent type %T", i.Intent))
}

func (p *Provider) performActionLogin(i *Interaction, intent *IntentLogin, step *StepState, s *State, action Action) error {
	switch step.Step {
	case StepAuthenticatePrimary, StepAuthenticateSecondary:
		switch action := action.(type) {
		case *ActionAuthenticate:
			authen, err := p.doAuthenticate(i, step, &i.State, intent.Identity, action.Authenticator, action.Secret)
			if skyerr.IsAPIError(err) {
				i.Error = skyerr.AsAPIError(err)
				return nil
			} else if err != nil {
				return err
			}

			ar := authen.ToRef()
			if step.Step == StepAuthenticatePrimary {
				i.PrimaryAuthenticator = &ar
				i.SecondaryAuthenticator = nil
			} else {
				i.SecondaryAuthenticator = &ar
			}
			i.Error = nil
			return nil

		case *ActionTriggerOOBAuthenticator:
			err := p.doTriggerOOB(i, action)
			if err != nil {
				return err
			}
			return nil
		default:
			panic(fmt.Sprintf("interaction_login: unhandled authenticate action %T", action))
		}

	case StepSetupSecondaryAuthenticator:
		// TODO(interaction): setup secondary authenticator

	case StepCommit:
		// TODO(interaction): allow setup bearer token

	}
	panic("interaction_login: unhandled step " + step.Step)
}

func (p *Provider) performActionSignup(i *Interaction, intent *IntentSignup, step *StepState, s *State, action Action) error {
	switch step.Step {
	case StepSetupPrimaryAuthenticator:
		switch action := action.(type) {
		case *ActionSetupAuthenticator:
			authen, err := p.setupAuthenticator(i, step, &i.State, action.Authenticator, action.Secret)
			if skyerr.IsAPIError(err) {
				i.Error = skyerr.AsAPIError(err)
				return nil
			} else if err != nil {
				return err
			}

			ar := authen.ToRef()
			i.PrimaryAuthenticator = &ar
			i.Error = nil
			return nil

		case *ActionTriggerOOBAuthenticator:
			err := p.doTriggerOOB(i, action)
			if err != nil {
				return err
			}
			return nil
		default:
			panic(fmt.Sprintf("interaction_signup: unhandled authenticate action %T", action))
		}

	}
	panic("interaction_signup: unhandled step " + step.Step)
}

func (p *Provider) doAuthenticate(i *Interaction, step *StepState, astate *map[string]string, is IdentitySpec, as AuthenticatorSpec, secret string) (*AuthenticatorInfo, error) {
	userID, iden, err := p.Identity.GetByClaims(is.Type, is.Claims)
	if errors.Is(err, identity.ErrIdentityNotFound) {
		return nil, ErrInvalidCredentials
	} else if err != nil {
		return nil, err
	}

	authen, err := p.Authenticator.Authenticate(userID, as, astate, secret)
	if err != nil {
		return nil, err
	}

	i.UserID = userID
	ir := iden.ToRef()
	i.Identity = &ir
	i.State = nil
	return authen, nil
}

func (p *Provider) setupAuthenticator(i *Interaction, step *StepState, astate *map[string]string, as AuthenticatorSpec, secret string) (*AuthenticatorInfo, error) {
	ok := false
	for _, aa := range step.AvailableAuthenticators {
		if aa.Type == as.Type {
			ok = true
			break
		}
	}
	if !ok {
		// Authenticator is not available for current step, reject it
		return nil, ErrInvalidAction
	}

	switch as.Type {
	case authn.AuthenticatorTypePassword:
		// Nothing special needs to be done
		break
	case authn.AuthenticatorTypeOOB:
		_, err := p.Authenticator.Authenticate( /* userID */ "", as, astate, secret)
		if err != nil {
			return nil, err
		}
	default:
		panic("interaction_signup: setup up unexpected authenticator type: " + as.Type)
	}

	ais, err := p.Authenticator.New(i.UserID, as, secret)
	if err != nil {
		return nil, err
	}
	i.NewAuthenticators = append(i.NewAuthenticators, ais...)
	i.State = nil
	return ais[0], nil
}

func (p *Provider) doTriggerOOB(i *Interaction, action *ActionTriggerOOBAuthenticator) (err error) {
	spec := action.Authenticator

	if spec.Type != authn.AuthenticatorTypeOOB {
		panic("interaction: unexpected ActionTriggerOOBAuthenticator.Authenticator.Type: " + spec.Type)
	}

	now := p.Time.NowUTC()
	triggerTime, err := now.MarshalText()
	if err != nil {
		return
	}

	if i.State == nil {
		i.State = map[string]string{}
	}

	// Check if we have a code already.
	// The code remains unchanged through out the entire interaction once it was generated.
	// Therefore it expires when the interaction expires.
	code := i.State[AuthenticatorStateOOBOTPCode]
	if code == "" {
		code = p.OOB.GenerateCode()
	}

	err = p.OOB.SendCode(spec, code)
	if err != nil {
		return
	}

	// Perform mutation on interaction at the end.

	// This function can be called by login or signup.
	// In case of signup, the spec does not have an ID yet.
	if id, ok := spec.Props[AuthenticatorPropOOBOTPID].(string); ok {
		i.State[AuthenticatorStateOOBOTPID] = id
	}
	i.State[AuthenticatorStateOOBOTPCode] = code
	i.State[AuthenticatorStateOOBOTPTriggerTime] = string(triggerTime)

	return
}
<commit_msg>Pass Interaction.UserID<commit_after>package interaction

import (
	"errors"
	"fmt"

	"github.com/skygeario/skygear-server/pkg/auth/dependency/identity"
	"github.com/skygeario/skygear-server/pkg/core/authn"
	"github.com/skygeario/skygear-server/pkg/core/skyerr"
)

func (p *Provider) PerformAction(i *Interaction, step Step, action Action) error {
	state, err := p.GetInteractionState(i)
	if err != nil {
		return err
	}

	var stepState *StepState
	for _, s := range state.Steps {
		if s.Step == step {
			stepState = &s
			break
		}
	}
	if stepState == nil {
		return ErrInvalidStep
	}

	switch intent := i.Intent.(type) {
	case *IntentLogin:
		return p.performActionLogin(i, intent, stepState, state, action)
	case *IntentSignup:
		return p.performActionSignup(i, intent, stepState, state, action)
	}
	panic(fmt.Sprintf("interaction: unknown intent type %T", i.Intent))
}

func (p *Provider) performActionLogin(i *Interaction, intent *IntentLogin, step *StepState, s *State, action Action) error {
	switch step.Step {
	case StepAuthenticatePrimary, StepAuthenticateSecondary:
		switch action := action.(type) {
		case *ActionAuthenticate:
			authen, err := p.doAuthenticate(i, step, &i.State, intent.Identity, action.Authenticator, action.Secret)
			if skyerr.IsAPIError(err) {
				i.Error = skyerr.AsAPIError(err)
				return nil
			} else if err != nil {
				return err
			}

			ar := authen.ToRef()
			if step.Step == StepAuthenticatePrimary {
				i.PrimaryAuthenticator = &ar
				i.SecondaryAuthenticator = nil
			} else {
				i.SecondaryAuthenticator = &ar
			}
			i.Error = nil
			return nil

		case *ActionTriggerOOBAuthenticator:
			err := p.doTriggerOOB(i, action)
			if err != nil {
				return err
			}
			return nil
		default:
			panic(fmt.Sprintf("interaction_login: unhandled authenticate action %T", action))
		}

	case StepSetupSecondaryAuthenticator:
		// TODO(interaction): setup secondary authenticator

	case StepCommit:
		// TODO(interaction): allow setup bearer token

	}
	panic("interaction_login: unhandled step " + step.Step)
}

func (p *Provider) performActionSignup(i *Interaction, intent *IntentSignup, step *StepState, s *State, action Action) error {
	switch step.Step {
	case StepSetupPrimaryAuthenticator:
		switch action := action.(type) {
		case *ActionSetupAuthenticator:
			authen, err := p.setupAuthenticator(i, step, &i.State, action.Authenticator, action.Secret)
			if skyerr.IsAPIError(err) {
				i.Error = skyerr.AsAPIError(err)
				return nil
			} else if err != nil {
				return err
			}

			ar := authen.ToRef()
			i.PrimaryAuthenticator = &ar
			i.Error = nil
			return nil

		case *ActionTriggerOOBAuthenticator:
			err := p.doTriggerOOB(i, action)
			if err != nil {
				return err
			}
			return nil
		default:
			panic(fmt.Sprintf("interaction_signup: unhandled authenticate action %T", action))
		}

	}
	panic("interaction_signup: unhandled step " + step.Step)
}

func (p *Provider) doAuthenticate(i *Interaction, step *StepState, astate *map[string]string, is IdentitySpec, as AuthenticatorSpec, secret string) (*AuthenticatorInfo, error) {
	userID, iden, err := p.Identity.GetByClaims(is.Type, is.Claims)
	if errors.Is(err, identity.ErrIdentityNotFound) {
		return nil, ErrInvalidCredentials
	} else if err != nil {
		return nil, err
	}

	authen, err := p.Authenticator.Authenticate(userID, as, astate, secret)
	if err != nil {
		return nil, err
	}

	i.UserID = userID
	ir := iden.ToRef()
	i.Identity = &ir
	i.State = nil
	return authen, nil
}

func (p *Provider) setupAuthenticator(i *Interaction, step *StepState, astate *map[string]string, as AuthenticatorSpec, secret string) (*AuthenticatorInfo, error) {
	ok := false
	for _, aa := range step.AvailableAuthenticators {
		if aa.Type == as.Type {
			ok = true
			break
		}
	}
	if !ok {
		// Authenticator is not available for current step, reject it
		return nil, ErrInvalidAction
	}

	switch as.Type {
	case authn.AuthenticatorTypePassword:
		// Nothing special needs to be done
		break
	case authn.AuthenticatorTypeOOB:
		// Ignoring the first return value because it is always nil.
		_, err := p.Authenticator.Authenticate(i.UserID, as, astate, secret)
		if err != nil {
			return nil, err
		}
	default:
		panic("interaction_signup: setup up unexpected authenticator type: " + as.Type)
	}

	ais, err := p.Authenticator.New(i.UserID, as, secret)
	if err != nil {
		return nil, err
	}
	i.NewAuthenticators = append(i.NewAuthenticators, ais...)
	i.State = nil
	return ais[0], nil
}

func (p *Provider) doTriggerOOB(i *Interaction, action *ActionTriggerOOBAuthenticator) (err error) {
	spec := action.Authenticator

	if spec.Type != authn.AuthenticatorTypeOOB {
		panic("interaction: unexpected ActionTriggerOOBAuthenticator.Authenticator.Type: " + spec.Type)
	}

	now := p.Time.NowUTC()
	triggerTime, err := now.MarshalText()
	if err != nil {
		return
	}

	if i.State == nil {
		i.State = map[string]string{}
	}

	// Check if we have a code already.
	// The code remains unchanged through out the entire interaction once it was generated.
	// Therefore it expires when the interaction expires.
	code := i.State[AuthenticatorStateOOBOTPCode]
	if code == "" {
		code = p.OOB.GenerateCode()
	}

	err = p.OOB.SendCode(spec, code)
	if err != nil {
		return
	}

	// Perform mutation on interaction at the end.

	// This function can be called by login or signup.
	// In case of signup, the spec does not have an ID yet.
	if id, ok := spec.Props[AuthenticatorPropOOBOTPID].(string); ok {
		i.State[AuthenticatorStateOOBOTPID] = id
	}
	i.State[AuthenticatorStateOOBOTPCode] = code
	i.State[AuthenticatorStateOOBOTPTriggerTime] = string(triggerTime)

	return
}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"

	sm "github.com/Ariemeth/frame-assault-2/engine/shaderManager"
	tm "github.com/Ariemeth/frame-assault-2/engine/textureManager"
	"github.com/go-gl/gl/v4.1-core/gl"
	"github.com/go-gl/mathgl/mgl32"
)

//Model represents a physical entity
type Model struct {
	Entity
	vertices          []float32
	indices           []uint32
	shaders           sm.ShaderManager
	textures          tm.TextureManager
	angle             float64
	model             mgl32.Mat4
	camera            mgl32.Mat4
	projection        mgl32.Mat4
	modelUniform      int32
	projectionUniform int32
	cameraUniform     int32
	textureUniform    int32
	vao               uint32
	currentProgram    uint32
	currentTexture    uint32
}

//NewModel creates a new model
func NewModel(id string, shaders sm.ShaderManager, textures tm.TextureManager, shader string) *Model {
	m := Model{
		Entity:     NewEntity(id),
		shaders:    shaders,
		textures:   textures,
		angle:      0.0,
		model:      mgl32.Ident4(),
		camera:     mgl32.Ident4(),
		projection: mgl32.Ident4(),
		vertices:   iHexVerts,
		indices:   hexIndices,
	}

	program, status := shaders.GetShader(shader)
	if status {
		m.currentProgram = program
	} else {
		fmt.Println("unable to load program ", shader, ": ", program)
	}
	return &m
}

//Update updates the model
func (m *Model) Update(elapsed float64) {
	m.angle += elapsed
	m.model = mgl32.HomogRotate3D(float32(m.angle), mgl32.Vec3{0, 1, 0})
}

//Render renders the model
func (m *Model) Render() {

	gl.UseProgram(m.currentProgram)
	gl.UniformMatrix4fv(m.modelUniform, 1, false, &m.model[0])

	gl.BindVertexArray(m.vao)

	gl.ActiveTexture(gl.TEXTURE0)
	/* currently disabling the texture load
		texture, isLoaded := m.textures.GetTexture("square")

		if isLoaded {
			gl.BindTexture(gl.TEXTURE_2D, texture)
		} else {
			fmt.Println("Unable to load texture")
		}
	*/
	if m.indices != nil{
		gl.DrawElements(gl.TRIANGLE_FAN, int32(len(m.indices)), gl.UNSIGNED_INT, nil)
	} else {
		gl.DrawArrays(gl.TRIANGLES, 0, int32(len(m.vertices))/5)
	}

	gl.BindVertexArray(0)
}

//Load loads and sets up the model
func (m *Model) Load(isIndexed bool) {
	gl.UseProgram(m.currentProgram)

	m.projection = mgl32.Perspective(mgl32.DegToRad(45.0), float32(windowWidth)/windowHeight, 0.1, 10.0)
	m.projectionUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("projection\x00"))
	gl.UniformMatrix4fv(m.projectionUniform, 1, false, &m.projection[0])

	m.camera = mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
	m.cameraUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("camera\x00"))
	gl.UniformMatrix4fv(m.cameraUniform, 1, false, &m.camera[0])

	m.modelUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("model\x00"))
	gl.UniformMatrix4fv(m.modelUniform, 1, false, &m.model[0])

	m.textureUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("tex\x00"))
	gl.Uniform1i(m.textureUniform, 0)

	gl.BindFragDataLocation(m.currentProgram, 0, gl.Str("outputColor\x00"))

	// Load the texture
	//	m.textures.LoadTexture("assets/textures/square.png", "square")

	// Configure the vertex data
	gl.GenVertexArrays(1, &m.vao)
	gl.BindVertexArray(m.vao)

	var vbo uint32
	gl.GenBuffers(1, &vbo)
	fmt.Println(vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, len(m.vertices)*4, gl.Ptr(m.vertices), gl.STATIC_DRAW)

	if isIndexed {
		var indices uint32
		gl.GenBuffers(1, &indices)
		gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices)
		gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(m.indices)*4, gl.Ptr(m.indices), gl.STATIC_DRAW)
	}

	vertAttrib := uint32(gl.GetAttribLocation(m.currentProgram, gl.Str("vert\x00")))
	gl.EnableVertexAttribArray(vertAttrib)
	gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 3*4, gl.PtrOffset(0)) //5:number of values per vertex, 4:number of bytes in a float32

	texCoordAttrib := uint32(gl.GetAttribLocation(m.currentProgram, gl.Str("vertTexCoord\x00")))
	gl.EnableVertexAttribArray(texCoordAttrib)
	gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 3*4, gl.PtrOffset(3*4)) //5:number of values per vertex, 4:number of bytes in a float32

	gl.BindVertexArray(0)
}

var cubeVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	-1.0, -1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,

	// Top
	-1.0, 1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, 1.0, 1.0, 1.0,

	// Front
	-1.0, -1.0, 1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,

	// Back
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 1.0,

	// Left
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,

	// Right
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
}

type point struct {
	X float32
	Y float32
	Z float32
	T float32
	U float32
}

var (
	Center = point{0.0, 0.0, 0.0, 0.0, 0.0}
	P1     = point{0.0, 1.0, 0.0, 0.0, 0.0}
	P2     = point{-1.0, 0.5, 0.0, 0.0, 0.0}
	P3     = point{-1.0, -0.5, 0.0, 0.0, 0.0}
	P4     = point{0.0, -1.0, 0.0, 0.0, 0.0}
	P5     = point{1.0, -0.5, 0.0, 0.0, 0.0}
	P6     = point{1.0, 0.5, 0.0, 0.0, 0.0}
)

var iHexVerts = []float32{
	// X, Y, Z
	// Top
	Center.X, Center.Y, Center.Z,
	P1.X, P1.Y, P1.Z,
	P2.X, P2.Y, P2.Z,
	P3.X, P3.Y, P3.Z,
	P4.X, P4.Y, P4.Z,
	P5.X, P5.Y, P5.Z,
	P6.X, P6.Y, P6.Z,
}

var hexIndices = []uint32{
	0, 1, 2, 3, 4, 5, 6, 1,
}

/*
var hexVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P1.X, P1.Y, P1.Z, P1.T, P1.U,
	P2.X, P2.Y, P2.Z, P2.T, P2.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P2.X, P2.Y, P2.Z, P2.T, P2.U,
	P3.X, P3.Y, P3.Z, P3.T, P3.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P3.X, P3.Y, P3.Z, P3.T, P3.U,
	P4.X, P4.Y, P4.Z, P4.T, P4.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P4.X, P4.Y, P4.Z, P4.T, P4.U,
	P5.X, P5.Y, P5.Z, P5.T, P5.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P5.X, P5.Y, P5.Z, P5.T, P5.U,
	P6.X, P6.Y, P6.Z, P6.T, P6.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P6.X, P6.Y, P6.Z, P6.T, P6.U,
	P1.X, P1.Y, P1.Z, P1.T, P1.U,

	// Top

	// Front

	// Back

	// Left

	// Right

}
*/
<commit_msg>formated code<commit_after>package engine

import (
	"fmt"

	sm "github.com/Ariemeth/frame-assault-2/engine/shaderManager"
	tm "github.com/Ariemeth/frame-assault-2/engine/textureManager"
	"github.com/go-gl/gl/v4.1-core/gl"
	"github.com/go-gl/mathgl/mgl32"
)

//Model represents a physical entity
type Model struct {
	Entity
	vertices          []float32
	indices           []uint32
	shaders           sm.ShaderManager
	textures          tm.TextureManager
	angle             float64
	model             mgl32.Mat4
	camera            mgl32.Mat4
	projection        mgl32.Mat4
	modelUniform      int32
	projectionUniform int32
	cameraUniform     int32
	textureUniform    int32
	vao               uint32
	currentProgram    uint32
	currentTexture    uint32
}

//NewModel creates a new model
func NewModel(id string, shaders sm.ShaderManager, textures tm.TextureManager, shader string) *Model {
	m := Model{
		Entity:     NewEntity(id),
		shaders:    shaders,
		textures:   textures,
		angle:      0.0,
		model:      mgl32.Ident4(),
		camera:     mgl32.Ident4(),
		projection: mgl32.Ident4(),
		vertices:   iHexVerts,
		indices:    hexIndices,
	}

	program, status := shaders.GetShader(shader)
	if status {
		m.currentProgram = program
	} else {
		fmt.Println("unable to load program ", shader, ": ", program)
	}
	return &m
}

//Update updates the model
func (m *Model) Update(elapsed float64) {
	m.angle += elapsed
	m.model = mgl32.HomogRotate3D(float32(m.angle), mgl32.Vec3{0, 1, 0})
}

//Render renders the model
func (m *Model) Render() {

	gl.UseProgram(m.currentProgram)
	gl.UniformMatrix4fv(m.modelUniform, 1, false, &m.model[0])

	gl.BindVertexArray(m.vao)

	gl.ActiveTexture(gl.TEXTURE0)
	/* currently disabling the texture load
	texture, isLoaded := m.textures.GetTexture("square")

	if isLoaded {
		gl.BindTexture(gl.TEXTURE_2D, texture)
	} else {
		fmt.Println("Unable to load texture")
	}
	*/
	if m.indices != nil {
		gl.DrawElements(gl.TRIANGLE_FAN, int32(len(m.indices)), gl.UNSIGNED_INT, nil)
	} else {
		gl.DrawArrays(gl.TRIANGLES, 0, int32(len(m.vertices))/5)
	}

	gl.BindVertexArray(0)
}

//Load loads and sets up the model
func (m *Model) Load(isIndexed bool) {
	gl.UseProgram(m.currentProgram)

	m.projection = mgl32.Perspective(mgl32.DegToRad(45.0), float32(windowWidth)/windowHeight, 0.1, 10.0)
	m.projectionUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("projection\x00"))
	gl.UniformMatrix4fv(m.projectionUniform, 1, false, &m.projection[0])

	m.camera = mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
	m.cameraUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("camera\x00"))
	gl.UniformMatrix4fv(m.cameraUniform, 1, false, &m.camera[0])

	m.modelUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("model\x00"))
	gl.UniformMatrix4fv(m.modelUniform, 1, false, &m.model[0])

	m.textureUniform = gl.GetUniformLocation(m.currentProgram, gl.Str("tex\x00"))
	gl.Uniform1i(m.textureUniform, 0)

	gl.BindFragDataLocation(m.currentProgram, 0, gl.Str("outputColor\x00"))

	// Load the texture
	//	m.textures.LoadTexture("assets/textures/square.png", "square")

	// Configure the vertex data
	gl.GenVertexArrays(1, &m.vao)
	gl.BindVertexArray(m.vao)

	var vbo uint32
	gl.GenBuffers(1, &vbo)
	fmt.Println(vbo)
	gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
	gl.BufferData(gl.ARRAY_BUFFER, len(m.vertices)*4, gl.Ptr(m.vertices), gl.STATIC_DRAW)

	if isIndexed {
		var indices uint32
		gl.GenBuffers(1, &indices)
		gl.BindBuffer(gl.ELEMENT_ARRAY_BUFFER, indices)
		gl.BufferData(gl.ELEMENT_ARRAY_BUFFER, len(m.indices)*4, gl.Ptr(m.indices), gl.STATIC_DRAW)
	}

	vertAttrib := uint32(gl.GetAttribLocation(m.currentProgram, gl.Str("vert\x00")))
	gl.EnableVertexAttribArray(vertAttrib)
	gl.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 3*4, gl.PtrOffset(0)) //5:number of values per vertex, 4:number of bytes in a float32

	texCoordAttrib := uint32(gl.GetAttribLocation(m.currentProgram, gl.Str("vertTexCoord\x00")))
	gl.EnableVertexAttribArray(texCoordAttrib)
	gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 3*4, gl.PtrOffset(3*4)) //5:number of values per vertex, 4:number of bytes in a float32

	gl.BindVertexArray(0)
}

var cubeVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	-1.0, -1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,

	// Top
	-1.0, 1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, 1.0, 0.0, 1.0,
	1.0, 1.0, 1.0, 1.0, 1.0,

	// Front
	-1.0, -1.0, 1.0, 1.0, 0.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, 1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,

	// Back
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	-1.0, 1.0, -1.0, 0.0, 1.0,
	1.0, 1.0, -1.0, 1.0, 1.0,

	// Left
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,
	-1.0, -1.0, -1.0, 0.0, 0.0,
	-1.0, -1.0, 1.0, 0.0, 1.0,
	-1.0, 1.0, 1.0, 1.0, 1.0,
	-1.0, 1.0, -1.0, 1.0, 0.0,

	// Right
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, -1.0, -1.0, 1.0, 0.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, -1.0, 1.0, 1.0, 1.0,
	1.0, 1.0, -1.0, 0.0, 0.0,
	1.0, 1.0, 1.0, 0.0, 1.0,
}

type point struct {
	X float32
	Y float32
	Z float32
	T float32
	U float32
}

var (
	Center = point{0.0, 0.0, 0.0, 0.0, 0.0}
	P1     = point{0.0, 1.0, 0.0, 0.0, 0.0}
	P2     = point{-1.0, 0.5, 0.0, 0.0, 0.0}
	P3     = point{-1.0, -0.5, 0.0, 0.0, 0.0}
	P4     = point{0.0, -1.0, 0.0, 0.0, 0.0}
	P5     = point{1.0, -0.5, 0.0, 0.0, 0.0}
	P6     = point{1.0, 0.5, 0.0, 0.0, 0.0}
)

var iHexVerts = []float32{
	// X, Y, Z
	// Top
	Center.X, Center.Y, Center.Z,
	P1.X, P1.Y, P1.Z,
	P2.X, P2.Y, P2.Z,
	P3.X, P3.Y, P3.Z,
	P4.X, P4.Y, P4.Z,
	P5.X, P5.Y, P5.Z,
	P6.X, P6.Y, P6.Z,
}

var hexIndices = []uint32{
	0, 1, 2, 3, 4, 5, 6, 1,
}

var hexVertices = []float32{
	//  X, Y, Z, U, V
	// Bottom
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P1.X, P1.Y, P1.Z, P1.T, P1.U,
	P2.X, P2.Y, P2.Z, P2.T, P2.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P2.X, P2.Y, P2.Z, P2.T, P2.U,
	P3.X, P3.Y, P3.Z, P3.T, P3.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P3.X, P3.Y, P3.Z, P3.T, P3.U,
	P4.X, P4.Y, P4.Z, P4.T, P4.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P4.X, P4.Y, P4.Z, P4.T, P4.U,
	P5.X, P5.Y, P5.Z, P5.T, P5.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P5.X, P5.Y, P5.Z, P5.T, P5.U,
	P6.X, P6.Y, P6.Z, P6.T, P6.U,
	Center.X, Center.Y, Center.Z, Center.T, Center.U,
	P6.X, P6.Y, P6.Z, P6.T, P6.U,
	P1.X, P1.Y, P1.Z, P1.T, P1.U,

	// Top

	// Front

	// Back

	// Left

	// Right

}
<|endoftext|>


<commit_before>package engine

import (
	"fmt"
	"strconv"
	"time"

	"github.com/mijia/adoc"
	"github.com/mijia/go-generics"
)

const (
	kLainDeploydRootKey = "/lain/deployd"
	kLainConstraintKey  = "constraints"
	kLainNotifyKey      = "notifies"
	kLainPodGroupKey    = "pod_groups"
	kLainDependencyKey  = "depends"
	kLainSpecKey        = "specs"
	kLainPodKey         = "pods"
	kLainNodesKey       = "nodes"

	kLainVolumeRoot      = "/data/lain/volumes"
	kLainCloudVolumeRoot = "/data/lain/cloud-volumes"
	kLainLabelPrefix     = "cc.bdp.lain.deployd"

	MinPodSetupTime = 0
	MaxPodSetupTime = 300

	MinPodKillTimeout = 10
	MaxPodKillTimeout = 120
)

type ImSpec struct {
	Name      string
	Namespace string
	Version   int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ContainerLabel struct {
	Name           string
	Namespace      string
	InstanceNo     int
	Version        int
	DriftCount     int
	ContainerIndex int
	Annotation     string
}

func (label ContainerLabel) NameAffinity() string {
	return fmt.Sprintf("affinity:%s.pg_name!=~%s", kLainLabelPrefix, label.Name)
}

func (label ContainerLabel) Label2Maps() map[string]string {
	labelMaps := make(map[string]string)
	labelMaps[kLainLabelPrefix+".pg_name"] = label.Name
	labelMaps[kLainLabelPrefix+".pg_namespace"] = label.Namespace
	labelMaps[kLainLabelPrefix+".instance_no"] = fmt.Sprintf("%d", label.InstanceNo)
	labelMaps[kLainLabelPrefix+".version"] = fmt.Sprintf("%d", label.Version)
	labelMaps[kLainLabelPrefix+".drift_count"] = fmt.Sprintf("%d", label.DriftCount)
	labelMaps[kLainLabelPrefix+".container_index"] = fmt.Sprintf("%d", label.ContainerIndex)
	labelMaps[kLainLabelPrefix+".annotation"] = label.Annotation
	return labelMaps
}

func (label *ContainerLabel) FromMaps(m map[string]string) bool {
	var err error
	hasError := false
	label.Name = m[kLainLabelPrefix+".pg_name"]
	hasError = hasError || label.Name == ""
	label.Namespace = m[kLainLabelPrefix+".pg_namespace"]
	label.InstanceNo, err = strconv.Atoi(m[kLainLabelPrefix+".instance_no"])
	hasError = hasError || err != nil
	label.Version, err = strconv.Atoi(m[kLainLabelPrefix+".version"])
	hasError = hasError || err != nil
	label.DriftCount, err = strconv.Atoi(m[kLainLabelPrefix+".drift_count"])
	hasError = hasError || err != nil
	label.ContainerIndex, err = strconv.Atoi(m[kLainLabelPrefix+".container_index"])
	hasError = hasError || err != nil
	label.Annotation = m[kLainLabelPrefix+".annotation"]
	return !hasError
}

const (
	CloudVolumeSingleMode = "single"
	CloudVolumeMultiMode  = "multi"
)

type CloudVolumeSpec struct {
	Type string
	Dirs []string
}

func (s CloudVolumeSpec) VerifyParams() bool {
	verify := s.Type == CloudVolumeMultiMode ||
		s.Type == CloudVolumeSingleMode

	return verify
}

func (s CloudVolumeSpec) Clone() CloudVolumeSpec {
	newSpec := s
	newSpec.Type = s.Type
	newSpec.Dirs = generics.Clone_StringSlice(s.Dirs)
	return newSpec
}

func (s CloudVolumeSpec) Equals(o CloudVolumeSpec) bool {
	return s.Type == o.Type &&
		generics.Equal_StringSlice(s.Dirs, o.Dirs)
}

type ContainerSpec struct {
	ImSpec
	Image         string
	Env           []string
	User          string
	WorkingDir    string
	DnsSearch     []string
	Volumes       []string // a stateful flag
	SystemVolumes []string // not a stateful flag, every node has system volumes
	CloudVolumes  []CloudVolumeSpec
	Command       []string
	Entrypoint    []string
	CpuLimit      int
	MemoryLimit   int64
	Expose        int
	LogConfig     adoc.LogConfig
}

func (s ContainerSpec) Clone() ContainerSpec {
	newSpec := s
	newSpec.Env = generics.Clone_StringSlice(s.Env)
	newSpec.Volumes = generics.Clone_StringSlice(s.Volumes)
	newSpec.SystemVolumes = generics.Clone_StringSlice(s.SystemVolumes)
	newSpec.Command = generics.Clone_StringSlice(s.Command)
	newSpec.DnsSearch = generics.Clone_StringSlice(s.DnsSearch)
	newSpec.Entrypoint = generics.Clone_StringSlice(s.Entrypoint)
	newSpec.LogConfig.Type = s.LogConfig.Type
	newSpec.LogConfig.Config = generics.Clone_StringStringMap(s.LogConfig.Config)
	for i := range s.CloudVolumes {
		newSpec.CloudVolumes[i] = s.CloudVolumes[i].Clone()
	}
	return newSpec
}

func (s ContainerSpec) VerifyParams() bool {
	verify := s.Image != "" &&
		s.CpuLimit >= 0 &&
		s.MemoryLimit >= 0 &&
		s.Expose >= 0
	if !verify {
		return false
	}
	for _, cvSpec := range s.CloudVolumes {
		if !cvSpec.VerifyParams() {
			return false
		}
	}
	return true
}

func (s ContainerSpec) Equals(o ContainerSpec) bool {
	return s.Name == o.Name &&
		s.Image == o.Image &&
		generics.Equal_StringSlice(s.Env, o.Env) &&
		generics.Equal_StringSlice(s.Command, o.Command) &&
		generics.Equal_StringSlice(s.DnsSearch, o.DnsSearch) &&
		s.CpuLimit == o.CpuLimit &&
		s.MemoryLimit == o.MemoryLimit &&
		s.Expose == o.Expose &&
		s.User == o.User &&
		s.WorkingDir == o.WorkingDir &&
		generics.Equal_StringSlice(s.Volumes, o.Volumes) &&
		generics.Equal_StringSlice(s.SystemVolumes, o.SystemVolumes) &&
		generics.Equal_StringSlice(s.Entrypoint, o.Entrypoint) &&
		s.LogConfig.Type == o.LogConfig.Type &&
		generics.Equal_StringStringMap(s.LogConfig.Config, o.LogConfig.Config)
}

func NewContainerSpec(image string) ContainerSpec {
	spec := ContainerSpec{
		Image: image,
	}
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	return spec
}

type DependencyPolicy int

const (
	DependencyNamespaceLevel = iota
	DependencyNodeLevel
)

type Dependency struct {
	PodName string
	Policy  DependencyPolicy
}

func (d Dependency) Clone() Dependency {
	return d
}

type PodPrevState struct {
	NodeName string
	IPs      []string
}

func NewPodPrevState(length int) PodPrevState {
	return PodPrevState{
		NodeName: "",
		IPs:      make([]string, length),
	}
}

func (pps PodPrevState) Clone() PodPrevState {
	newState := pps
	newState.IPs = make([]string, len(pps.IPs))
	copy(newState.IPs, pps.IPs)
	return newState
}

type PodSpec struct {
	ImSpec
	Network      string
	Containers   []ContainerSpec
	Filters      []string // for cluster scheduling
	Dependencies []Dependency
	Annotation   string
	Stateful     bool
	SetupTime    int
	KillTimeout  int
	PrevState    PodPrevState
}

func (s PodSpec) GetSetupTime() int {
	if s.SetupTime < MinPodSetupTime {
		return MinPodSetupTime
	} else if s.SetupTime > MaxPodSetupTime {
		return MaxPodSetupTime
	}
	return s.SetupTime
}

func (s PodSpec) GetKillTimeout() int {
	if s.KillTimeout < MinPodKillTimeout {
		return MinPodKillTimeout
	} else if s.KillTimeout > MaxPodKillTimeout {
		return MaxPodKillTimeout
	}
	return s.KillTimeout
}

func (s PodSpec) String() string {
	return fmt.Sprintf("Pod[name=%s, version=%d, depends=%+v, stateful=%v, #containers=%d]",
		s.Name, s.Version, s.Dependencies, s.Stateful, len(s.Containers))
}

func (s PodSpec) Clone() PodSpec {
	newSpec := s
	newSpec.Filters = generics.Clone_StringSlice(s.Filters)
	newSpec.Containers = make([]ContainerSpec, len(s.Containers))
	newSpec.PrevState = s.PrevState.Clone()
	for i := range s.Containers {
		newSpec.Containers[i] = s.Containers[i].Clone()
	}
	newSpec.Dependencies = make([]Dependency, len(s.Dependencies))
	for i := range s.Dependencies {
		newSpec.Dependencies[i] = s.Dependencies[i].Clone()
	}
	return newSpec
}

func (s PodSpec) VerifyParams() bool {
	verify := s.Name != "" && s.Namespace != "" &&
		len(s.Containers) > 0
	if !verify {
		return false
	}
	for _, cSpec := range s.Containers {
		if !cSpec.VerifyParams() {
			return false
		}
	}
	return true
}

func (s PodSpec) IsHardStateful() bool {
	return s.Stateful
}

func (s PodSpec) IsStateful() bool {
	return s.HasVolumes() || s.Stateful
}

func (s PodSpec) HasVolumes() bool {
	for _, container := range s.Containers {
		if len(container.Volumes) > 0 {
			return true
		}
	}
	return false
}

func (s PodSpec) Equals(o PodSpec) bool {
	if len(s.Containers) != len(o.Containers) {
		return false
	}
	for i := range s.Containers {
		if !s.Containers[i].Equals(o.Containers[i]) {
			return false
		}
	}
	if len(s.Dependencies) != len(o.Dependencies) {
		return false
	}
	for i := range s.Dependencies {
		if s.Dependencies[i] != o.Dependencies[i] {
			return false
		}
	}
	return s.Name == o.Name &&
		s.Namespace == o.Namespace &&
		s.Version == o.Version &&
		s.Annotation == o.Annotation &&
		s.Stateful == o.Stateful &&
		generics.Equal_StringSlice(s.Filters, o.Filters)
}

func (s PodSpec) Merge(o PodSpec) PodSpec {
	s.Containers = o.Containers
	s.Dependencies = o.Dependencies
	s.Filters = o.Filters
	s.Annotation = o.Annotation
	s.Stateful = o.Stateful
	s.Version += 1
	s.UpdatedAt = time.Now()
	s.PrevState = o.PrevState
	return s
}

func NewPodSpec(containerSpec ContainerSpec, otherSpecs ...ContainerSpec) PodSpec {
	cSpecs := make([]ContainerSpec, 1+len(otherSpecs))
	cSpecs[0] = containerSpec
	for i, cs := range otherSpecs {
		cSpecs[i+1] = cs
	}
	spec := PodSpec{
		Containers: cSpecs,
		PrevState:  NewPodPrevState(len(otherSpecs) + 1),
	}
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	return spec
}

type RestartPolicy int

const (
	RestartPolicyNever = iota
	RestartPolicyAlways
	RestartPolicyOnFail
)

func (rp RestartPolicy) String() string {
	switch rp {
	case RestartPolicyNever:
		return "RestartPolicyNever"
	case RestartPolicyAlways:
		return "RestartPolicyAlways"
	case RestartPolicyOnFail:
		return "RestartPolicyOnFail"
	default:
		return "Unknown RestartPolicy"
	}
}

type PodGroupPrevState struct {
	Nodes []string
	// we think a instance only have one ip, as now a instance only have one container.
	IPs []string
}

func (pgps PodGroupPrevState) Clone() PodGroupPrevState {
	newState := PodGroupPrevState{
		Nodes: make([]string, len(pgps.Nodes)),
		IPs:   make([]string, len(pgps.Nodes)),
	}
	copy(newState.Nodes, pgps.Nodes)
	copy(newState.IPs, pgps.IPs)
	return newState
}

func (pgps PodGroupPrevState) Reset(instanceNo int) PodGroupPrevState {
	newState := PodGroupPrevState{
		Nodes: make([]string, instanceNo),
		IPs:   make([]string, instanceNo),
	}
	copy(newState.Nodes, pgps.Nodes)
	copy(newState.IPs, pgps.IPs)
	return newState
}

func (pgps PodGroupPrevState) Length() int {
	if pgps.Nodes == nil {
		return 0
	}
	return len(pgps.Nodes)
}

type PodGroupSpec struct {
	ImSpec
	Pod           PodSpec
	NumInstances  int
	RestartPolicy RestartPolicy
}

func (spec PodGroupSpec) String() string {
	return fmt.Sprintf("PodGroup[name=%s, version=%d, #instances=%d, restart=%s]",
		spec.Name, spec.Version, spec.NumInstances, spec.RestartPolicy)
}

func (spec PodGroupSpec) Clone() PodGroupSpec {
	newSpec := spec
	newSpec.Pod = spec.Pod.Clone()
	return newSpec
}

func (spec PodGroupSpec) Equals(o PodGroupSpec) bool {
	return spec.Name == o.Name &&
		spec.Namespace == o.Namespace &&
		spec.Version == o.Version &&
		spec.Pod.Equals(o.Pod) &&
		spec.NumInstances == o.NumInstances &&
		spec.RestartPolicy == o.RestartPolicy
}

func (spec PodGroupSpec) VerifyParams() bool {
	verify := spec.Name != "" &&
		spec.Namespace != "" &&
		spec.NumInstances >= 0
	if !verify {
		return false
	}
	return spec.Pod.VerifyParams()
}

func NewPodGroupSpec(name string, namespace string, podSpec PodSpec, numInstances int) PodGroupSpec {
	spec := PodGroupSpec{
		Pod:          podSpec,
		NumInstances: numInstances,
	}
	spec.Name = name
	spec.Namespace = namespace
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	spec.Pod.ImSpec = spec.ImSpec
	return spec
}
<commit_msg>Fixed bug for spec info refresh<commit_after>package engine

import (
	"fmt"
	"strconv"
	"time"

	"github.com/mijia/adoc"
	"github.com/mijia/go-generics"
)

const (
	kLainDeploydRootKey = "/lain/deployd"
	kLainConstraintKey  = "constraints"
	kLainNotifyKey      = "notifies"
	kLainPodGroupKey    = "pod_groups"
	kLainDependencyKey  = "depends"
	kLainSpecKey        = "specs"
	kLainPodKey         = "pods"
	kLainNodesKey       = "nodes"

	kLainVolumeRoot      = "/data/lain/volumes"
	kLainCloudVolumeRoot = "/data/lain/cloud-volumes"
	kLainLabelPrefix     = "cc.bdp.lain.deployd"

	MinPodSetupTime = 0
	MaxPodSetupTime = 300

	MinPodKillTimeout = 10
	MaxPodKillTimeout = 120
)

type ImSpec struct {
	Name      string
	Namespace string
	Version   int
	CreatedAt time.Time
	UpdatedAt time.Time
}

type ContainerLabel struct {
	Name           string
	Namespace      string
	InstanceNo     int
	Version        int
	DriftCount     int
	ContainerIndex int
	Annotation     string
}

func (label ContainerLabel) NameAffinity() string {
	return fmt.Sprintf("affinity:%s.pg_name!=~%s", kLainLabelPrefix, label.Name)
}

func (label ContainerLabel) Label2Maps() map[string]string {
	labelMaps := make(map[string]string)
	labelMaps[kLainLabelPrefix+".pg_name"] = label.Name
	labelMaps[kLainLabelPrefix+".pg_namespace"] = label.Namespace
	labelMaps[kLainLabelPrefix+".instance_no"] = fmt.Sprintf("%d", label.InstanceNo)
	labelMaps[kLainLabelPrefix+".version"] = fmt.Sprintf("%d", label.Version)
	labelMaps[kLainLabelPrefix+".drift_count"] = fmt.Sprintf("%d", label.DriftCount)
	labelMaps[kLainLabelPrefix+".container_index"] = fmt.Sprintf("%d", label.ContainerIndex)
	labelMaps[kLainLabelPrefix+".annotation"] = label.Annotation
	return labelMaps
}

func (label *ContainerLabel) FromMaps(m map[string]string) bool {
	var err error
	hasError := false
	label.Name = m[kLainLabelPrefix+".pg_name"]
	hasError = hasError || label.Name == ""
	label.Namespace = m[kLainLabelPrefix+".pg_namespace"]
	label.InstanceNo, err = strconv.Atoi(m[kLainLabelPrefix+".instance_no"])
	hasError = hasError || err != nil
	label.Version, err = strconv.Atoi(m[kLainLabelPrefix+".version"])
	hasError = hasError || err != nil
	label.DriftCount, err = strconv.Atoi(m[kLainLabelPrefix+".drift_count"])
	hasError = hasError || err != nil
	label.ContainerIndex, err = strconv.Atoi(m[kLainLabelPrefix+".container_index"])
	hasError = hasError || err != nil
	label.Annotation = m[kLainLabelPrefix+".annotation"]
	return !hasError
}

const (
	CloudVolumeSingleMode = "single"
	CloudVolumeMultiMode  = "multi"
)

type CloudVolumeSpec struct {
	Type string
	Dirs []string
}

func (s CloudVolumeSpec) VerifyParams() bool {
	verify := s.Type == CloudVolumeMultiMode ||
		s.Type == CloudVolumeSingleMode

	return verify
}

func (s CloudVolumeSpec) Clone() CloudVolumeSpec {
	newSpec := s
	newSpec.Type = s.Type
	newSpec.Dirs = generics.Clone_StringSlice(s.Dirs)
	return newSpec
}

func (s CloudVolumeSpec) Equals(o CloudVolumeSpec) bool {
	return s.Type == o.Type &&
		generics.Equal_StringSlice(s.Dirs, o.Dirs)
}

type ContainerSpec struct {
	ImSpec
	Image         string
	Env           []string
	User          string
	WorkingDir    string
	DnsSearch     []string
	Volumes       []string // a stateful flag
	SystemVolumes []string // not a stateful flag, every node has system volumes
	CloudVolumes  []CloudVolumeSpec
	Command       []string
	Entrypoint    []string
	CpuLimit      int
	MemoryLimit   int64
	Expose        int
	LogConfig     adoc.LogConfig
}

func (s ContainerSpec) Clone() ContainerSpec {
	newSpec := s
	newSpec.Env = generics.Clone_StringSlice(s.Env)
	newSpec.Volumes = generics.Clone_StringSlice(s.Volumes)
	newSpec.SystemVolumes = generics.Clone_StringSlice(s.SystemVolumes)
	newSpec.Command = generics.Clone_StringSlice(s.Command)
	newSpec.DnsSearch = generics.Clone_StringSlice(s.DnsSearch)
	newSpec.Entrypoint = generics.Clone_StringSlice(s.Entrypoint)
	newSpec.LogConfig.Type = s.LogConfig.Type
	newSpec.LogConfig.Config = generics.Clone_StringStringMap(s.LogConfig.Config)
	for i := range s.CloudVolumes {
		newSpec.CloudVolumes[i] = s.CloudVolumes[i].Clone()
	}
	return newSpec
}

func (s ContainerSpec) VerifyParams() bool {
	verify := s.Image != "" &&
		s.CpuLimit >= 0 &&
		s.MemoryLimit >= 0 &&
		s.Expose >= 0
	if !verify {
		return false
	}
	for _, cvSpec := range s.CloudVolumes {
		if !cvSpec.VerifyParams() {
			return false
		}
	}
	return true
}

func (s ContainerSpec) Equals(o ContainerSpec) bool {
	return s.Name == o.Name &&
		s.Image == o.Image &&
		generics.Equal_StringSlice(s.Env, o.Env) &&
		generics.Equal_StringSlice(s.Command, o.Command) &&
		generics.Equal_StringSlice(s.DnsSearch, o.DnsSearch) &&
		s.CpuLimit == o.CpuLimit &&
		s.MemoryLimit == o.MemoryLimit &&
		s.Expose == o.Expose &&
		s.User == o.User &&
		s.WorkingDir == o.WorkingDir &&
		generics.Equal_StringSlice(s.Volumes, o.Volumes) &&
		generics.Equal_StringSlice(s.SystemVolumes, o.SystemVolumes) &&
		generics.Equal_StringSlice(s.Entrypoint, o.Entrypoint) &&
		s.LogConfig.Type == o.LogConfig.Type &&
		generics.Equal_StringStringMap(s.LogConfig.Config, o.LogConfig.Config)
}

func NewContainerSpec(image string) ContainerSpec {
	spec := ContainerSpec{
		Image: image,
	}
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	return spec
}

type DependencyPolicy int

const (
	DependencyNamespaceLevel = iota
	DependencyNodeLevel
)

type Dependency struct {
	PodName string
	Policy  DependencyPolicy
}

func (d Dependency) Clone() Dependency {
	return d
}

type PodPrevState struct {
	NodeName string
	IPs      []string
}

func NewPodPrevState(length int) PodPrevState {
	return PodPrevState{
		NodeName: "",
		IPs:      make([]string, length),
	}
}

func (pps PodPrevState) Clone() PodPrevState {
	newState := pps
	newState.IPs = make([]string, len(pps.IPs))
	copy(newState.IPs, pps.IPs)
	return newState
}

type PodSpec struct {
	ImSpec
	Network      string
	Containers   []ContainerSpec
	Filters      []string // for cluster scheduling
	Dependencies []Dependency
	Annotation   string
	Stateful     bool
	SetupTime    int
	KillTimeout  int
	PrevState    PodPrevState
}

func (s PodSpec) GetSetupTime() int {
	if s.SetupTime < MinPodSetupTime {
		return MinPodSetupTime
	} else if s.SetupTime > MaxPodSetupTime {
		return MaxPodSetupTime
	}
	return s.SetupTime
}

func (s PodSpec) GetKillTimeout() int {
	if s.KillTimeout < MinPodKillTimeout {
		return MinPodKillTimeout
	} else if s.KillTimeout > MaxPodKillTimeout {
		return MaxPodKillTimeout
	}
	return s.KillTimeout
}

func (s PodSpec) String() string {
	return fmt.Sprintf("Pod[name=%s, version=%d, depends=%+v, stateful=%v, #containers=%d]",
		s.Name, s.Version, s.Dependencies, s.Stateful, len(s.Containers))
}

func (s PodSpec) Clone() PodSpec {
	newSpec := s
	newSpec.Filters = generics.Clone_StringSlice(s.Filters)
	newSpec.Containers = make([]ContainerSpec, len(s.Containers))
	newSpec.PrevState = s.PrevState.Clone()
	for i := range s.Containers {
		newSpec.Containers[i] = s.Containers[i].Clone()
	}
	newSpec.Dependencies = make([]Dependency, len(s.Dependencies))
	for i := range s.Dependencies {
		newSpec.Dependencies[i] = s.Dependencies[i].Clone()
	}
	return newSpec
}

func (s PodSpec) VerifyParams() bool {
	verify := s.Name != "" && s.Namespace != "" &&
		len(s.Containers) > 0
	if !verify {
		return false
	}
	for _, cSpec := range s.Containers {
		if !cSpec.VerifyParams() {
			return false
		}
	}
	return true
}

func (s PodSpec) IsHardStateful() bool {
	return s.Stateful
}

func (s PodSpec) IsStateful() bool {
	return s.HasVolumes() || s.Stateful
}

func (s PodSpec) HasVolumes() bool {
	for _, container := range s.Containers {
		if len(container.Volumes) > 0 {
			return true
		}
	}
	return false
}

func (s PodSpec) Equals(o PodSpec) bool {
	if len(s.Containers) != len(o.Containers) {
		return false
	}
	for i := range s.Containers {
		if !s.Containers[i].Equals(o.Containers[i]) {
			return false
		}
	}
	if len(s.Dependencies) != len(o.Dependencies) {
		return false
	}
	for i := range s.Dependencies {
		if s.Dependencies[i] != o.Dependencies[i] {
			return false
		}
	}
	return s.Name == o.Name &&
		s.Namespace == o.Namespace &&
		s.Version == o.Version &&
		s.Annotation == o.Annotation &&
		s.Stateful == o.Stateful &&
		generics.Equal_StringSlice(s.Filters, o.Filters)
}

func (s PodSpec) Merge(o PodSpec) PodSpec {
	s.Containers = o.Containers
	s.Dependencies = o.Dependencies
	s.Filters = o.Filters
	s.Annotation = o.Annotation
	s.Stateful = o.Stateful
	s.Version += 1
	s.UpdatedAt = time.Now()
	s.PrevState = o.PrevState
	s.SetupTime = o.SetupTime
	s.KillTimeout = o.KillTimeout
	return s
}

func NewPodSpec(containerSpec ContainerSpec, otherSpecs ...ContainerSpec) PodSpec {
	cSpecs := make([]ContainerSpec, 1+len(otherSpecs))
	cSpecs[0] = containerSpec
	for i, cs := range otherSpecs {
		cSpecs[i+1] = cs
	}
	spec := PodSpec{
		Containers: cSpecs,
		PrevState:  NewPodPrevState(len(otherSpecs) + 1),
	}
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	return spec
}

type RestartPolicy int

const (
	RestartPolicyNever = iota
	RestartPolicyAlways
	RestartPolicyOnFail
)

func (rp RestartPolicy) String() string {
	switch rp {
	case RestartPolicyNever:
		return "RestartPolicyNever"
	case RestartPolicyAlways:
		return "RestartPolicyAlways"
	case RestartPolicyOnFail:
		return "RestartPolicyOnFail"
	default:
		return "Unknown RestartPolicy"
	}
}

type PodGroupPrevState struct {
	Nodes []string
	// we think a instance only have one ip, as now a instance only have one container.
	IPs []string
}

func (pgps PodGroupPrevState) Clone() PodGroupPrevState {
	newState := PodGroupPrevState{
		Nodes: make([]string, len(pgps.Nodes)),
		IPs:   make([]string, len(pgps.Nodes)),
	}
	copy(newState.Nodes, pgps.Nodes)
	copy(newState.IPs, pgps.IPs)
	return newState
}

func (pgps PodGroupPrevState) Reset(instanceNo int) PodGroupPrevState {
	newState := PodGroupPrevState{
		Nodes: make([]string, instanceNo),
		IPs:   make([]string, instanceNo),
	}
	copy(newState.Nodes, pgps.Nodes)
	copy(newState.IPs, pgps.IPs)
	return newState
}

func (pgps PodGroupPrevState) Length() int {
	if pgps.Nodes == nil {
		return 0
	}
	return len(pgps.Nodes)
}

type PodGroupSpec struct {
	ImSpec
	Pod           PodSpec
	NumInstances  int
	RestartPolicy RestartPolicy
}

func (spec PodGroupSpec) String() string {
	return fmt.Sprintf("PodGroup[name=%s, version=%d, #instances=%d, restart=%s]",
		spec.Name, spec.Version, spec.NumInstances, spec.RestartPolicy)
}

func (spec PodGroupSpec) Clone() PodGroupSpec {
	newSpec := spec
	newSpec.Pod = spec.Pod.Clone()
	return newSpec
}

func (spec PodGroupSpec) Equals(o PodGroupSpec) bool {
	return spec.Name == o.Name &&
		spec.Namespace == o.Namespace &&
		spec.Version == o.Version &&
		spec.Pod.Equals(o.Pod) &&
		spec.NumInstances == o.NumInstances &&
		spec.RestartPolicy == o.RestartPolicy
}

func (spec PodGroupSpec) VerifyParams() bool {
	verify := spec.Name != "" &&
		spec.Namespace != "" &&
		spec.NumInstances >= 0
	if !verify {
		return false
	}
	return spec.Pod.VerifyParams()
}

func NewPodGroupSpec(name string, namespace string, podSpec PodSpec, numInstances int) PodGroupSpec {
	spec := PodGroupSpec{
		Pod:          podSpec,
		NumInstances: numInstances,
	}
	spec.Name = name
	spec.Namespace = namespace
	spec.Version = 1
	spec.CreatedAt = time.Now()
	spec.UpdatedAt = spec.CreatedAt
	spec.Pod.ImSpec = spec.ImSpec
	return spec
}
<|endoftext|>


<commit_before>package engine

import (
	"testing"
	"runtime"
	"strings"
	"fmt"
	"io/ioutil"
	"github.com/dotcloud/docker/utils"
)

var globalTestID string

func init() {
	Register("dummy", func(job *Job) string { return ""; })
}

func NewTestEngine(t *testing.T) *Engine {
	// Use the caller function name as a prefix.
	// This helps trace temp directories back to their test.
	pc, _, _, _ := runtime.Caller(1)
	callerLongName := runtime.FuncForPC(pc).Name()
	parts := strings.Split(callerLongName, ".")
	callerShortName := parts[len(parts)-1]
	if globalTestID == "" {
		globalTestID = utils.RandomString()[:4]
	}
	prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, callerShortName)
	root, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatal(err)
	}
	eng, err := New(root)
	if err != nil {
		t.Fatal(err)
	}
	return eng
}

func mkJob(t *testing.T, name string, args ...string) *Job {
	return NewTestEngine(t).Job(name, args...)
}
<commit_msg>Engine: don't export private testing utilities<commit_after>package engine

import (
	"testing"
	"runtime"
	"strings"
	"fmt"
	"io/ioutil"
	"github.com/dotcloud/docker/utils"
)

var globalTestID string

func init() {
	Register("dummy", func(job *Job) string { return ""; })
}

func newTestEngine(t *testing.T) *Engine {
	// Use the caller function name as a prefix.
	// This helps trace temp directories back to their test.
	pc, _, _, _ := runtime.Caller(1)
	callerLongName := runtime.FuncForPC(pc).Name()
	parts := strings.Split(callerLongName, ".")
	callerShortName := parts[len(parts)-1]
	if globalTestID == "" {
		globalTestID = utils.RandomString()[:4]
	}
	prefix := fmt.Sprintf("docker-test%s-%s-", globalTestID, callerShortName)
	root, err := ioutil.TempDir("", prefix)
	if err != nil {
		t.Fatal(err)
	}
	eng, err := New(root)
	if err != nil {
		t.Fatal(err)
	}
	return eng
}

func mkJob(t *testing.T, name string, args ...string) *Job {
	return newTestEngine(t).Job(name, args...)
}
<|endoftext|>


<commit_before>package server

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	pfsclient "github.com/pachyderm/pachyderm/src/client/pfs"
	"go.pedge.io/pb/go/google/protobuf"
	"go.pedge.io/proto/rpclog"
	"go.pedge.io/proto/stream"
	"go.pedge.io/proto/time"
	"golang.org/x/net/context"
)

type localBlockAPIServer struct {
	protorpclog.Logger
	dir string
}

func newLocalBlockAPIServer(dir string) (*localBlockAPIServer, error) {
	server := &localBlockAPIServer{
		Logger: protorpclog.NewLogger("pfs.BlockAPIServer.Local"),
		dir:    dir,
	}
	if err := os.MkdirAll(server.blockDir(), 0777); err != nil {
		return nil, err
	}
	return server, nil
}

func (s *localBlockAPIServer) PutBlock(putBlockServer pfsclient.BlockAPI_PutBlockServer) (retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	result := &pfsclient.BlockRefs{}
	defer func(start time.Time) { s.Log(nil, result, retErr, time.Since(start)) }(time.Now())
	defer drainBlockServer(putBlockServer)

	putBlockRequest, err := putBlockServer.Recv()
	if err != nil {
		if err != io.EOF {
			return err
		}
		// Allow empty PutBlock requests, in this case we don't create any actual blockRefs
		return putBlockServer.SendAndClose(result)
	}

	reader := bufio.NewReader(&putBlockReader{
		server: putBlockServer,
		buffer: bytes.NewBuffer(putBlockRequest.Value),
	})

	decoder := json.NewDecoder(reader)

	for {
		blockRef, err := s.putOneBlock(putBlockRequest.Delimiter, reader, decoder)
		if err != nil {
			return err
		}
		result.BlockRef = append(result.BlockRef, blockRef)
		if (blockRef.Range.Upper - blockRef.Range.Lower) < uint64(blockSize) {
			break
		}
	}
	return putBlockServer.SendAndClose(result)
}

func (s *localBlockAPIServer) blockFile(block *pfsclient.Block) (*os.File, error) {
	return os.Open(s.blockPath(block))
}

func (s *localBlockAPIServer) GetBlock(request *pfsclient.GetBlockRequest, getBlockServer pfsclient.BlockAPI_GetBlockServer) (retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, nil, retErr, time.Since(start)) }(time.Now())
	file, err := s.blockFile(request.Block)
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	var reader io.Reader
	if request.SizeBytes == 0 {
		_, err = file.Seek(int64(request.OffsetBytes), 0)
		if err != nil {
			return err
		}
		reader = file
	} else {
		reader = io.NewSectionReader(file, int64(request.OffsetBytes), int64(request.SizeBytes))
	}
	return protostream.WriteToStreamingBytesServer(reader, getBlockServer)
}

func (s *localBlockAPIServer) DeleteBlock(ctx context.Context, request *pfsclient.DeleteBlockRequest) (response *google_protobuf.Empty, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	return google_protobuf.EmptyInstance, s.deleteBlock(request.Block)
}

func (s *localBlockAPIServer) InspectBlock(ctx context.Context, request *pfsclient.InspectBlockRequest) (response *pfsclient.BlockInfo, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	stat, err := os.Stat(s.blockPath(request.Block))
	if err != nil {
		return nil, err
	}
	return &pfsclient.BlockInfo{
		Block: request.Block,
		Created: prototime.TimeToTimestamp(
			stat.ModTime(),
		),
		SizeBytes: uint64(stat.Size()),
	}, nil
}

func (s *localBlockAPIServer) ListBlock(ctx context.Context, request *pfsclient.ListBlockRequest) (response *pfsclient.BlockInfos, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	return nil, fmt.Errorf("not implemented")
}

func (s *localBlockAPIServer) PutObject(ctx context.Context, request *pfsclient.PutObjectRequest) (response *pfsclient.Object, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	object := &pfsclient.Object{Hash: base64.URLEncoding.EncodeToString(newHash().Sum(request.Value))}
	objectPath := s.objectPath(object)
	if err := ioutil.WriteFile(objectPath, request.Value, 0666); err != nil {
		return nil, err
	}
	for _, tag := range request.Tags {
		if err := os.Symlink(objectPath, s.tagPath(tag)); err != nil {
			return nil, err
		}
	}
	return object, nil
}

func (s *localBlockAPIServer) GetObject(ctx context.Context, request *pfsclient.Object) (response *google_protobuf.BytesValue, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	value, err := ioutil.ReadFile(s.objectPath(request))
	if err != nil {
		return nil, err
	}
	return &google_protobuf.BytesValue{Value: value}, nil
}

func (s *localBlockAPIServer) GetTag(ctx context.Context, request *pfsclient.Tag) (response *google_protobuf.BytesValue, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	value, err := ioutil.ReadFile(s.tagPath(request))
	if err != nil {
		return nil, err
	}
	return &google_protobuf.BytesValue{Value: value}, nil
}

func (s *localBlockAPIServer) blockDir() string {
	return filepath.Join(s.dir, "block")
}

func (s *localBlockAPIServer) blockPath(block *pfsclient.Block) string {
	return filepath.Join(s.blockDir(), block.Hash)
}

func (s *localBlockAPIServer) objectDir() string {
	return filepath.Join(s.dir, "object")
}

func (s *localBlockAPIServer) objectPath(object *pfsclient.Object) string {
	return filepath.Join(s.objectDir(), object.Hash)
}

func (s *localBlockAPIServer) tagDir() string {
	return filepath.Join(s.dir, "tag")
}

func (s *localBlockAPIServer) tagPath(tag *pfsclient.Tag) string {
	return filepath.Join(s.tagDir(), tag.Name)
}

func (s *localBlockAPIServer) indexDir() string {
	return filepath.Join(s.dir, "index")
}

func (s *localBlockAPIServer) indexPath(prefix string) string {
	return filepath.Join(s.indexDir(), prefix)
}

func readBlock(delimiter pfsclient.Delimiter, reader *bufio.Reader, decoder *json.Decoder) (*pfsclient.BlockRef, []byte, error) {
	var buffer bytes.Buffer
	var bytesWritten int
	hash := newHash()
	EOF := false
	var value []byte

	for !EOF {
		var err error
		if delimiter == pfsclient.Delimiter_JSON {
			var jsonValue json.RawMessage
			err = decoder.Decode(&jsonValue)
			value = jsonValue
		} else if delimiter == pfsclient.Delimiter_NONE {
			value = make([]byte, 1000)
			n, e := reader.Read(value)
			err = e
			value = value[:n]
		} else {
			value, err = reader.ReadBytes('\n')
		}
		if err != nil {
			if err == io.EOF {
				EOF = true
			} else {
				return nil, nil, err
			}
		}
		buffer.Write(value)
		hash.Write(value)
		bytesWritten += len(value)
		if bytesWritten > blockSize && delimiter != pfsclient.Delimiter_NONE {
			break
		}
	}

	return &pfsclient.BlockRef{
		Block: getBlock(hash),
		Range: &pfsclient.ByteRange{
			Lower: 0,
			Upper: uint64(buffer.Len()),
		},
	}, buffer.Bytes(), nil
}

func (s *localBlockAPIServer) putOneBlock(delimiter pfsclient.Delimiter, reader *bufio.Reader, decoder *json.Decoder) (*pfsclient.BlockRef, error) {
	blockRef, data, err := readBlock(delimiter, reader, decoder)
	if err != nil {
		return nil, err
	}
	if _, err := os.Stat(s.blockPath(blockRef.Block)); os.IsNotExist(err) {
		ioutil.WriteFile(s.blockPath(blockRef.Block), data, 0666)
	}
	return blockRef, nil
}

func (s *localBlockAPIServer) deleteBlock(block *pfsclient.Block) error {
	return os.RemoveAll(s.blockPath(block))
}

type putBlockReader struct {
	server pfsclient.BlockAPI_PutBlockServer
	buffer *bytes.Buffer
}

func (r *putBlockReader) Read(p []byte) (int, error) {
	if r.buffer.Len() == 0 {
		request, err := r.server.Recv()
		if err != nil {
			return 0, err
		}
		// Buffer.Write cannot error
		r.buffer.Write(request.Value)
	}
	return r.buffer.Read(p)
}

func drainBlockServer(putBlockServer pfsclient.BlockAPI_PutBlockServer) {
	for {
		if _, err := putBlockServer.Recv(); err != nil {
			break
		}
	}
}
<commit_msg>Make necessary directories for local object server.<commit_after>package server

import (
	"bufio"
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"time"

	pfsclient "github.com/pachyderm/pachyderm/src/client/pfs"
	"go.pedge.io/pb/go/google/protobuf"
	"go.pedge.io/proto/rpclog"
	"go.pedge.io/proto/stream"
	"go.pedge.io/proto/time"
	"golang.org/x/net/context"
)

type localBlockAPIServer struct {
	protorpclog.Logger
	dir string
}

func newLocalBlockAPIServer(dir string) (*localBlockAPIServer, error) {
	server := &localBlockAPIServer{
		Logger: protorpclog.NewLogger("pfs.BlockAPIServer.Local"),
		dir:    dir,
	}
	if err := os.MkdirAll(server.blockDir(), 0777); err != nil {
		return nil, err
	}
	if err := os.MkdirAll(server.objectDir(), 0777); err != nil {
		return nil, err
	}
	if err := os.MkdirAll(server.tagDir(), 0777); err != nil {
		return nil, err
	}
	return server, nil
}

func (s *localBlockAPIServer) PutBlock(putBlockServer pfsclient.BlockAPI_PutBlockServer) (retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	result := &pfsclient.BlockRefs{}
	defer func(start time.Time) { s.Log(nil, result, retErr, time.Since(start)) }(time.Now())
	defer drainBlockServer(putBlockServer)

	putBlockRequest, err := putBlockServer.Recv()
	if err != nil {
		if err != io.EOF {
			return err
		}
		// Allow empty PutBlock requests, in this case we don't create any actual blockRefs
		return putBlockServer.SendAndClose(result)
	}

	reader := bufio.NewReader(&putBlockReader{
		server: putBlockServer,
		buffer: bytes.NewBuffer(putBlockRequest.Value),
	})

	decoder := json.NewDecoder(reader)

	for {
		blockRef, err := s.putOneBlock(putBlockRequest.Delimiter, reader, decoder)
		if err != nil {
			return err
		}
		result.BlockRef = append(result.BlockRef, blockRef)
		if (blockRef.Range.Upper - blockRef.Range.Lower) < uint64(blockSize) {
			break
		}
	}
	return putBlockServer.SendAndClose(result)
}

func (s *localBlockAPIServer) blockFile(block *pfsclient.Block) (*os.File, error) {
	return os.Open(s.blockPath(block))
}

func (s *localBlockAPIServer) GetBlock(request *pfsclient.GetBlockRequest, getBlockServer pfsclient.BlockAPI_GetBlockServer) (retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, nil, retErr, time.Since(start)) }(time.Now())
	file, err := s.blockFile(request.Block)
	if err != nil {
		return err
	}
	defer func() {
		if err := file.Close(); err != nil && retErr == nil {
			retErr = err
		}
	}()
	var reader io.Reader
	if request.SizeBytes == 0 {
		_, err = file.Seek(int64(request.OffsetBytes), 0)
		if err != nil {
			return err
		}
		reader = file
	} else {
		reader = io.NewSectionReader(file, int64(request.OffsetBytes), int64(request.SizeBytes))
	}
	return protostream.WriteToStreamingBytesServer(reader, getBlockServer)
}

func (s *localBlockAPIServer) DeleteBlock(ctx context.Context, request *pfsclient.DeleteBlockRequest) (response *google_protobuf.Empty, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	return google_protobuf.EmptyInstance, s.deleteBlock(request.Block)
}

func (s *localBlockAPIServer) InspectBlock(ctx context.Context, request *pfsclient.InspectBlockRequest) (response *pfsclient.BlockInfo, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	stat, err := os.Stat(s.blockPath(request.Block))
	if err != nil {
		return nil, err
	}
	return &pfsclient.BlockInfo{
		Block: request.Block,
		Created: prototime.TimeToTimestamp(
			stat.ModTime(),
		),
		SizeBytes: uint64(stat.Size()),
	}, nil
}

func (s *localBlockAPIServer) ListBlock(ctx context.Context, request *pfsclient.ListBlockRequest) (response *pfsclient.BlockInfos, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	return nil, fmt.Errorf("not implemented")
}

func (s *localBlockAPIServer) PutObject(ctx context.Context, request *pfsclient.PutObjectRequest) (response *pfsclient.Object, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	object := &pfsclient.Object{Hash: base64.URLEncoding.EncodeToString(newHash().Sum(request.Value))}
	objectPath := s.objectPath(object)
	if err := ioutil.WriteFile(objectPath, request.Value, 0666); err != nil {
		return nil, err
	}
	for _, tag := range request.Tags {
		if err := os.Symlink(objectPath, s.tagPath(tag)); err != nil {
			return nil, err
		}
	}
	return object, nil
}

func (s *localBlockAPIServer) GetObject(ctx context.Context, request *pfsclient.Object) (response *google_protobuf.BytesValue, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	value, err := ioutil.ReadFile(s.objectPath(request))
	if err != nil {
		return nil, err
	}
	return &google_protobuf.BytesValue{Value: value}, nil
}

func (s *localBlockAPIServer) GetTag(ctx context.Context, request *pfsclient.Tag) (response *google_protobuf.BytesValue, retErr error) {
	func() { s.Log(nil, nil, nil, 0) }()
	defer func(start time.Time) { s.Log(request, response, retErr, time.Since(start)) }(time.Now())
	value, err := ioutil.ReadFile(s.tagPath(request))
	if err != nil {
		return nil, err
	}
	return &google_protobuf.BytesValue{Value: value}, nil
}

func (s *localBlockAPIServer) blockDir() string {
	return filepath.Join(s.dir, "block")
}

func (s *localBlockAPIServer) blockPath(block *pfsclient.Block) string {
	return filepath.Join(s.blockDir(), block.Hash)
}

func (s *localBlockAPIServer) objectDir() string {
	return filepath.Join(s.dir, "object")
}

func (s *localBlockAPIServer) objectPath(object *pfsclient.Object) string {
	return filepath.Join(s.objectDir(), object.Hash)
}

func (s *localBlockAPIServer) tagDir() string {
	return filepath.Join(s.dir, "tag")
}

func (s *localBlockAPIServer) tagPath(tag *pfsclient.Tag) string {
	return filepath.Join(s.tagDir(), tag.Name)
}

func (s *localBlockAPIServer) indexDir() string {
	return filepath.Join(s.dir, "index")
}

func (s *localBlockAPIServer) indexPath(prefix string) string {
	return filepath.Join(s.indexDir(), prefix)
}

func readBlock(delimiter pfsclient.Delimiter, reader *bufio.Reader, decoder *json.Decoder) (*pfsclient.BlockRef, []byte, error) {
	var buffer bytes.Buffer
	var bytesWritten int
	hash := newHash()
	EOF := false
	var value []byte

	for !EOF {
		var err error
		if delimiter == pfsclient.Delimiter_JSON {
			var jsonValue json.RawMessage
			err = decoder.Decode(&jsonValue)
			value = jsonValue
		} else if delimiter == pfsclient.Delimiter_NONE {
			value = make([]byte, 1000)
			n, e := reader.Read(value)
			err = e
			value = value[:n]
		} else {
			value, err = reader.ReadBytes('\n')
		}
		if err != nil {
			if err == io.EOF {
				EOF = true
			} else {
				return nil, nil, err
			}
		}
		buffer.Write(value)
		hash.Write(value)
		bytesWritten += len(value)
		if bytesWritten > blockSize && delimiter != pfsclient.Delimiter_NONE {
			break
		}
	}

	return &pfsclient.BlockRef{
		Block: getBlock(hash),
		Range: &pfsclient.ByteRange{
			Lower: 0,
			Upper: uint64(buffer.Len()),
		},
	}, buffer.Bytes(), nil
}

func (s *localBlockAPIServer) putOneBlock(delimiter pfsclient.Delimiter, reader *bufio.Reader, decoder *json.Decoder) (*pfsclient.BlockRef, error) {
	blockRef, data, err := readBlock(delimiter, reader, decoder)
	if err != nil {
		return nil, err
	}
	if _, err := os.Stat(s.blockPath(blockRef.Block)); os.IsNotExist(err) {
		ioutil.WriteFile(s.blockPath(blockRef.Block), data, 0666)
	}
	return blockRef, nil
}

func (s *localBlockAPIServer) deleteBlock(block *pfsclient.Block) error {
	return os.RemoveAll(s.blockPath(block))
}

type putBlockReader struct {
	server pfsclient.BlockAPI_PutBlockServer
	buffer *bytes.Buffer
}

func (r *putBlockReader) Read(p []byte) (int, error) {
	if r.buffer.Len() == 0 {
		request, err := r.server.Recv()
		if err != nil {
			return 0, err
		}
		// Buffer.Write cannot error
		r.buffer.Write(request.Value)
	}
	return r.buffer.Read(p)
}

func drainBlockServer(putBlockServer pfsclient.BlockAPI_PutBlockServer) {
	for {
		if _, err := putBlockServer.Recv(); err != nil {
			break
		}
	}
}
<|endoftext|>


<commit_before>package switchboard

import (
	"github.com/pivotal-golang/lager"
	"sync"
)

type Backends interface {
	All() <-chan Backend
	Active() Backend
	SetHealthy(backend Backend)
	SetUnhealthy(backend Backend)
	Healthy() <-chan Backend
	ActivityChannels() (<-chan struct{}, <-chan struct{})
}

type backends struct {
	mutex        sync.RWMutex
	all          []*statefulBackend
	active       Backend
	logger       lager.Logger
	activeChan   chan struct{}
	inactiveChan chan struct{}
}

type statefulBackend struct {
	backend Backend
	healthy bool
}

func NewBackends(backendIPs []string, backendPorts []uint, healthcheckPorts []uint, logger lager.Logger) Backends {
	b := &backends{
		logger:       logger,
		all:          make([]*statefulBackend, len(backendIPs)),
		activeChan:   make(chan struct{}),
		inactiveChan: make(chan struct{}, 1),
	}

	for i, ip := range backendIPs {
		backend := NewBackend(
			ip,
			backendPorts[i],
			healthcheckPorts[i],
			logger,
		)

		b.all[i] = &statefulBackend{
			backend: backend,
			healthy: true,
		}
	}

	if len(b.all) > 0 {
		b.active = b.all[0].backend
	} else {
		select {
		case b.inactiveChan <- struct{}{}:
		default:
		}
	}

	return b
}

func (b *backends) ActivityChannels() (<-chan struct{}, <-chan struct{}) {
	return b.activeChan, b.inactiveChan
}

func (b *backends) All() <-chan Backend {
	ch := make(chan Backend, len(b.all))

	go func() {
		b.mutex.RLock()
		defer b.mutex.RUnlock()

		for _, sb := range b.all {
			ch <- sb.backend
		}
		close(ch)
	}()

	return ch
}

func (b *backends) Active() Backend {
	b.mutex.Lock()
	defer b.mutex.Unlock()

	return b.active
}

func (b *backends) SetHealthy(backend Backend) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	knownBackend := b.unsafeSetHealth(backend, true)
	b.logger.Info("Backend became healthy again.")
	if b.active == nil {
		b.active = knownBackend
		if b.active != nil {
			b.logger.Info("Recovering from down cluster, new active backend...")
			select {
			case b.activeChan <- struct{}{}:
			default:
			}
		}
	}
}

func (b *backends) SetUnhealthy(backend Backend) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	knownBackend := b.unsafeSetHealth(backend, false)
	if b.active == knownBackend {
		b.active = b.unsafeNextHealthy()
		b.logger.Info("Active backend became unhealthy. Switching over to next available...")
		if b.active == nil {
			b.logger.Info("All backends unhealthy! No currently active backend.")
			select {
			case b.inactiveChan <- struct{}{}:
			default:
			}
		} else {
			b.logger.Info("Successfully failed over to next available backend!")
		}
	}
}

func (b *backends) unsafeNextHealthy() Backend {
	for _, sb := range b.all {
		if sb.healthy {
			return sb.backend
		}
	}
	return nil
}

func (b *backends) Healthy() <-chan Backend {
	c := make(chan Backend, len(b.all))

	go func() {
		b.mutex.RLock()
		defer b.mutex.RUnlock()

		for _, sb := range b.all {
			if sb.healthy {
				c <- sb.backend
			}
		}

		close(c)
	}()

	return c
}

func (b *backends) unsafeSetHealth(backend Backend, healthy bool) Backend {
	for _, sb := range b.all {
		if sb.backend == backend {
			sb.healthy = healthy
			return sb.backend
		}
	}
	return nil
}
<commit_msg>Use map to represent backends and their health<commit_after>package switchboard

import (
	"sync"

	"github.com/pivotal-golang/lager"
)

type Backends interface {
	All() <-chan Backend
	Active() Backend
	SetHealthy(backend Backend)
	SetUnhealthy(backend Backend)
	Healthy() <-chan Backend
	ActivityChannels() (<-chan struct{}, <-chan struct{})
}

type backends struct {
	mutex        sync.RWMutex
	all          map[Backend]bool
	active       Backend
	logger       lager.Logger
	activeChan   chan struct{}
	inactiveChan chan struct{}
}

func NewBackends(backendIPs []string, backendPorts []uint, healthcheckPorts []uint, logger lager.Logger) Backends {
	b := &backends{
		logger:       logger,
		all:          make(map[Backend]bool),
		activeChan:   make(chan struct{}),
		inactiveChan: make(chan struct{}, 1),
	}

	for i, ip := range backendIPs {
		backend := NewBackend(
			ip,
			backendPorts[i],
			healthcheckPorts[i],
			logger,
		)

		b.all[backend] = true
	}

	if len(b.all) > 0 {
		b.active = b.unsafeNextHealthy()
	} else {
		select {
		case b.inactiveChan <- struct{}{}:
		default:
		}
	}

	return b
}

func (b *backends) ActivityChannels() (<-chan struct{}, <-chan struct{}) {
	return b.activeChan, b.inactiveChan
}

func (b *backends) All() <-chan Backend {
	ch := make(chan Backend, len(b.all))

	go func() {
		b.mutex.RLock()
		defer b.mutex.RUnlock()

		for backend, _ := range b.all {
			ch <- backend
		}
		close(ch)
	}()

	return ch
}

func (b *backends) Active() Backend {
	b.mutex.Lock()
	defer b.mutex.Unlock()

	return b.active
}

func (b *backends) SetHealthy(backend Backend) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	knownBackend := b.unsafeSetHealth(backend, true)
	b.logger.Info("Backend became healthy again.")
	if b.active == nil {
		b.active = knownBackend
		if b.active != nil {
			b.logger.Info("Recovering from down cluster, new active backend...")
			select {
			case b.activeChan <- struct{}{}:
			default:
			}
		}
	}
}

func (b *backends) SetUnhealthy(backend Backend) {
	b.mutex.Lock()
	defer b.mutex.Unlock()
	knownBackend := b.unsafeSetHealth(backend, false)
	if b.active == knownBackend {
		b.active = b.unsafeNextHealthy()
		b.logger.Info("Active backend became unhealthy. Switching over to next available...")
		if b.active == nil {
			b.logger.Info("All backends unhealthy! No currently active backend.")
			select {
			case b.inactiveChan <- struct{}{}:
			default:
			}
		} else {
			b.logger.Info("Successfully failed over to next available backend!")
		}
	}
}

func (b *backends) unsafeNextHealthy() Backend {
	for backend, healthy := range b.all {
		if healthy {
			return backend
		}
	}
	return nil
}

func (b *backends) Healthy() <-chan Backend {
	c := make(chan Backend, len(b.all))

	go func() {
		b.mutex.RLock()
		defer b.mutex.RUnlock()

		for backend, healthy := range b.all {
			if healthy {
				c <- backend
			}
		}

		close(c)
	}()

	return c
}

func (b *backends) unsafeSetHealth(backend Backend, healthy bool) Backend {
	_, found := b.all[backend]
	if found {
		b.all[backend] = healthy
		return backend
	}
	return nil
}
<|endoftext|>