<commit_before>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	RedisManagerDefaultMaxIdle     = 1
	RedisManagerDefaultMaxActive   = 10
	RedisManagerDefaultIdleTimeout = 30 * time.Second
	RedisManagerDefaultHost        = "127.0.0.1" // No use yet
	RedisManagerDefaultPort        = 6379        // No use yet
	RedisManagerDefaultPassword    = ""          // No use yet
	RedisManagerDefaultDb          = 0           // No use yet
	RedisManagerDefaultExpireTime  = 21600       // 6 hours
)

const (
	RedisManagerStatusUncheck = iota
	RedisManagerStatusChecked
	RedisManagerStatusDirty
	RedisManagerStatusError
)

type RedisManager struct {
	maxIdle     int
	maxActive   int
	idleTimeout time.Duration
	host        string
	port        int
	password    string
	db          int
	pool        *redis.Pool
	expireTime  int64
}

func NewRedisManager(host string, port int, password string, db int) *RedisManager {
	redisMgr := &RedisManager{
		maxIdle:     RedisManagerDefaultMaxIdle,
		maxActive:   RedisManagerDefaultMaxActive,
		idleTimeout: RedisManagerDefaultIdleTimeout,
		host:        host,
		port:        port,
		password:    password,
		db:          db,
		pool:        nil,
		expireTime:  RedisManagerDefaultExpireTime,
	}
	redisMgr.pool = redisMgr.init()
	return redisMgr
}

func NewRedisManagerWithPool(host string, port int, password string, db int, maxIdle int, maxActive int, idleTimeout time.Duration) *RedisManager {
	redisMgr := &RedisManager{
		maxIdle:     maxIdle,
		maxActive:   maxActive,
		idleTimeout: idleTimeout,
		host:        host,
		port:        port,
		password:    password,
		db:          db,
	}
	redisMgr.pool = redisMgr.init()
	return redisMgr
}

func (redisMgr *RedisManager) init() *redis.Pool {
	return &redis.Pool{
		MaxIdle:     1,
		MaxActive:   10,
		IdleTimeout: 30 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", redisMgr.host, redisMgr.port))
			if err != nil {
				return nil, err
			}
			c.Do("SELECT", string(redisMgr.db))
			return c, nil
		},
	}
}

func (redisMgr *RedisManager) getConnection() redis.Conn {
	return redisMgr.pool.Get()
}

func (redisMgr *RedisManager) getStatusKey(key string) string {
	return key + "/status"
}

func (redisMgr *RedisManager) getTempKey(key string) string {
	return "tmp/" + key
}

func (redisMgr *RedisManager) Set(key string, str string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	_, err := c.Do("SET", key, str)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (redisMgr *RedisManager) Get(key string) (string, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	v, err := redis.String(c.Do("GET", key))
	if err != nil {
		log.Error(err.Error())
		return "", err
	}
	return v, nil
}

func (redisMgr *RedisManager) Del(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	_, err := c.Do("DEL", key)
	if err != nil {
		log.Error(err.Error())
	}
	return err
}

func (redisMgr *RedisManager) SetObject(key string, obj interface{}) error {
	c := redisMgr.getConnection()
	defer c.Close()

	bytes, e := json.Marshal(obj)
	if e != nil {
		log.Error(e.Error())
		return e
	}
	statusKey := redisMgr.getStatusKey(key)
	status := RedisManagerStatusUncheck

	ok, err := redis.Bool(c.Do("EXISTS", statusKey))
	if err != nil {
		log.Error(err.Error())
		return err
	}
	if ok {
		v, err := redis.Int(c.Do("GET", statusKey))
		if err != nil {
			log.Error(err.Error())
			return err
		}
		if v != RedisManagerStatusChecked {
			status = RedisManagerStatusDirty
		}
	}
	c.Do("MULTI")
	c.Do("SET", key, bytes)
	c.Do("SET", statusKey, status)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}
	return err
}

func (redisMgr *RedisManager) GetObject(key string, obj interface{}) (int, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	status := RedisManagerStatusError
	ok, err := redis.Bool(c.Do("EXISTS", statusKey))
	if ok {
		status, err = redis.Int(c.Do("GET", statusKey))
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
		bytes, err := redis.Bytes(c.Do("GET", key))
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
		err = json.Unmarshal(bytes, obj)
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
	} else {
		err = errors.New("RedisManager: has not status")
		log.Error(err.Error())
		obj = nil
	}
	return status, err
}

func (redisMgr *RedisManager) DelObject(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	c.Do("MULTI")
	c.Do("DEL", key)
	c.Do("DEL", statusKey)
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) CheckObject(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	c.Do("MULTI")
	c.Do("SET", statusKey, RedisManagerStatusChecked)
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) getStudentKey(key string, id int) string {
	return fmt.Sprintf("%s/%d", key, id)
}

func (redisMgr *RedisManager) SetStudents(key string, students []*Student) error {
	c := redisMgr.getConnection()
	defer c.Close()

	c.Do("MULTI")
	for _, student := range students {
		studentId := student.Id
		// log.Info(student)
		studentKey := redisMgr.getStudentKey(key, studentId)
		bytes, err := json.Marshal(student)
		if err != nil {
			log.Error(err.Error())
			c.Do("DISCARD")
			return err
		}
		c.Do("SET", studentKey, bytes)
		c.Do("HMSET", key, studentId, RedisManagerStatusUncheck)
	}
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) SetStudent(key string, student *Student) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentId := student.Id
	studentKey := redisMgr.getStudentKey(key, studentId)
	bytes, err := json.Marshal(student)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	c.Do("MULTI")
	c.Do("HMSET", key, studentId, RedisManagerStatusUncheck)
	c.Do("SET", studentKey, bytes)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) GetStudents(key string) ([]*Student, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	studentIds, err := redis.Ints(c.Do("HKEYS", key))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	c.Do("MULTI")
	for _, studentId := range studentIds {
		studentKey := redisMgr.getStudentKey(key, studentId)
		c.Do("GET", studentKey)
		// log.Info(studentKey)
	}
	values, err := redis.ByteSlices(c.Do("EXEC"))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	students := make([]*Student, 0, len(values))
	for _, value := range values {
		student := &Student{}
		// log.Info(value)
		// log.Info(string(value))
		err = json.Unmarshal(value, student)
		if err != nil {
			log.Error(err.Error())
			return nil, err
		}
		students = append(students, student)
	}

	return students, err
}

func (redisMgr *RedisManager) GetStudent(key string, id int) (*Student, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	studentKey := redisMgr.getStudentKey(key, id)
	value, err := redis.Bytes(c.Do("GET", studentKey))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	student := &Student{}
	err = json.Unmarshal(value, student)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}

	return student, nil
}

func (redisMgr *RedisManager) GetStudentStatus(key string, id int) (int, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	status, err := redis.Int(c.Do("HGET", key, id))
	if err != nil {
		log.Error(err.Error())
		status = RedisManagerStatusError
	}

	return status, err
}

func (redisMgr *RedisManager) DelStudents(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentIds, err := redis.Ints(c.Do("HKEYS", key))
	if err != nil {
		log.Error(err.Error())
		return err
	}
	c.Do("MULTI")
	for _, studentId := range studentIds {
		studentKey := redisMgr.getStudentKey(key, studentId)
		c.Do("DEL", studentKey)
	}
	c.Do("DEL", key)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) DelStudent(key string, id int) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentKey := redisMgr.getStudentKey(key, id)

	c.Do("MULTI")
	c.Do("DEL", studentKey)
	c.Do("HDEL", key, id)
	_, err := c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) CheckStudent(key string, id int) error {
	c := redisMgr.getConnection()
	defer c.Close()

	tempKey := redisMgr.getTempKey(key)
	studentKey := redisMgr.getStudentKey(key, id)
	studentTempKey := redisMgr.getTempKey(studentKey)

	c.Do("MULTI")
	c.Do("RENAME", studentKey, studentTempKey)
	c.Do("SADD", tempKey, id)
	// c.Do("EXPIRE", studentTempKey, redisMgr.expireTime)
	// c.Do("EXPIRE", tempKey, redisMgr.expireTime)
	c.Do("EXPIRE", studentTempKey, 60)
	c.Do("EXPIRE", tempKey, 60)
	c.Do("HDEL", key, id)
	_, err := c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

type Student struct {
	Id   int
	Name string
}

func main() {
	student1 := &Student{
		Id:   1,
		Name: "Ming",
	}
	student2 := &Student{
		Id:   2,
		Name: "huangzeming",
	}
	student3 := &Student{
		Id:   3,
		Name: "zeming",
	}
	students := make([]*Student, 0)
	students = append(students, student1)
	students = append(students, student2)
	students = append(students, student3)

	redisMgr := NewRedisManagerWithPool("127.0.0.1", 6379, "", 0, 1, 10, 30*time.Second)
	redisMgr.SetStudents("students/cqut", students)

	redisMgr.DelStudent("students/cqut", 2)

	queryStudents, _ := redisMgr.GetStudents("students/cqut")
	log.Info(queryStudents)
	for _, queryStudent := range queryStudents {
		log.Info(queryStudent)
	}
	redisMgr.CheckStudent("students/cqut", 3)

	log.Info(redisMgr.GetStudentStatus("students/cqut", 1))
	log.Info(redisMgr.GetStudentStatus("students/cqut", 2))
	log.Info(redisMgr.GetStudentStatus("students/cqut", 3))

	redisMgr.DelStudents("students/cqut")

	redisMgr.SetStudent("students/cqut", student1)
}

func main0() {
	redisMgr := NewRedisManagerWithPool("127.0.0.1", 6379, "", 0, 1, 10, 30*time.Second)
	redisMgr.Set("test", "huangzeming")
	v, _ := redisMgr.Get("test")
	log.Info(v)
	redisMgr.Del("test")
	student := &Student{
		Id:   1,
		Name: "Ming",
	}
	redisMgr.SetObject("student/1", student)
	obj := &Student{}
	status, _ := redisMgr.GetObject("student/1", obj)
	log.Info(obj)
	log.Info(status)
	redisMgr.DelObject("student/1")
}
<commit_msg>Update redis_manager.go<commit_after>package main

import (
	"encoding/json"
	"errors"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/garyburd/redigo/redis"
	"time"
)

const (
	RedisManagerDefaultMaxIdle     = 1
	RedisManagerDefaultMaxActive   = 10
	RedisManagerDefaultIdleTimeout = 30 * time.Second
	RedisManagerDefaultHost        = "127.0.0.1" // No use yet
	RedisManagerDefaultPort        = 6379        // No use yet
	RedisManagerDefaultPassword    = ""          // No use yet
	RedisManagerDefaultDb          = 0           // No use yet
	RedisManagerDefaultExpireTime  = 21600       // 6 hours
)

const (
	RedisManagerStatusUncheck = iota
	RedisManagerStatusChecked
	RedisManagerStatusDirty
	RedisManagerStatusError
)

type RedisManager struct {
	maxIdle     int
	maxActive   int
	idleTimeout time.Duration
	host        string
	port        int
	password    string
	db          int
	pool        *redis.Pool
	expireTime  int64
}

func NewRedisManager(host string, port int, password string, db int) *RedisManager {
	redisMgr := &RedisManager{
		maxIdle:     RedisManagerDefaultMaxIdle,
		maxActive:   RedisManagerDefaultMaxActive,
		idleTimeout: RedisManagerDefaultIdleTimeout,
		host:        host,
		port:        port,
		password:    password,
		db:          db,
		pool:        nil,
		expireTime:  RedisManagerDefaultExpireTime,
	}
	redisMgr.pool = redisMgr.init()
	return redisMgr
}

func NewRedisManagerWithPool(host string, port int, password string, db int, maxIdle int, maxActive int, idleTimeout time.Duration) *RedisManager {
	redisMgr := &RedisManager{
		maxIdle:     maxIdle,
		maxActive:   maxActive,
		idleTimeout: idleTimeout,
		host:        host,
		port:        port,
		password:    password,
		db:          db,
	}
	redisMgr.pool = redisMgr.init()
	return redisMgr
}

func (redisMgr *RedisManager) init() *redis.Pool {
	return &redis.Pool{
		MaxIdle:     1,
		MaxActive:   10,
		IdleTimeout: 30 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", fmt.Sprintf("%s:%d", redisMgr.host, redisMgr.port))
			if err != nil {
				return nil, err
			}
			c.Do("SELECT", string(redisMgr.db))
			return c, nil
		},
	}
}

func (redisMgr *RedisManager) getConnection() redis.Conn {
	c := redisMgr.pool.Get()
	if redisMgr.password != "" {
		c.Do("AUTH", redisMgr.password)
	}
	return c
}

func (redisMgr *RedisManager) getStatusKey(key string) string {
	return key + "/status"
}

func (redisMgr *RedisManager) getTempKey(key string) string {
	return "tmp/" + key
}

func (redisMgr *RedisManager) Set(key string, str string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	_, err := c.Do("SET", key, str)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return nil
}

func (redisMgr *RedisManager) Get(key string) (string, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	v, err := redis.String(c.Do("GET", key))
	if err != nil {
		log.Error(err.Error())
		return "", err
	}
	return v, nil
}

func (redisMgr *RedisManager) Del(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	_, err := c.Do("DEL", key)
	if err != nil {
		log.Error(err.Error())
	}
	return err
}

func (redisMgr *RedisManager) SetObject(key string, obj interface{}) error {
	c := redisMgr.getConnection()
	defer c.Close()

	bytes, e := json.Marshal(obj)
	if e != nil {
		log.Error(e.Error())
		return e
	}
	statusKey := redisMgr.getStatusKey(key)
	status := RedisManagerStatusUncheck

	ok, err := redis.Bool(c.Do("EXISTS", statusKey))
	if err != nil {
		log.Error(err.Error())
		return err
	}
	if ok {
		v, err := redis.Int(c.Do("GET", statusKey))
		if err != nil {
			log.Error(err.Error())
			return err
		}
		if v != RedisManagerStatusChecked {
			status = RedisManagerStatusDirty
		}
	}
	c.Do("MULTI")
	c.Do("SET", key, bytes)
	c.Do("SET", statusKey, status)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}
	return err
}

func (redisMgr *RedisManager) GetObject(key string, obj interface{}) (int, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	status := RedisManagerStatusError
	ok, err := redis.Bool(c.Do("EXISTS", statusKey))
	if ok {
		status, err = redis.Int(c.Do("GET", statusKey))
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
		bytes, err := redis.Bytes(c.Do("GET", key))
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
		err = json.Unmarshal(bytes, obj)
		if err != nil {
			log.Error(err.Error())
			obj = nil
			return RedisManagerStatusError, err
		}
	} else {
		err = errors.New("RedisManager: has not status")
		log.Error(err.Error())
		obj = nil
	}
	return status, err
}

func (redisMgr *RedisManager) DelObject(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	c.Do("MULTI")
	c.Do("DEL", key)
	c.Do("DEL", statusKey)
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) CheckObject(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	statusKey := redisMgr.getStatusKey(key)

	c.Do("MULTI")
	c.Do("SET", statusKey, RedisManagerStatusChecked)
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) getStudentKey(key string, id int) string {
	return fmt.Sprintf("%s/%d", key, id)
}

func (redisMgr *RedisManager) SetStudents(key string, students []*Student) error {
	c := redisMgr.getConnection()
	defer c.Close()

	c.Do("MULTI")
	for _, student := range students {
		studentId := student.Id
		// log.Info(student)
		studentKey := redisMgr.getStudentKey(key, studentId)
		bytes, err := json.Marshal(student)
		if err != nil {
			log.Error(err.Error())
			c.Do("DISCARD")
			return err
		}
		c.Do("SET", studentKey, bytes)
		c.Do("HMSET", key, studentId, RedisManagerStatusUncheck)
	}
	_, err := c.Do("EXEC")

	return err
}

func (redisMgr *RedisManager) SetStudent(key string, student *Student) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentId := student.Id
	studentKey := redisMgr.getStudentKey(key, studentId)
	bytes, err := json.Marshal(student)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	c.Do("MULTI")
	c.Do("HMSET", key, studentId, RedisManagerStatusUncheck)
	c.Do("SET", studentKey, bytes)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) GetStudents(key string) ([]*Student, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	studentIds, err := redis.Ints(c.Do("HKEYS", key))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	c.Do("MULTI")
	for _, studentId := range studentIds {
		studentKey := redisMgr.getStudentKey(key, studentId)
		c.Do("GET", studentKey)
		// log.Info(studentKey)
	}
	values, err := redis.ByteSlices(c.Do("EXEC"))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	students := make([]*Student, 0, len(values))
	for _, value := range values {
		student := &Student{}
		// log.Info(value)
		// log.Info(string(value))
		err = json.Unmarshal(value, student)
		if err != nil {
			log.Error(err.Error())
			return nil, err
		}
		students = append(students, student)
	}

	return students, err
}

func (redisMgr *RedisManager) GetStudent(key string, id int) (*Student, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	studentKey := redisMgr.getStudentKey(key, id)
	value, err := redis.Bytes(c.Do("GET", studentKey))
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}
	student := &Student{}
	err = json.Unmarshal(value, student)
	if err != nil {
		log.Error(err.Error())
		return nil, err
	}

	return student, nil
}

func (redisMgr *RedisManager) GetStudentStatus(key string, id int) (int, error) {
	c := redisMgr.getConnection()
	defer c.Close()

	status, err := redis.Int(c.Do("HGET", key, id))
	if err != nil {
		log.Error(err.Error())
		status = RedisManagerStatusError
	}

	return status, err
}

func (redisMgr *RedisManager) DelStudents(key string) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentIds, err := redis.Ints(c.Do("HKEYS", key))
	if err != nil {
		log.Error(err.Error())
		return err
	}
	c.Do("MULTI")
	for _, studentId := range studentIds {
		studentKey := redisMgr.getStudentKey(key, studentId)
		c.Do("DEL", studentKey)
	}
	c.Do("DEL", key)
	_, err = c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) DelStudent(key string, id int) error {
	c := redisMgr.getConnection()
	defer c.Close()

	studentKey := redisMgr.getStudentKey(key, id)

	c.Do("MULTI")
	c.Do("DEL", studentKey)
	c.Do("HDEL", key, id)
	_, err := c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

func (redisMgr *RedisManager) CheckStudent(key string, id int) error {
	c := redisMgr.getConnection()
	defer c.Close()

	tempKey := redisMgr.getTempKey(key)
	studentKey := redisMgr.getStudentKey(key, id)
	studentTempKey := redisMgr.getTempKey(studentKey)

	c.Do("MULTI")
	c.Do("RENAME", studentKey, studentTempKey)
	c.Do("SADD", tempKey, id)
	// c.Do("EXPIRE", studentTempKey, redisMgr.expireTime)
	// c.Do("EXPIRE", tempKey, redisMgr.expireTime)
	c.Do("EXPIRE", studentTempKey, 60)
	c.Do("EXPIRE", tempKey, 60)
	c.Do("HDEL", key, id)
	_, err := c.Do("EXEC")
	if err != nil {
		log.Error(err.Error())
	}

	return err
}

type Student struct {
	Id   int
	Name string
}

func main() {
	student1 := &Student{
		Id:   1,
		Name: "Ming",
	}
	student2 := &Student{
		Id:   2,
		Name: "huangzeming",
	}
	student3 := &Student{
		Id:   3,
		Name: "zeming",
	}
	students := make([]*Student, 0)
	students = append(students, student1)
	students = append(students, student2)
	students = append(students, student3)

	redisMgr := NewRedisManagerWithPool("127.0.0.1", 6379, "", 0, 1, 10, 30*time.Second)
	redisMgr.SetStudents("students/cqut", students)

	redisMgr.DelStudent("students/cqut", 2)

	queryStudents, _ := redisMgr.GetStudents("students/cqut")
	log.Info(queryStudents)
	for _, queryStudent := range queryStudents {
		log.Info(queryStudent)
	}
	redisMgr.CheckStudent("students/cqut", 3)

	log.Info(redisMgr.GetStudentStatus("students/cqut", 1))
	log.Info(redisMgr.GetStudentStatus("students/cqut", 2))
	log.Info(redisMgr.GetStudentStatus("students/cqut", 3))

	redisMgr.DelStudents("students/cqut")

	redisMgr.SetStudent("students/cqut", student1)
}

func main0() {
	redisMgr := NewRedisManagerWithPool("127.0.0.1", 6379, "", 0, 1, 10, 30*time.Second)
	redisMgr.Set("test", "huangzeming")
	v, _ := redisMgr.Get("test")
	log.Info(v)
	redisMgr.Del("test")
	student := &Student{
		Id:   1,
		Name: "Ming",
	}
	redisMgr.SetObject("student/1", student)
	obj := &Student{}
	status, _ := redisMgr.GetObject("student/1", obj)
	log.Info(obj)
	log.Info(status)
	redisMgr.DelObject("student/1")
}
<|endoftext|>


<commit_before>package main

import (
    "fmt"
    "html/template"
    "io"
    "log"
    "net"
    "net/http"
    "regexp"
)

type Client struct {
    IP net.IP
}

func isCli(userAgent string) bool {
    match, _ := regexp.MatchString("^(?i)(curl|wget|fetch\\slibfetch)\\/.*$",
        userAgent)
    return match
}

func handler(w http.ResponseWriter, req *http.Request) {
    if req.Method != "GET" {
        http.Error(w, "Invalid request method", 405)
        return
    }

    var host string
    var err error
    realIP := req.Header.Get("X-Real-IP")
    if realIP != "" {
        host = realIP
    } else {
        host, _, err = net.SplitHostPort(req.RemoteAddr)
    }
    ip := net.ParseIP(host)
    if err != nil {
        log.Printf("Failed to parse remote address: %s\n", req.RemoteAddr)
        http.Error(w, "Failed to parse remote address", 500)
        return
    }

    if isCli(req.UserAgent()) {
        io.WriteString(w, fmt.Sprintf("%s\n", ip))
    } else {
        t, _ := template.ParseFiles("index.html")
        client := &Client{IP: ip}
        t.Execute(w, client)
    }
}

func main() {
    http.HandleFunc("/", handler)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<commit_msg>Serve assets<commit_after>package main

import (
    "fmt"
    "html/template"
    "io"
    "log"
    "net"
    "net/http"
    "regexp"
)

type Client struct {
    IP net.IP
}

func isCli(userAgent string) bool {
    match, _ := regexp.MatchString("^(?i)(curl|wget|fetch\\slibfetch)\\/.*$",
        userAgent)
    return match
}

func handler(w http.ResponseWriter, req *http.Request) {
    if req.Method != "GET" {
        http.Error(w, "Invalid request method", 405)
        return
    }

    var host string
    var err error
    realIP := req.Header.Get("X-Real-IP")
    if realIP != "" {
        host = realIP
    } else {
        host, _, err = net.SplitHostPort(req.RemoteAddr)
    }
    ip := net.ParseIP(host)
    if err != nil {
        log.Printf("Failed to parse remote address: %s\n", req.RemoteAddr)
        http.Error(w, "Failed to parse remote address", 500)
        return
    }

    if isCli(req.UserAgent()) {
        io.WriteString(w, fmt.Sprintf("%s\n", ip))
    } else {
        t, _ := template.ParseFiles("index.html")
        client := &Client{IP: ip}
        t.Execute(w, client)
    }
}

func main() {
    http.Handle("/assets/", http.StripPrefix("/assets/",
        http.FileServer(http.Dir("assets/"))))
    http.HandleFunc("/", handler)
    err := http.ListenAndServe(":8080", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}
<|endoftext|>


<commit_before>package cast

import (
	"math"

	"testing"
)

func TestIntFromInt32(t *testing.T) {

	tests := []struct{
		Value int32
	}{
		{
			Value: math.MinInt32,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt32,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int32
			}{
				Value: int32(randomness.Int63n(math.MaxInt32)),
			}
			tests = append(tests, test)

			test = struct{
				Value int32
			}{
				Value: -int32(randomness.Int63n(-1*math.MinInt32)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int32(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromInt16(t *testing.T) {

	tests := []struct{
		Value int16
	}{
		{
			Value: math.MinInt16,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt16,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int16
			}{
				Value: int16(randomness.Int63n(math.MaxInt16)),
			}
			tests = append(tests, test)

			test = struct{
				Value int16
			}{
				Value: -int16(randomness.Int63n(-1*math.MinInt16)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int16(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromInt8(t *testing.T) {

	tests := []struct{
		Value int8
	}{
		{
			Value: math.MinInt8,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt8,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int8
			}{
				Value: int8(randomness.Int63n(math.MaxInt8)),
			}
			tests = append(tests, test)

			test = struct{
				Value int8
			}{
				Value: -int8(randomness.Int63n(-1*math.MinInt8)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int8(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromUint16(t *testing.T) {

	tests := []struct{
		Value uint16
	}{
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxUint16,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value uint16
			}{
				Value: uint16(randomness.Int63n(math.MaxUint16)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := uint16(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromUint8(t *testing.T) {

	tests := []struct{
		Value uint8
	}{
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxUint8,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value uint8
			}{
				Value: uint8(randomness.Int63n(math.MaxUint8)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := uint8(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}
<commit_msg>added more tests<commit_after>package cast

import (
	"math"

	"testing"
)

func TestIntFromInt32(t *testing.T) {

	tests := []struct{
		Value int32
	}{
		{
			Value: math.MinInt32,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt32,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int32
			}{
				Value: int32(randomness.Int63n(math.MaxInt32)),
			}
			tests = append(tests, test)

			test = struct{
				Value int32
			}{
				Value: -int32(randomness.Int63n(-1*math.MinInt32)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int32(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromInt16(t *testing.T) {

	tests := []struct{
		Value int16
	}{
		{
			Value: math.MinInt16,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt16,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int16
			}{
				Value: int16(randomness.Int63n(math.MaxInt16)),
			}
			tests = append(tests, test)

			test = struct{
				Value int16
			}{
				Value: -int16(randomness.Int63n(-1*math.MinInt16)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int16(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromInt8(t *testing.T) {

	tests := []struct{
		Value int8
	}{
		{
			Value: math.MinInt8,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxInt8,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int8
			}{
				Value: int8(randomness.Int63n(math.MaxInt8)),
			}
			tests = append(tests, test)

			test = struct{
				Value int8
			}{
				Value: -int8(randomness.Int63n(-1*math.MinInt8)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int8(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromInt(t *testing.T) {

	const maxInt = int((^uint(0)) >> 1)
	const minInt = -maxInt - 1

	tests := []struct{
		Value int
	}{
		{
			Value: minInt,
		},
		{
			Value: -1,
		},
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: maxInt,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value int
			}{
				Value: randomness.Int(),
			}
			tests = append(tests, test)

			test = struct{
				Value int
			}{
				Value: -randomness.Int(),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := int(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromUint16(t *testing.T) {

	tests := []struct{
		Value uint16
	}{
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxUint16,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value uint16
			}{
				Value: uint16(randomness.Int63n(math.MaxUint16)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := uint16(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}

func TestIntFromUint8(t *testing.T) {

	tests := []struct{
		Value uint8
	}{
		{
			Value: 0,
		},
		{
			Value: 1,
		},
		{
			Value: math.MaxUint8,
		},
	}

	{
		const numRand = 20
		for i:=0; i<numRand; i++ {
			test := struct{
				Value uint8
			}{
				Value: uint8(randomness.Int63n(math.MaxUint8)),
			}
			tests = append(tests, test)
		}
	}

	for testNumber, test := range tests {

		x, err := Int(test.Value)
		if nil != err {
			t.Errorf("For test #%d, did not expect an error, but actually got one: (%T) %v", testNumber, err, err)
			continue
		}

		y := uint8(x)

		if expected, actual := test.Value, y; expected != actual {
			t.Errorf("For test #%d, expected %v, but actually got %v.", testNumber, expected, actual)
			continue
		}
	}
}
<|endoftext|>


<commit_before>package taskrunner

import (
	"context"
	"sync"
	"time"

	hclog "github.com/hashicorp/go-hclog"
	"github.com/hashicorp/nomad/client/allocrunner/interfaces"
	cstructs "github.com/hashicorp/nomad/client/structs"
	"github.com/hashicorp/nomad/nomad/structs"
	bstructs "github.com/hashicorp/nomad/plugins/base/structs"
)

// StatsUpdater is the interface required by the StatsHook to update stats.
// Satisfied by TaskRunner.
type StatsUpdater interface {
	UpdateStats(*cstructs.TaskResourceUsage)
}

// statsHook manages the task stats collection goroutine.
type statsHook struct {
	updater  StatsUpdater
	interval time.Duration

	// cancel is called by Exited
	cancel context.CancelFunc

	mu sync.Mutex

	logger hclog.Logger
}

func newStatsHook(su StatsUpdater, interval time.Duration, logger hclog.Logger) *statsHook {
	h := &statsHook{
		updater:  su,
		interval: interval,
	}
	h.logger = logger.Named(h.Name())
	return h
}

func (*statsHook) Name() string {
	return "stats_hook"
}

func (h *statsHook) Poststart(ctx context.Context, req *interfaces.TaskPoststartRequest, _ *interfaces.TaskPoststartResponse) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	// This shouldn't happen, but better safe than risk leaking a goroutine
	if h.cancel != nil {
		h.logger.Debug("poststart called twice without exiting between")
		h.cancel()
	}

	// Using a new context here because the existing context is for the scope of
	// the Poststart request. If that context was used, stats collection would
	// stop when the task was killed. It makes for more readable code and better
	// follows the taskrunner hook model to create a new context that can be
	// canceled on the Exited hook.
	ctx, cancel := context.WithCancel(context.Background())
	h.cancel = cancel
	go h.collectResourceUsageStats(ctx, req.DriverStats)

	return nil
}

func (h *statsHook) Exited(context.Context, *interfaces.TaskExitedRequest, *interfaces.TaskExitedResponse) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	if h.cancel == nil {
		// No stats running
		return nil
	}

	// Call cancel to stop stats collection
	h.cancel()

	// Clear cancel func so we don't double call for any reason
	h.cancel = nil

	return nil
}

// collectResourceUsageStats starts collecting resource usage stats of a Task.
// Collection ends when the passed channel is closed
func (h *statsHook) collectResourceUsageStats(ctx context.Context, handle interfaces.DriverStats) {

MAIN:
	ch, err := h.callStatsWithRetry(ctx, handle)
	if err != nil {
		return
	}

	for {
		select {
		case ru, ok := <-ch:
			// if channel closes, re-establish a new one
			if !ok {
				goto MAIN
			}

			// Update stats on TaskRunner and emit them
			h.updater.UpdateStats(ru)

		case <-ctx.Done():
			return
		}
	}
}

// callStatsWithRetry invokes handle driver Stats() functions and retries until channel is established
// successfully.  Returns an error if it encounters a permanent error.
//
// It logs the errors with appropriate log levels; don't log returned error
func (h *statsHook) callStatsWithRetry(ctx context.Context, handle interfaces.DriverStats) (<-chan *cstructs.TaskResourceUsage, error) {
	var retry int

MAIN:
	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	ch, err := handle.Stats(ctx, h.interval)
	if err == nil {
		return ch, nil
	}

	// Check if the driver doesn't implement stats
	if err.Error() == cstructs.DriverStatsNotImplemented.Error() {
		h.logger.Debug("driver does not support stats")
		return nil, err
	}

	// check if the error is terminal otherwise it's likely a
	// transport error and we should retry
	if re, ok := err.(*structs.RecoverableError); ok && re.IsUnrecoverable() {
		h.logger.Error("failed to start stats collection for task with unrecoverable error", "error", err)
		return nil, err
	}

	// We do not warn when the plugin is shutdown since this is
	// likely because the driver plugin has unexpectedly exited,
	// in which case sleeping and trying again or returning based
	// on the stop channel is the correct behavior
	if err == bstructs.ErrPluginShutdown {
		h.logger.Debug("failed to fetching stats of task", "error", err)
	} else {
		h.logger.Error("failed to start stats collection for task", "error", err)
	}

	limit := time.Second * 5
	backoff := 1 << (2 * uint64(retry)) * time.Second
	if backoff > limit || retry > 5 {
		backoff = limit
	}

	// Increment retry counter
	retry++

	time.Sleep(backoff)
	goto MAIN
}

func (h *statsHook) Shutdown() {
	h.mu.Lock()
	defer h.mu.Unlock()

	if h.cancel == nil {
		return
	}

	h.cancel()
}
<commit_msg>stats_hook: log normal shutdown condition as debug, not error (#8028)<commit_after>package taskrunner

import (
	"context"
	"sync"
	"time"

	hclog "github.com/hashicorp/go-hclog"
	"github.com/hashicorp/nomad/client/allocrunner/interfaces"
	cstructs "github.com/hashicorp/nomad/client/structs"
	"github.com/hashicorp/nomad/nomad/structs"
	bstructs "github.com/hashicorp/nomad/plugins/base/structs"
)

// StatsUpdater is the interface required by the StatsHook to update stats.
// Satisfied by TaskRunner.
type StatsUpdater interface {
	UpdateStats(*cstructs.TaskResourceUsage)
}

// statsHook manages the task stats collection goroutine.
type statsHook struct {
	updater  StatsUpdater
	interval time.Duration

	// cancel is called by Exited
	cancel context.CancelFunc

	mu sync.Mutex

	logger hclog.Logger
}

func newStatsHook(su StatsUpdater, interval time.Duration, logger hclog.Logger) *statsHook {
	h := &statsHook{
		updater:  su,
		interval: interval,
	}
	h.logger = logger.Named(h.Name())
	return h
}

func (*statsHook) Name() string {
	return "stats_hook"
}

func (h *statsHook) Poststart(ctx context.Context, req *interfaces.TaskPoststartRequest, _ *interfaces.TaskPoststartResponse) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	// This shouldn't happen, but better safe than risk leaking a goroutine
	if h.cancel != nil {
		h.logger.Debug("poststart called twice without exiting between")
		h.cancel()
	}

	// Using a new context here because the existing context is for the scope of
	// the Poststart request. If that context was used, stats collection would
	// stop when the task was killed. It makes for more readable code and better
	// follows the taskrunner hook model to create a new context that can be
	// canceled on the Exited hook.
	ctx, cancel := context.WithCancel(context.Background())
	h.cancel = cancel
	go h.collectResourceUsageStats(ctx, req.DriverStats)

	return nil
}

func (h *statsHook) Exited(context.Context, *interfaces.TaskExitedRequest, *interfaces.TaskExitedResponse) error {
	h.mu.Lock()
	defer h.mu.Unlock()

	if h.cancel == nil {
		// No stats running
		return nil
	}

	// Call cancel to stop stats collection
	h.cancel()

	// Clear cancel func so we don't double call for any reason
	h.cancel = nil

	return nil
}

// collectResourceUsageStats starts collecting resource usage stats of a Task.
// Collection ends when the passed channel is closed
func (h *statsHook) collectResourceUsageStats(ctx context.Context, handle interfaces.DriverStats) {

MAIN:
	ch, err := h.callStatsWithRetry(ctx, handle)
	if err != nil {
		return
	}

	for {
		select {
		case ru, ok := <-ch:
			// if channel closes, re-establish a new one
			if !ok {
				goto MAIN
			}

			// Update stats on TaskRunner and emit them
			h.updater.UpdateStats(ru)

		case <-ctx.Done():
			return
		}
	}
}

// callStatsWithRetry invokes handle driver Stats() functions and retries until channel is established
// successfully.  Returns an error if it encounters a permanent error.
//
// It logs the errors with appropriate log levels; don't log returned error
func (h *statsHook) callStatsWithRetry(ctx context.Context, handle interfaces.DriverStats) (<-chan *cstructs.TaskResourceUsage, error) {
	var retry int

MAIN:
	if ctx.Err() != nil {
		return nil, ctx.Err()
	}

	ch, err := handle.Stats(ctx, h.interval)
	if err == nil {
		return ch, nil
	}

	// Check if the driver doesn't implement stats
	if err.Error() == cstructs.DriverStatsNotImplemented.Error() {
		h.logger.Debug("driver does not support stats")
		return nil, err
	}

	// check if the error is terminal otherwise it's likely a
	// transport error and we should retry
	if re, ok := err.(*structs.RecoverableError); ok && re.IsUnrecoverable() {
		h.logger.Debug("failed to start stats collection for task with unrecoverable error", "error", err)
		return nil, err
	}

	// We do not warn when the plugin is shutdown since this is
	// likely because the driver plugin has unexpectedly exited,
	// in which case sleeping and trying again or returning based
	// on the stop channel is the correct behavior
	if err == bstructs.ErrPluginShutdown {
		h.logger.Debug("failed to fetching stats of task", "error", err)
	} else {
		h.logger.Error("failed to start stats collection for task", "error", err)
	}

	limit := time.Second * 5
	backoff := 1 << (2 * uint64(retry)) * time.Second
	if backoff > limit || retry > 5 {
		backoff = limit
	}

	// Increment retry counter
	retry++

	time.Sleep(backoff)
	goto MAIN
}

func (h *statsHook) Shutdown() {
	h.mu.Lock()
	defer h.mu.Unlock()

	if h.cancel == nil {
		return
	}

	h.cancel()
}
<|endoftext|>


<commit_before>package slackapi

// FileListArgs defines the data to send to the API service.
type FileListArgs struct {
	Channel string `json:"channel"`
	Count   int    `json:"count"`
	Page    int    `json:"page"`
	TsFrom  string `json:"ts_from"`
	TsTo    string `json:"ts_to"`
	Types   string `json:"types"`
	User    string `json:"user"`
}

// FileUploadArgs defines the data to send to the API service.
type FileUploadArgs struct {
	Channels       string `json:"channels"`
	Content        string `json:"content"`
	File           string `json:"file"`
	Filename       string `json:"filename"`
	Filetype       string `json:"filetype"`
	InitialComment string `json:"initial_comment"`
	Title          string `json:"title"`
}

// ResponseFilesInfo defines the JSON-encoded output for FilesInfo.
type ResponseFilesInfo struct {
	Response
	File     File          `json:"file"`
	Comments []FileComment `json:"comments"`
	Paging   Paging        `json:"paging"`
}

// ResponseFilesList defines the JSON-encoded output for FilesList.
type ResponseFilesList struct {
	Response
	Files  []File `json:"files"`
	Paging Paging `json:"paging"`
}

// ResponseFilesSharedPublicURL defines the JSON-encoded output for FilesSharedPublicURL.
type ResponseFilesSharedPublicURL struct {
	Response
	File File `json:"file"`
}

// ResponseFilesUpload defines the JSON-encoded output for FilesUpload.
type ResponseFilesUpload struct {
	Response
	File File `json:"file"`
}

// ResponseFilesComments defines the JSON-encoded output for FilesComments.
type ResponseFilesComments struct {
	Response
	Comment FileComment `json:"comment"`
}

// File defines the expected data from the JSON-encoded API response.
type File struct {
	Channels           []string    `json:"channels"`
	CommentsCount      int         `json:"comments_count"`
	Created            int         `json:"created"`
	DeanimateGif       string      `json:"deanimate_gif"`
	DisplayAsBot       bool        `json:"display_as_bot"`
	Editable           bool        `json:"editable"`
	EditLink           string      `json:"edit_link"`
	ExternalType       string      `json:"external_type"`
	Filetype           string      `json:"filetype"`
	Groups             []string    `json:"groups"`
	ID                 string      `json:"id"`
	ImageExifRotation  int         `json:"image_exif_rotation"`
	InitialComment     FileComment `json:"initial_comment"`
	InstantMessages    []string    `json:"ims"`
	IsExternal         bool        `json:"is_external"`
	IsPublic           bool        `json:"is_public"`
	IsStarred          bool        `json:"is_starred"`
	Lines              int         `json:"lines"`
	LinesMore          int         `json:"lines_more"`
	Mimetype           string      `json:"mimetype"`
	Mode               string      `json:"mode"`
	Name               string      `json:"name"`
	NumStars           int         `json:"num_stars"`
	OriginalH          int         `json:"original_h"`
	OriginalW          int         `json:"original_w"`
	Permalink          string      `json:"permalink"`
	PermalinkPublic    string      `json:"permalink_public"`
	PrettyType         string      `json:"pretty_type"`
	Preview            string      `json:"preview"`
	PreviewHighlight   string      `json:"preview_highlight"`
	PublicURLShared    bool        `json:"public_url_shared"`
	Reactions          []Reaction  `json:"reactions"`
	Score              string      `json:"score"`
	Size               int         `json:"size"`
	Thumb160           string      `json:"thumb_160"`
	Thumb360           string      `json:"thumb_360"`
	Thumb360Gif        string      `json:"thumb_360_gif"`
	Thumb360H          int         `json:"thumb_360_h"`
	Thumb360W          int         `json:"thumb_360_w"`
	Thumb480           string      `json:"thumb_480"`
	Thumb480Gif        string      `json:"thumb_480_gif"`
	Thumb480H          int         `json:"thumb_480_h"`
	Thumb480W          int         `json:"thumb_480_w"`
	Thumb64            string      `json:"thumb_64"`
	Thumb80            string      `json:"thumb_80"`
	Timestamp          int         `json:"timestamp"`
	Title              string      `json:"title"`
	TopFile            bool        `json:"top_file"`
	URL                string      `json:"url"`
	URLDownload        string      `json:"url_download"`
	URLPrivate         string      `json:"url_private"`
	URLPrivateDownload string      `json:"url_private_download"`
	User               string      `json:"user"`
	Username           string      `json:"username"`
}

// FileComment defines the expected data from the JSON-encoded API response.
type FileComment struct {
	Comment   string `json:"comment"`
	ID        string `json:"id"`
	User      string `json:"user"`
	Created   int    `json:"created"`
	Timestamp int    `json:"timestamp"`
	IsIntro   bool   `json:"is_intro"`
}

// FilesCommentsAdd add a comment to an existing file.
func (s *SlackAPI) FilesCommentsAdd(file string, comment string) ResponseFilesComments {
	var response ResponseFilesComments
	s.postRequest(&response, "files.comments.add", struct {
		File    string `json:"file"`
		Comment string `json:"comment"`
	}{file, comment})
	return response
}

// FilesCommentsDelete deletes an existing comment on a file.
func (s *SlackAPI) FilesCommentsDelete(file string, commentid string) Response {
	var response Response
	s.postRequest(&response, "files.comments.delete", struct {
		File string `json:"file"`
		ID   string `json:"id"`
	}{file, commentid})
	return response
}

// FilesCommentsEdit edit an existing file comment.
func (s *SlackAPI) FilesCommentsEdit(file string, commentid string, comment string) ResponseFilesComments {
	var response ResponseFilesComments
	s.postRequest(&response, "files.comments.edit", struct {
		File    string `json:"file"`
		ID      string `json:"id"`
		Comment string `json:"comment"`
	}{file, commentid, comment})
	return response
}

// FilesDelete deletes a file.
func (s *SlackAPI) FilesDelete(file string) Response {
	var response Response
	s.postRequest(&response, "files.delete", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesInfo gets information about a team file.
func (s *SlackAPI) FilesInfo(file string, count int, page int) ResponseFilesInfo {
	var response ResponseFilesInfo
	s.getRequest(&response, "files.info", struct {
		File  string `json:"file"`
		Count int    `json:"count"`
		Page  int    `json:"page"`
	}{file, count, page})
	return response
}

// FilesList lists and filters team files.
// FilesListAfterTime lists and filters team files after this timestamp (inclusive).
// FilesListBeforeTime lists and filters team files before this timestamp (inclusive).
// FilesListByChannel lists and filters team files in a specific channel.
// FilesListByType lists and filters team files by type: all, posts, snippets, images, gdocs, zips, pdfs.
// FilesListByUser lists and filters team files created by a single user.
func (s *SlackAPI) FilesList(data FileListArgs) ResponseFilesList {
	if data.Count == 0 {
		data.Count = 100
	}

	var response ResponseFilesList
	s.getRequest(&response, "files.list", data)
	return response
}

// FilesRevokePublicURL revokes public/external sharing access for a file.
func (s *SlackAPI) FilesRevokePublicURL(file string) interface{} {
	var response interface{}
	s.postRequest(&response, "files.revokePublicURL", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesSharedPublicURL enables a file for public/external sharing.
func (s *SlackAPI) FilesSharedPublicURL(file string) ResponseFilesSharedPublicURL {
	var response ResponseFilesSharedPublicURL
	s.postRequest(&response, "files.sharedPublicURL", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesUpload uploads or creates a file.
func (s *SlackAPI) FilesUpload(data FileUploadArgs) ResponseFilesUpload {
	var response ResponseFilesUpload
	s.postRequest(&response, "files.upload", data)
	return response
}
<commit_msg>Fix struct padding for the File struct<commit_after>package slackapi

// FileListArgs defines the data to send to the API service.
type FileListArgs struct {
	Channel string `json:"channel"`
	Count   int    `json:"count"`
	Page    int    `json:"page"`
	TsFrom  string `json:"ts_from"`
	TsTo    string `json:"ts_to"`
	Types   string `json:"types"`
	User    string `json:"user"`
}

// FileUploadArgs defines the data to send to the API service.
type FileUploadArgs struct {
	Channels       string `json:"channels"`
	Content        string `json:"content"`
	File           string `json:"file"`
	Filename       string `json:"filename"`
	Filetype       string `json:"filetype"`
	InitialComment string `json:"initial_comment"`
	Title          string `json:"title"`
}

// ResponseFilesInfo defines the JSON-encoded output for FilesInfo.
type ResponseFilesInfo struct {
	Response
	File     File          `json:"file"`
	Comments []FileComment `json:"comments"`
	Paging   Paging        `json:"paging"`
}

// ResponseFilesList defines the JSON-encoded output for FilesList.
type ResponseFilesList struct {
	Response
	Files  []File `json:"files"`
	Paging Paging `json:"paging"`
}

// ResponseFilesSharedPublicURL defines the JSON-encoded output for FilesSharedPublicURL.
type ResponseFilesSharedPublicURL struct {
	Response
	File File `json:"file"`
}

// ResponseFilesUpload defines the JSON-encoded output for FilesUpload.
type ResponseFilesUpload struct {
	Response
	File File `json:"file"`
}

// ResponseFilesComments defines the JSON-encoded output for FilesComments.
type ResponseFilesComments struct {
	Response
	Comment FileComment `json:"comment"`
}

// File defines the expected data from the JSON-encoded API response.
type File struct {
	Channels           []string    `json:"channels"`
	CommentsCount      int         `json:"comments_count"`
	Created            int         `json:"created"`
	DeanimateGif       string      `json:"deanimate_gif"`
	EditLink           string      `json:"edit_link"`
	ExternalType       string      `json:"external_type"`
	Filetype           string      `json:"filetype"`
	Groups             []string    `json:"groups"`
	ID                 string      `json:"id"`
	ImageExifRotation  int         `json:"image_exif_rotation"`
	InitialComment     FileComment `json:"initial_comment"`
	InstantMessages    []string    `json:"ims"`
	Lines              int         `json:"lines"`
	LinesMore          int         `json:"lines_more"`
	Mimetype           string      `json:"mimetype"`
	Mode               string      `json:"mode"`
	Name               string      `json:"name"`
	NumStars           int         `json:"num_stars"`
	OriginalH          int         `json:"original_h"`
	OriginalW          int         `json:"original_w"`
	Permalink          string      `json:"permalink"`
	PermalinkPublic    string      `json:"permalink_public"`
	PrettyType         string      `json:"pretty_type"`
	Preview            string      `json:"preview"`
	PreviewHighlight   string      `json:"preview_highlight"`
	Reactions          []Reaction  `json:"reactions"`
	Score              string      `json:"score"`
	Size               int         `json:"size"`
	Thumb160           string      `json:"thumb_160"`
	Thumb360           string      `json:"thumb_360"`
	Thumb360Gif        string      `json:"thumb_360_gif"`
	Thumb360H          int         `json:"thumb_360_h"`
	Thumb360W          int         `json:"thumb_360_w"`
	Thumb480           string      `json:"thumb_480"`
	Thumb480Gif        string      `json:"thumb_480_gif"`
	Thumb480H          int         `json:"thumb_480_h"`
	Thumb480W          int         `json:"thumb_480_w"`
	Thumb64            string      `json:"thumb_64"`
	Thumb80            string      `json:"thumb_80"`
	Timestamp          int         `json:"timestamp"`
	Title              string      `json:"title"`
	URL                string      `json:"url"`
	URLDownload        string      `json:"url_download"`
	URLPrivate         string      `json:"url_private"`
	URLPrivateDownload string      `json:"url_private_download"`
	User               string      `json:"user"`
	Username           string      `json:"username"`
	DisplayAsBot       bool        `json:"display_as_bot"`
	Editable           bool        `json:"editable"`
	IsExternal         bool        `json:"is_external"`
	IsPublic           bool        `json:"is_public"`
	IsStarred          bool        `json:"is_starred"`
	PublicURLShared    bool        `json:"public_url_shared"`
	TopFile            bool        `json:"top_file"`
}

// FileComment defines the expected data from the JSON-encoded API response.
type FileComment struct {
	Comment   string `json:"comment"`
	ID        string `json:"id"`
	User      string `json:"user"`
	Created   int    `json:"created"`
	Timestamp int    `json:"timestamp"`
	IsIntro   bool   `json:"is_intro"`
}

// FilesCommentsAdd add a comment to an existing file.
func (s *SlackAPI) FilesCommentsAdd(file string, comment string) ResponseFilesComments {
	var response ResponseFilesComments
	s.postRequest(&response, "files.comments.add", struct {
		File    string `json:"file"`
		Comment string `json:"comment"`
	}{file, comment})
	return response
}

// FilesCommentsDelete deletes an existing comment on a file.
func (s *SlackAPI) FilesCommentsDelete(file string, commentid string) Response {
	var response Response
	s.postRequest(&response, "files.comments.delete", struct {
		File string `json:"file"`
		ID   string `json:"id"`
	}{file, commentid})
	return response
}

// FilesCommentsEdit edit an existing file comment.
func (s *SlackAPI) FilesCommentsEdit(file string, commentid string, comment string) ResponseFilesComments {
	var response ResponseFilesComments
	s.postRequest(&response, "files.comments.edit", struct {
		File    string `json:"file"`
		ID      string `json:"id"`
		Comment string `json:"comment"`
	}{file, commentid, comment})
	return response
}

// FilesDelete deletes a file.
func (s *SlackAPI) FilesDelete(file string) Response {
	var response Response
	s.postRequest(&response, "files.delete", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesInfo gets information about a team file.
func (s *SlackAPI) FilesInfo(file string, count int, page int) ResponseFilesInfo {
	var response ResponseFilesInfo
	s.getRequest(&response, "files.info", struct {
		File  string `json:"file"`
		Count int    `json:"count"`
		Page  int    `json:"page"`
	}{file, count, page})
	return response
}

// FilesList lists and filters team files.
// FilesListAfterTime lists and filters team files after this timestamp (inclusive).
// FilesListBeforeTime lists and filters team files before this timestamp (inclusive).
// FilesListByChannel lists and filters team files in a specific channel.
// FilesListByType lists and filters team files by type: all, posts, snippets, images, gdocs, zips, pdfs.
// FilesListByUser lists and filters team files created by a single user.
func (s *SlackAPI) FilesList(data FileListArgs) ResponseFilesList {
	if data.Count == 0 {
		data.Count = 100
	}

	var response ResponseFilesList
	s.getRequest(&response, "files.list", data)
	return response
}

// FilesRevokePublicURL revokes public/external sharing access for a file.
func (s *SlackAPI) FilesRevokePublicURL(file string) interface{} {
	var response interface{}
	s.postRequest(&response, "files.revokePublicURL", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesSharedPublicURL enables a file for public/external sharing.
func (s *SlackAPI) FilesSharedPublicURL(file string) ResponseFilesSharedPublicURL {
	var response ResponseFilesSharedPublicURL
	s.postRequest(&response, "files.sharedPublicURL", struct {
		File string `json:"file"`
	}{file})
	return response
}

// FilesUpload uploads or creates a file.
func (s *SlackAPI) FilesUpload(data FileUploadArgs) ResponseFilesUpload {
	var response ResponseFilesUpload
	s.postRequest(&response, "files.upload", data)
	return response
}
<|endoftext|>


<commit_before>package io

import (
	"fmt"
	"strconv"

	"github.com/phil-mansfield/shellfish/cosmo"
	artio "github.com/phil-mansfield/go-artio"
)

const (
	// emulateHubble is used for debugging purposes. I've never had access to
	// a cosmological simulation, so this is necessary.
	emulateHubble = true
)

type ARTIOBuffer struct {
	open bool
	xsBuf [][3]float32
	msBuf []float32
	xsBufs [][][3]float32
	msBufs [][]float32
	sMasses []float32
	fileset string
}

func NewARTIOBuffer(fileset string) (VectorBuffer, error) {
	h, err := artio.FilesetOpen(fileset, artio.OpenHeader, artio.NullContext)
	if err != nil { return nil, err  }
	defer h.Close()

	numSpecies := h.GetInt(h.Key("num_particle_species"))[0]

	sMasses := h.GetFloat(h.Key("particle_species_mass"))

	var h100 float64
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return nil, fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = h.GetDouble(h.Key("hubble"))[0]
	}
	massUnit := (h100 / cosmo.MSunMks * 1000) *
		h.GetDouble(h.Key("mass_unit"))[0]
	for i := range sMasses { sMasses[i] *= float32(massUnit) }

	return &ARTIOBuffer{
		xsBufs: make([][][3]float32, numSpecies),
		sMasses: sMasses,
	}, nil
}

func (buf *ARTIOBuffer) Read(
	fileNumStr string,
) ([][3]float32, []float32, error) {
	// Open the file.
	if buf.open { panic("Buffer already open.") }
	buf.open = true

	h, err := artio.FilesetOpen(
		buf.fileset, artio.OpenHeader, artio.NullContext,
	)
	if err != nil { return nil, nil, err  }
	defer h.Close()

	// I'm not sure if this can just be replaced with putting an
	// artio.OpenParticles flag in artio.FilesetOpen(). Someone with more
	// knowledge about ARTIO than me should figure this out.
	err = h.OpenParticles()
	if err != nil { return nil, nil, err}

	// Flag N_BODY particles.
	flags, err := nBodyFlags(h, buf.fileset)
	if err != nil { return nil, nil, err }

	// Get SFC range.
	fIdx, err := strconv.Atoi(fileNumStr)
	fileIdxs := h.GetLong(h.Key("particle_file_sfc_index"))
	sfcStart, sfcEnd := fileIdxs[fIdx], fileIdxs[fIdx + 1] - 1

	// Counts and buffer manipulation. Do the reading.
	sCounts, err := h.CountInRange(sfcStart, sfcEnd)
	totCount := int64(0)
	for i := range sCounts {
		if flags[i] {
			totCount += sCounts[i]
			expandVectors(buf.xsBufs[i][:0], int(sCounts[i]))
			err = h.GetPositionsAt(i, sfcStart, sfcEnd, buf.xsBufs[i])
			if err != nil { return nil, nil, err }

			expandScalars(buf.msBufs[i][:0], int(sCounts[i]))
			for j := range buf.msBufs[i] {
				buf.msBufs[i][j] = buf.sMasses[i]
			}
		}
	}

	// Copy to output buffer.
	expandVectors(buf.xsBuf, int(totCount))
	expandScalars(buf.msBuf, int(totCount))
	k := 0
	for j := range buf.xsBufs {
		for i := range buf.xsBufs[j] {
			buf.xsBuf[k] = buf.xsBufs[j][i]
			buf.msBuf[k] = buf.msBufs[j][i]
			k++
		}
	}

	var h100 float32
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return nil, nil, fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = float32(h.GetDouble(h.Key("hubble"))[0])
	}

	lengthUnit := float32(h100) / (cosmo.MpcMks * 100)
	for i := range buf.xsBuf {
		buf.xsBuf[i][0] *= lengthUnit
		buf.xsBuf[i][1] *= lengthUnit
		buf.xsBuf[i][2] *= lengthUnit
	}

	return buf.xsBuf, buf.msBuf, nil
}

func nBodyFlags(h artio.Fileset, fname string) ([]bool, error) {
	speciesLabels := h.GetString(h.Key("particle_species_labels"))
	isNBody, nBodyCount := make([]bool, len(speciesLabels)), 0
	for i := range isNBody {
		isNBody[i] = speciesLabels[i] == "N-BODY"
		nBodyCount++
	}
	if nBodyCount == 0 {
		return nil, fmt.Errorf("ARTIO fileset '%s' does not contain any " +
		"particle species of type 'N-BODY'.", fname)
	}
	return isNBody, nil

}

func (buf *ARTIOBuffer) Close() {
	if !buf.open { panic("Buffer not open.") }
	buf.open = false
}

func (buf *ARTIOBuffer) IsOpen() bool {
	return buf.open
}

func (buf *ARTIOBuffer) ReadHeader(fileNumStr string, out *Header) error {
	xs, _, err := buf.Read(fileNumStr)

	h, err := artio.FilesetOpen(
		buf.fileset, artio.OpenHeader, artio.NullContext,
	)
	if err != nil { return err }
	defer h.Close()

	var h100 float64
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = h.GetDouble(h.Key("hubble"))[0]
	}

	out.TotalWidth = h.GetDouble(h.Key("box_size"))[0] *
		(h100 / (cosmo.MpcMks * 100))
	out.Origin, out.Width = boundingBox(xs, out.TotalWidth)
	out.N = int64(len(xs))

	switch {
	case !h.HasKey("auni"):
		return fmt.Errorf("ARTIO header does not contain 'auni' field.")
	case !h.HasKey("OmegaM"):
		return fmt.Errorf("ARTIO header does not contain 'OmegaM' field.")
	case !h.HasKey("OmegaL"):
		return fmt.Errorf("ARTIO header does not contain 'OmegaL' field.")

	}

	out.Cosmo.Z = 1/h.GetDouble(h.Key("auni"))[0] - 1
	out.Cosmo.OmegaM = h.GetDouble(h.Key("OmegaM"))[0]
	out.Cosmo.OmegaL = h.GetDouble(h.Key("OmegaL"))[0]
	out.Cosmo.H100 = h.GetDouble(h.Key("hubble"))[0]

	if out.Cosmo.H100 > 10 {
		panic("Oops, Phil misunderstood the meaning of an ARTIO field. " +
		"Please submit an issue.")
	}

	return nil
}<commit_msg>Clarified emulateHubble constant.<commit_after>package io

import (
	"fmt"
	"strconv"

	"github.com/phil-mansfield/shellfish/cosmo"
	artio "github.com/phil-mansfield/go-artio"
)

const (
	// emulateHubble is used for debugging purposes. I've never had access to
	// a cosmological simulation, so this is necessary. Don't worry: even if
	// this flag is set, an error will still be returned if called on invalid
	// header contents. It will just occur late enough to allow for illustrative
	// logging.
	emulateHubble = true
)

type ARTIOBuffer struct {
	open bool
	xsBuf [][3]float32
	msBuf []float32
	xsBufs [][][3]float32
	msBufs [][]float32
	sMasses []float32
	fileset string
}

func NewARTIOBuffer(fileset string) (VectorBuffer, error) {
	h, err := artio.FilesetOpen(fileset, artio.OpenHeader, artio.NullContext)
	if err != nil { return nil, err  }
	defer h.Close()

	numSpecies := h.GetInt(h.Key("num_particle_species"))[0]

	sMasses := h.GetFloat(h.Key("particle_species_mass"))

	var h100 float64
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return nil, fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = h.GetDouble(h.Key("hubble"))[0]
	}
	massUnit := (h100 / cosmo.MSunMks * 1000) *
		h.GetDouble(h.Key("mass_unit"))[0]
	for i := range sMasses { sMasses[i] *= float32(massUnit) }

	return &ARTIOBuffer{
		xsBufs: make([][][3]float32, numSpecies),
		sMasses: sMasses,
	}, nil
}

func (buf *ARTIOBuffer) Read(
	fileNumStr string,
) ([][3]float32, []float32, error) {
	// Open the file.
	if buf.open { panic("Buffer already open.") }
	buf.open = true

	h, err := artio.FilesetOpen(
		buf.fileset, artio.OpenHeader, artio.NullContext,
	)
	if err != nil { return nil, nil, err  }
	defer h.Close()

	// I'm not sure if this can just be replaced with putting an
	// artio.OpenParticles flag in artio.FilesetOpen(). Someone with more
	// knowledge about ARTIO than me should figure this out.
	err = h.OpenParticles()
	if err != nil { return nil, nil, err}

	// Flag N_BODY particles.
	flags, err := nBodyFlags(h, buf.fileset)
	if err != nil { return nil, nil, err }

	// Get SFC range.
	fIdx, err := strconv.Atoi(fileNumStr)
	fileIdxs := h.GetLong(h.Key("particle_file_sfc_index"))
	sfcStart, sfcEnd := fileIdxs[fIdx], fileIdxs[fIdx + 1] - 1

	// Counts and buffer manipulation. Do the reading.
	sCounts, err := h.CountInRange(sfcStart, sfcEnd)
	totCount := int64(0)
	for i := range sCounts {
		if flags[i] {
			totCount += sCounts[i]
			expandVectors(buf.xsBufs[i][:0], int(sCounts[i]))
			err = h.GetPositionsAt(i, sfcStart, sfcEnd, buf.xsBufs[i])
			if err != nil { return nil, nil, err }

			expandScalars(buf.msBufs[i][:0], int(sCounts[i]))
			for j := range buf.msBufs[i] {
				buf.msBufs[i][j] = buf.sMasses[i]
			}
		}
	}

	// Copy to output buffer.
	expandVectors(buf.xsBuf, int(totCount))
	expandScalars(buf.msBuf, int(totCount))
	k := 0
	for j := range buf.xsBufs {
		for i := range buf.xsBufs[j] {
			buf.xsBuf[k] = buf.xsBufs[j][i]
			buf.msBuf[k] = buf.msBufs[j][i]
			k++
		}
	}

	var h100 float32
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return nil, nil, fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = float32(h.GetDouble(h.Key("hubble"))[0])
	}

	lengthUnit := float32(h100) / (cosmo.MpcMks * 100)
	for i := range buf.xsBuf {
		buf.xsBuf[i][0] *= lengthUnit
		buf.xsBuf[i][1] *= lengthUnit
		buf.xsBuf[i][2] *= lengthUnit
	}

	return buf.xsBuf, buf.msBuf, nil
}

func nBodyFlags(h artio.Fileset, fname string) ([]bool, error) {
	speciesLabels := h.GetString(h.Key("particle_species_labels"))
	isNBody, nBodyCount := make([]bool, len(speciesLabels)), 0
	for i := range isNBody {
		isNBody[i] = speciesLabels[i] == "N-BODY"
		nBodyCount++
	}
	if nBodyCount == 0 {
		return nil, fmt.Errorf("ARTIO fileset '%s' does not contain any " +
		"particle species of type 'N-BODY'.", fname)
	}
	return isNBody, nil

}

func (buf *ARTIOBuffer) Close() {
	if !buf.open { panic("Buffer not open.") }
	buf.open = false
}

func (buf *ARTIOBuffer) IsOpen() bool {
	return buf.open
}

func (buf *ARTIOBuffer) ReadHeader(fileNumStr string, out *Header) error {
	xs, _, err := buf.Read(fileNumStr)

	h, err := artio.FilesetOpen(
		buf.fileset, artio.OpenHeader, artio.NullContext,
	)
	if err != nil { return err }
	defer h.Close()

	var h100 float64
	if !h.HasKey("hubble") {
		if emulateHubble {
			h100 = 0.7
		} else {
			return fmt.Errorf(
				"ARTIO header does not contain 'hubble' field.",
			)
		}
	} else {
		h100 = h.GetDouble(h.Key("hubble"))[0]
	}

	out.TotalWidth = h.GetDouble(h.Key("box_size"))[0] *
		(h100 / (cosmo.MpcMks * 100))
	out.Origin, out.Width = boundingBox(xs, out.TotalWidth)
	out.N = int64(len(xs))

	switch {
	case !h.HasKey("auni"):
		return fmt.Errorf("ARTIO header does not contain 'auni' field.")
	case !h.HasKey("OmegaM"):
		return fmt.Errorf("ARTIO header does not contain 'OmegaM' field.")
	case !h.HasKey("OmegaL"):
		return fmt.Errorf("ARTIO header does not contain 'OmegaL' field.")

	}

	out.Cosmo.Z = 1/h.GetDouble(h.Key("auni"))[0] - 1
	out.Cosmo.OmegaM = h.GetDouble(h.Key("OmegaM"))[0]
	out.Cosmo.OmegaL = h.GetDouble(h.Key("OmegaL"))[0]
	out.Cosmo.H100 = h.GetDouble(h.Key("hubble"))[0]

	if out.Cosmo.H100 > 10 {
		panic("Oops, Phil misunderstood the meaning of an ARTIO field. " +
		"Please submit an issue.")
	}

	return nil
}<|endoftext|>


<commit_before>package iptables

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type Action string

const (
	Add    Action = "-A"
	Delete Action = "-D"
)

var (
	ErrIptablesNotFound = errors.New("Iptables not found")
	nat                 = []string{"-t", "nat"}
	supportsXlock       = false
)

type Chain struct {
	Name   string
	Bridge string
}

func init() {
	supportsXlock = exec.Command("iptables", "--wait", "-L", "-n").Run() == nil
}

func NewChain(name, bridge string) (*Chain, error) {
	if output, err := Raw("-t", "nat", "-N", name); err != nil {
		return nil, err
	} else if len(output) != 0 {
		return nil, fmt.Errorf("Error creating new iptables chain: %s", output)
	}
	chain := &Chain{
		Name:   name,
		Bridge: bridge,
	}

	if err := chain.Prerouting(Add, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
	}
	if err := chain.Output(Add, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
	}
	return chain, nil
}

func RemoveExistingChain(name string) error {
	chain := &Chain{
		Name: name,
	}
	return chain.Remove()
}

func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr string, dest_port int) error {
	daddr := ip.String()
	if ip.IsUnspecified() {
		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
		// want "0.0.0.0/0". "0/0" is correctly interpreted as "any
		// value" by both iptables and ip6tables.
		daddr = "0/0"
	}
	if output, err := Raw("-t", "nat", fmt.Sprint(action), c.Name,
		"-p", proto,
		"-d", daddr,
		"--dport", strconv.Itoa(port),
		"!", "-i", c.Bridge,
		"-j", "DNAT",
		"--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port))); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	fAction := action
	if fAction == Add {
		fAction = "-I"
	}
	if output, err := Raw(string(fAction), "FORWARD",
		"!", "-i", c.Bridge,
		"-o", c.Bridge,
		"-p", proto,
		"-d", dest_addr,
		"--dport", strconv.Itoa(dest_port),
		"-j", "ACCEPT"); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	return nil
}

func (c *Chain) Prerouting(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "PREROUTING")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables prerouting: %s", output)
	}
	return nil
}

func (c *Chain) Output(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "OUTPUT")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables output: %s", output)
	}
	return nil
}

func (c *Chain) Remove() error {
	// Ignore errors - This could mean the chains were never set up
	c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL") // Created in versions <= 0.1.6

	c.Prerouting(Delete)
	c.Output(Delete)

	Raw("-t", "nat", "-F", c.Name)
	Raw("-t", "nat", "-X", c.Name)

	return nil
}

// Check if an existing rule exists
func Exists(args ...string) bool {
	if _, err := Raw(append([]string{"-C"}, args...)...); err != nil {
		return false
	}
	return true
}

func Raw(args ...string) ([]byte, error) {
	path, err := exec.LookPath("iptables")
	if err != nil {
		return nil, ErrIptablesNotFound
	}

	if supportsXlock {
		args = append([]string{"--wait"}, args...)
	}

	if os.Getenv("DEBUG") != "" {
		fmt.Printf("[DEBUG] [iptables]: %s, %v\n", path, args)
	}

	output, err := exec.Command(path, args...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
	}

	return output, err
}
<commit_msg>* do not consider iptables' output an error in case of xtables lock Docker-DCO-1.1-Signed-off-by: Giuseppe Mazzotta <gdm85@users.noreply.github.com> (github: gdm85)<commit_after>package iptables

import (
	"errors"
	"fmt"
	"net"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

type Action string

const (
	Add    Action = "-A"
	Delete Action = "-D"
)

var (
	ErrIptablesNotFound = errors.New("Iptables not found")
	nat                 = []string{"-t", "nat"}
	supportsXlock       = false
)

type Chain struct {
	Name   string
	Bridge string
}

func init() {
	supportsXlock = exec.Command("iptables", "--wait", "-L", "-n").Run() == nil
}

func NewChain(name, bridge string) (*Chain, error) {
	if output, err := Raw("-t", "nat", "-N", name); err != nil {
		return nil, err
	} else if len(output) != 0 {
		return nil, fmt.Errorf("Error creating new iptables chain: %s", output)
	}
	chain := &Chain{
		Name:   name,
		Bridge: bridge,
	}

	if err := chain.Prerouting(Add, "-m", "addrtype", "--dst-type", "LOCAL"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in PREROUTING chain: %s", err)
	}
	if err := chain.Output(Add, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8"); err != nil {
		return nil, fmt.Errorf("Failed to inject docker in OUTPUT chain: %s", err)
	}
	return chain, nil
}

func RemoveExistingChain(name string) error {
	chain := &Chain{
		Name: name,
	}
	return chain.Remove()
}

func (c *Chain) Forward(action Action, ip net.IP, port int, proto, dest_addr string, dest_port int) error {
	daddr := ip.String()
	if ip.IsUnspecified() {
		// iptables interprets "0.0.0.0" as "0.0.0.0/32", whereas we
		// want "0.0.0.0/0". "0/0" is correctly interpreted as "any
		// value" by both iptables and ip6tables.
		daddr = "0/0"
	}
	if output, err := Raw("-t", "nat", fmt.Sprint(action), c.Name,
		"-p", proto,
		"-d", daddr,
		"--dport", strconv.Itoa(port),
		"!", "-i", c.Bridge,
		"-j", "DNAT",
		"--to-destination", net.JoinHostPort(dest_addr, strconv.Itoa(dest_port))); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	fAction := action
	if fAction == Add {
		fAction = "-I"
	}
	if output, err := Raw(string(fAction), "FORWARD",
		"!", "-i", c.Bridge,
		"-o", c.Bridge,
		"-p", proto,
		"-d", dest_addr,
		"--dport", strconv.Itoa(dest_port),
		"-j", "ACCEPT"); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables forward: %s", output)
	}

	return nil
}

func (c *Chain) Prerouting(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "PREROUTING")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables prerouting: %s", output)
	}
	return nil
}

func (c *Chain) Output(action Action, args ...string) error {
	a := append(nat, fmt.Sprint(action), "OUTPUT")
	if len(args) > 0 {
		a = append(a, args...)
	}
	if output, err := Raw(append(a, "-j", c.Name)...); err != nil {
		return err
	} else if len(output) != 0 {
		return fmt.Errorf("Error iptables output: %s", output)
	}
	return nil
}

func (c *Chain) Remove() error {
	// Ignore errors - This could mean the chains were never set up
	c.Prerouting(Delete, "-m", "addrtype", "--dst-type", "LOCAL")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL", "!", "--dst", "127.0.0.0/8")
	c.Output(Delete, "-m", "addrtype", "--dst-type", "LOCAL") // Created in versions <= 0.1.6

	c.Prerouting(Delete)
	c.Output(Delete)

	Raw("-t", "nat", "-F", c.Name)
	Raw("-t", "nat", "-X", c.Name)

	return nil
}

// Check if an existing rule exists
func Exists(args ...string) bool {
	if _, err := Raw(append([]string{"-C"}, args...)...); err != nil {
		return false
	}
	return true
}

func Raw(args ...string) ([]byte, error) {
	path, err := exec.LookPath("iptables")
	if err != nil {
		return nil, ErrIptablesNotFound
	}

	if supportsXlock {
		args = append([]string{"--wait"}, args...)
	}

	if os.Getenv("DEBUG") != "" {
		fmt.Printf("[DEBUG] [iptables]: %s, %v\n", path, args)
	}

	output, err := exec.Command(path, args...).CombinedOutput()
	if err != nil {
		return nil, fmt.Errorf("iptables failed: iptables %v: %s (%s)", strings.Join(args, " "), output, err)
	}

	// ignore iptables' message about xtables lock
	if strings.Contains(string(output), "waiting for it to exit") {
		output = []byte("")
	}

	return output, err
}
<|endoftext|>