<commit_before>// Usenet Speedtest
// Try to accurately measure usenet speed.
// tommy@chiparus.org
// This program is in the public domain.
//
// Use like:
// ./speedtest -server your.server.name:119 -user user@name -pass secret -arts 1000 -conns 10
//
// Example Output:
// Read 91537632 bytes in 72.49 seconds. 10.10 mbit.

package main

import (
	"code.google.com/p/chiparus-nntp-go/nntp"
	"flag"
	"fmt"
	"io/ioutil"
	"runtime"
	"sync"
	"time"
)

var user = flag.String("user", "", "Username for server.")
var pass = flag.String("pass", "", "Password for server.")
var server = flag.String("server", "", "NNTP hostname:port.")
var verbose = flag.Bool("v", false, "Be verbose.")
var conns = flag.Int("conns", 1, "Nr of connections.")
var arts = flag.Int64("arts", 100, "Nr of articles.")
var group = flag.String("group", "alt.binaries.boneless", "Newsgroup to use.")
var ssl = flag.Bool("ssl", false, "Use SSL connection.")

var wg sync.WaitGroup

type Connection struct {
	nntp   *nntp.Conn
	closer chan bool
}

func (c *Connection) Connect(q chan string) (err error) {
	if *ssl == true {
		c.nntp, err = nntp.DialTLS("tcp", *server)
	} else {
		c.nntp, err = nntp.Dial("tcp", *server)
	}
	if err != nil {
		panic(err)
	}

	msg := c.nntp.Msg()
	if msg[0] != '2' {
		panic(msg)
	}

	if *user != "" && *pass != "" {
		c.nntp.Authenticate(*user, *pass)
	}

	err = c.nntp.ModeReader()
	if err != nil {
		panic(err)
	}

	c.closer = make(chan bool)
	go c.readQueue(q)

	return nil
}

func (c *Connection) Close() {
	c.closer <- true
}

func (c *Connection) readArt(msgid string) {
	artr, err := c.nntp.ArticleText(msgid)
	if err != nil {
		fmt.Printf("Article: %s %v\n", msgid, err)
	} else {
		art, _ := ioutil.ReadAll(artr)
		lenart := len(art)
		totsize += lenart
		if *verbose {
			fmt.Printf("%p Retrieving article: %s (%d)\n", c, msgid, lenart)
		}
	}
	wg.Done()
}

func (c *Connection) readQueue(q chan string) {
	for {
		select {
		case <-c.closer:
			c.nntp.Quit()
			return
		case msgid := <-q:
			c.readArt(msgid)
		}
	}
}

var totsize = 0

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(8)

	fmt.Printf("Retrieving data for %s..\n", *server)
	var n *nntp.Conn
	var err error
	if *ssl == true {
		n, err = nntp.DialTLS("tcp", *server)
	} else {
		n, err = nntp.Dial("tcp", *server)
	}
	if err != nil {
		panic(err)
	}

	if *user != "" && *pass != "" {
		n.Authenticate(*user, *pass)
	}
	n.ModeReader()

	_, lo, hi, err := n.Group(*group)
	if err != nil {
		panic(err)
	}

	// Start somewhere in the middle.
	lo = lo + (hi-lo)/2
	hi = lo + *arts

	over, err := n.Over(fmt.Sprintf("%d-%d", lo, hi))
	if err != nil {
		panic(err)
	}

	n.Quit()

	fmt.Printf("Starting connections..\n")

	var pool []*Connection
	var queue = make(chan string)

	for i := 0; i < *conns; i++ {
		con := &Connection{}
		con.Connect(queue)
		pool = append(pool, con)
	}

	t0 := time.Now()
	for _, ov := range over {
		queue <- ov.MessageId
		wg.Add(1)
	}

	wg.Wait()

	// Totals
	numsec := float64(time.Now().Sub(t0)) / float64(time.Second)
	size := float64(totsize) * 8.0
	fmt.Printf("Read %d bytes in %.2f seconds. %.2f mbit.\n", totsize, numsec, (size/numsec)/1000/1000)
}
<commit_msg>Update package path, fix an error.<commit_after>// Usenet Speedtest
// Try to accurately measure usenet speed.
// tommy@chiparus.org
// This program is in the public domain.
//
// Use like:
// ./speedtest -server your.server.name:119 -user user@name -pass secret -arts 1000 -conns 10
//
// Example Output:
// Read 91537632 bytes in 72.49 seconds. 10.10 mbit.

package main

import (
	"github.com/tomarus/chiparus-nntp-go/nntp"
	"flag"
	"fmt"
	"io/ioutil"
	"runtime"
	"sync"
	"time"
)

var user = flag.String("user", "", "Username for server.")
var pass = flag.String("pass", "", "Password for server.")
var server = flag.String("server", "", "NNTP hostname:port.")
var verbose = flag.Bool("v", false, "Be verbose.")
var conns = flag.Int("conns", 1, "Nr of connections.")
var arts = flag.Int64("arts", 100, "Nr of articles.")
var group = flag.String("group", "alt.binaries.boneless", "Newsgroup to use.")
var ssl = flag.Bool("ssl", false, "Use SSL connection.")

var wg sync.WaitGroup

type Connection struct {
	nntp   *nntp.Conn
	closer chan bool
}

func (c *Connection) Connect(q chan string) (err error) {
	if *ssl == true {
		c.nntp, err = nntp.DialTLS("tcp", *server)
	} else {
		c.nntp, err = nntp.Dial("tcp", *server)
	}
	if err != nil {
		panic(err)
	}

	msg := c.nntp.Msg()
	if msg[0] != '2' {
		panic(msg)
	}

	if *user != "" && *pass != "" {
		err := c.nntp.Authenticate(*user, *pass)
		if err != nil {
			panic(err)
		}
	}

	err = c.nntp.ModeReader()
	if err != nil {
		panic(err)
	}

	c.closer = make(chan bool)
	go c.readQueue(q)

	return nil
}

func (c *Connection) Close() {
	c.closer <- true
}

func (c *Connection) readArt(msgid string) {
	artr, err := c.nntp.ArticleText(msgid)
	if err != nil {
		fmt.Printf("Article: %s %v\n", msgid, err)
	} else {
		art, _ := ioutil.ReadAll(artr)
		lenart := len(art)
		totsize += lenart
		if *verbose {
			fmt.Printf("%p Retrieving article: %s (%d)\n", c, msgid, lenart)
		}
	}
	wg.Done()
}

func (c *Connection) readQueue(q chan string) {
	for {
		select {
		case <-c.closer:
			c.nntp.Quit()
			return
		case msgid := <-q:
			c.readArt(msgid)
		}
	}
}

var totsize = 0

func main() {
	flag.Parse()
	runtime.GOMAXPROCS(8)

	fmt.Printf("Retrieving data for %s..\n", *server)
	var n *nntp.Conn
	var err error
	if *ssl == true {
		n, err = nntp.DialTLS("tcp", *server)
	} else {
		n, err = nntp.Dial("tcp", *server)
	}
	if err != nil {
		panic(err)
	}

	if *user != "" && *pass != "" {
		n.Authenticate(*user, *pass)
	}
	n.ModeReader()

	_, lo, hi, err := n.Group(*group)
	if err != nil {
		panic(err)
	}

	// Start somewhere in the middle.
	lo = lo + (hi-lo)/2
	hi = lo + *arts

	over, err := n.Over(fmt.Sprintf("%d-%d", lo, hi))
	if err != nil {
		panic(err)
	}

	n.Quit()

	fmt.Printf("Starting connections..\n")

	var pool []*Connection
	var queue = make(chan string)

	for i := 0; i < *conns; i++ {
		con := &Connection{}
		con.Connect(queue)
		pool = append(pool, con)
	}

	t0 := time.Now()
	for _, ov := range over {
		queue <- ov.MessageId
		wg.Add(1)
	}

	wg.Wait()

	// Totals
	numsec := float64(time.Now().Sub(t0)) / float64(time.Second)
	size := float64(totsize) * 8.0
	fmt.Printf("Read %d bytes in %.2f seconds. %.2f mbit.\n", totsize, numsec, (size/numsec)/1000/1000)
}
<|endoftext|>


<commit_before>package sql

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type shard struct {
	db *sql.DB
	shardConn
}

type sqlConn interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
}

type shardConn struct {
	sqlConn
}

func (s *shard) Autocommit(acFun TxFunc) (err error) {
	tx, err := s.db.Begin()
	if err != nil {
		return
	}

	return acFun(&shardConn{tx})
}

func (s *shard) Transact(txFun TxFunc) (err error) {
	tx, err := s.db.Begin()
	if err != nil {
		return
	}

	err = txFun(&shardConn{tx})
	if err != nil {
		rbErr := tx.Rollback()
		if rbErr != nil {
			return errors.New("Rollback error: " + rbErr.Error() + " Query error: " + err.Error())
		}

	} else {
		err = tx.Commit()
		if err != nil {
			return
		}
	}

	return
}

// Query with fixed args
func (s *shardConn) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
	fixArgs(args)
	rows, err = s.sqlConn.Query(query, args...)
	if err != nil {
		err = errors.New("sql.Query Error: " + err.Error() + ". Query: " + query + " Args: " + fmt.Sprint(args))
	}
	return
}

// Execute with fixed args
func (s *shardConn) Exec(query string, args ...interface{}) (res sql.Result, err error) {
	fixArgs(args)
	res, err = s.sqlConn.Exec(query, args...)
	if err != nil {
		err = errors.New("sql.Exec Error: " + err.Error() + ". Query: " + query + " Args: " + fmt.Sprint(args))
	}
	return
}
func IsDuplicateExecError(err error) bool {
	return strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1060: Duplicate column name") ||
		strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1061: Duplicate key name") ||
		strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1050: Table")
}
func (s *shardConn) ExecIgnoreDuplicateError(query string, args ...interface{}) (res sql.Result, err error) {
	res, err = s.Exec(query, args...)
	if err != nil && IsDuplicateExecError(err) {
		err = nil
	}
	return
}

/*
Fix args by converting them to values of their underlying kind.
This avoids problems in database/sql with e.g custom string types.
Without fixArgs, the following code:

	type Foo string
	...
	pool.Query("SELECT * WHERE Foo=?", Foo("bar"))

would give you the error:

	sql: converting Exec argument #1's type: unsupported type Foo, a string
*/
func fixArgs(args []interface{}) {
	for i, arg := range args {
		vArg := reflect.ValueOf(arg)
		switch vArg.Kind() {
		case reflect.String:
			args[i] = vArg.String()
			if args[i] == "" {
				args[i] = nil
			}
		}
	}
}

func (s *shardConn) SelectInt(query string, args ...interface{}) (num int, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectString(query string, args ...interface{}) (str string, err error) {
	found, err := s.queryOne(query, args, &str)
	if err != nil {
		return
	}
	if !found {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectUint(query string, args ...interface{}) (num uint, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectIntForce(query string, args ...interface{}) (num int, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectStringForce(query string, args ...interface{}) (str string, err error) {
	found, err := s.queryOne(query, args, &str)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectUintForce(query string, args ...interface{}) (num uint, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectIntMaybe(query string, args ...interface{}) (num int, found bool, err error) {
	found, err = s.queryOne(query, args, &num)
	return
}

func (s *shardConn) SelectStringMaybe(query string, args ...interface{}) (str string, found bool, err error) {
	found, err = s.queryOne(query, args, &str)
	return
}

func (s *shardConn) SelectUintMaybe(query string, args ...interface{}) (num uint, found bool, err error) {
	found, err = s.queryOne(query, args, &num)
	return
}

func (s *shardConn) queryOne(query string, args []interface{}, out interface{}) (found bool, err error) {
	rows, err := s.Query(query, args...)
	if err != nil {
		return
	}
	defer rows.Close()

	if rows.Next() {
		err = rows.Scan(out)
		if err != nil {
			return
		}
		if rows.Next() {
			err = errors.New("Query returned too many rows")
			return
		}
		found = true
	} else {
		found = false
	}

	err = rows.Err()
	if err != nil {
		return
	}

	return
}

func (s *shardConn) UpdateOne(query string, args ...interface{}) (err error) {
	return s.UpdateNum(1, query, args...)
}

func (s *shardConn) UpdateNum(num int64, query string, args ...interface{}) (err error) {
	rowsAffected, err := s.Update(query, args...)
	if err != nil {
		return
	}
	if rowsAffected != num {
		return errors.New(fmt.Sprint("UpdateOne affected ", rowsAffected, " rows. Query: ", query, " Args: ", args))
	}
	return
}

func (s *shardConn) Update(query string, args ...interface{}) (rowsAffected int64, err error) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}

	rowsAffected, err = res.RowsAffected()
	return
}

func (s *shardConn) InsertIgnoreId(query string, args ...interface{}) (err error) {
	_, err = s.Insert(query, args...)
	return
}

func IsDuplicateEntryError(err error) bool {
	return strings.Contains(err.Error(), "Duplicate entry")
}
func (s *shardConn) InsertIgnoreDuplicates(query string, args ...interface{}) (err error) {
	_, err = s.Insert(query, args...)
	if err != nil && IsDuplicateEntryError(err) {
		err = nil
	}
	return
}

func (s *shardConn) Insert(query string, args ...interface{}) (id int64, err error) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}
	id, err = res.LastInsertId()
	return
}

func (s *shardConn) Select(output interface{}, sql string, args ...interface{}) error {
	// Check types
	var outputPtr = reflect.ValueOf(output)
	if outputPtr.Kind() != reflect.Ptr {
		return errors.New("fun/sql.Select: expects a pointer to a slice of items")
	}
	var outputReflection = reflect.Indirect(outputPtr)
	if outputReflection.Kind() != reflect.Slice {
		return errors.New("fun/sql.Select: expects items to be a slice")
	}
	if outputReflection.Len() != 0 {
		return errors.New("fun/sql.Select: expects items to be empty")
	}
	outputItemType := outputReflection.Type().Elem().Elem()
	if outputItemType.Kind() != reflect.Struct {
		return errors.New("fun/sql.Select: expects items to be a slice of structs")
	}

	// Query DB
	var rows, err = s.Query(sql, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	outputReflection.Set(reflect.MakeSlice(outputReflection.Type(), 0, 0))
	// Reflect onto structs
	columns, err := rows.Columns()
	if err != nil {
		return err
	}

	structType := outputReflection.Type().Elem()
	for rows.Next() {
		structPtrVal := reflect.New(structType.Elem())
		outputItemStructVal := structPtrVal.Elem()
		err = structFromRow(outputItemStructVal, columns, rows, sql)
		if err != nil {
			return err
		}

		outputReflection.Set(reflect.Append(outputReflection, structPtrVal))
	}

	err = rows.Err()
	if err != nil {
		return err
	}

	return nil
}

const scanOneTypeError = "fun/sql.SelectOne: expects a **struct, e.g var person *Person; c.SelectOne(&person, sql)"

func (s *shardConn) SelectOne(output interface{}, query string, args ...interface{}) error {
	return s.scanOne(output, query, true, args...)
}
func (s *shardConn) SelectMaybe(output interface{}, query string, args ...interface{}) error {
	return s.scanOne(output, query, false, args...)
}
func (s *shardConn) scanOne(output interface{}, query string, required bool, args ...interface{}) error {
	// Check types
	var outputReflectionPtr = reflect.ValueOf(output)
	if !outputReflectionPtr.IsValid() {
		panic(scanOneTypeError)
	}
	if outputReflectionPtr.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}
	var outputReflection = outputReflectionPtr.Elem()
	if outputReflection.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}

	// Query DB
	var rows, err = s.Query(query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	// Reflect onto struct
	columns, err := rows.Columns()
	if err != nil {
		return err
	}
	if !rows.Next() {
		if required {
			return errors.New("SelectOne got 0 rows. Query: " + query + " Args: " + fmt.Sprint(args))
		} else {
			return nil
		}
	}

	var vStruct reflect.Value
	if outputReflection.IsNil() {
		structPtrVal := reflect.New(outputReflection.Type().Elem())
		outputReflection.Set(structPtrVal)
		vStruct = structPtrVal.Elem()
	} else {
		vStruct = outputReflection.Elem()
	}

	err = structFromRow(vStruct, columns, rows, query)
	if err != nil {
		return err
	}

	if rows.Next() {
		return errors.New("fun/sql.SelectOne: got multiple rows. Query: " + query + " Args: " + fmt.Sprint(args))
	}

	err = rows.Err()
	if err != nil {
		return err
	}

	return nil
}

type scanError struct {
	err   error
	query string
}

func (s *scanError) Error() string {
	return s.err.Error() + " [SQL: " + s.query + "]"
}

func structFromRow(outputItemStructVal reflect.Value, columns []string, rows *sql.Rows, query string) (err error) {
	vals := make([]interface{}, len(columns))
	for i, _ := range columns {
		vals[i] = &sql.RawBytes{}
		// vals[i] = &[]byte{}
	}
	err = rows.Scan(vals...)
	if err != nil {
		err = &scanError{err, query}
		return
	}

	var uintVal uint64
	var intVal int64
	for i, column := range columns {
		bytes := []byte(*vals[i].(*sql.RawBytes))
		// bytes := []byte(*vals[i].(*[]byte))
		if bytes == nil {
			continue // Leave struct field empty
		}
		var outputItemField = outputItemStructVal.FieldByName(column)
		switch outputItemField.Kind() {
		case reflect.String:
			outputItemField.SetString(string(bytes))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			uintVal, err = strconv.ParseUint(string(bytes), 10, 64)
			if err != nil {
				return
			}
			outputItemField.SetUint(reflect.ValueOf(uintVal).Uint())
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			intVal, err = strconv.ParseInt(string(bytes), 10, 64)
			if err != nil {
				return
			}
			outputItemField.SetInt(reflect.ValueOf(intVal).Int())
		default:
			if outputItemField.Kind() == reflect.Slice { // && outputItemField. == reflect.Uint8 {
				// byte slice
				outputItemField.SetBytes(bytes)
			} else {
				err = errors.New("fun/sql: Bad row value for column " + column + ": " + outputItemField.Kind().String())
				return
			}
		}
	}

	return
}
<commit_msg>Handle NULL values explicitly in SelectString<commit_after>package sql

import (
	"database/sql"
	"errors"
	"fmt"
	"reflect"
	"strconv"
	"strings"
)

type shard struct {
	db *sql.DB
	shardConn
}

type sqlConn interface {
	Exec(query string, args ...interface{}) (sql.Result, error)
	Query(query string, args ...interface{}) (*sql.Rows, error)
}

type shardConn struct {
	sqlConn
}

func (s *shard) Autocommit(acFun TxFunc) (err error) {
	tx, err := s.db.Begin()
	if err != nil {
		return
	}

	return acFun(&shardConn{tx})
}

func (s *shard) Transact(txFun TxFunc) (err error) {
	tx, err := s.db.Begin()
	if err != nil {
		return
	}

	err = txFun(&shardConn{tx})
	if err != nil {
		rbErr := tx.Rollback()
		if rbErr != nil {
			return errors.New("Rollback error: " + rbErr.Error() + " Query error: " + err.Error())
		}

	} else {
		err = tx.Commit()
		if err != nil {
			return
		}
	}

	return
}

// Query with fixed args
func (s *shardConn) Query(query string, args ...interface{}) (rows *sql.Rows, err error) {
	fixArgs(args)
	rows, err = s.sqlConn.Query(query, args...)
	if err != nil {
		err = errors.New("sql.Query Error: " + err.Error() + ". Query: " + query + " Args: " + fmt.Sprint(args))
	}
	return
}

// Execute with fixed args
func (s *shardConn) Exec(query string, args ...interface{}) (res sql.Result, err error) {
	fixArgs(args)
	res, err = s.sqlConn.Exec(query, args...)
	if err != nil {
		err = errors.New("sql.Exec Error: " + err.Error() + ". Query: " + query + " Args: " + fmt.Sprint(args))
	}
	return
}
func IsDuplicateExecError(err error) bool {
	return strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1060: Duplicate column name") ||
		strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1061: Duplicate key name") ||
		strings.HasPrefix(err.Error(), "sql.Exec Error: Error 1050: Table")
}
func (s *shardConn) ExecIgnoreDuplicateError(query string, args ...interface{}) (res sql.Result, err error) {
	res, err = s.Exec(query, args...)
	if err != nil && IsDuplicateExecError(err) {
		err = nil
	}
	return
}

/*
Fix args by converting them to values of their underlying kind.
This avoids problems in database/sql with e.g custom string types.
Without fixArgs, the following code:

	type Foo string
	...
	pool.Query("SELECT * WHERE Foo=?", Foo("bar"))

would give you the error:

	sql: converting Exec argument #1's type: unsupported type Foo, a string
*/
func fixArgs(args []interface{}) {
	for i, arg := range args {
		vArg := reflect.ValueOf(arg)
		switch vArg.Kind() {
		case reflect.String:
			args[i] = vArg.String()
			if args[i] == "" {
				args[i] = nil
			}
		}
	}
}

func (s *shardConn) SelectInt(query string, args ...interface{}) (num int, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectString(query string, args ...interface{}) (str string, err error) {
	var nullStr sql.NullString
	found, err := s.queryOne(query, args, &nullStr)
	if err != nil {
		return
	}
	if found {
		str = nullStr.String
	} else {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectUint(query string, args ...interface{}) (num uint, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		err = errors.New("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectIntForce(query string, args ...interface{}) (num int, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectStringForce(query string, args ...interface{}) (str string, err error) {
	found, err := s.queryOne(query, args, &str)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectUintForce(query string, args ...interface{}) (num uint, err error) {
	found, err := s.queryOne(query, args, &num)
	if err != nil {
		return
	}
	if !found {
		panic("Query returned no rows: " + query)
	}
	return
}

func (s *shardConn) SelectIntMaybe(query string, args ...interface{}) (num int, found bool, err error) {
	found, err = s.queryOne(query, args, &num)
	return
}

func (s *shardConn) SelectStringMaybe(query string, args ...interface{}) (str string, found bool, err error) {
	found, err = s.queryOne(query, args, &str)
	return
}

func (s *shardConn) SelectUintMaybe(query string, args ...interface{}) (num uint, found bool, err error) {
	found, err = s.queryOne(query, args, &num)
	return
}

func (s *shardConn) queryOne(query string, args []interface{}, out interface{}) (found bool, err error) {
	rows, err := s.Query(query, args...)
	if err != nil {
		return
	}
	defer rows.Close()

	if rows.Next() {
		err = rows.Scan(out)
		if err != nil {
			return
		}
		if rows.Next() {
			err = errors.New("Query returned too many rows")
			return
		}
		found = true
	} else {
		found = false
	}

	err = rows.Err()
	if err != nil {
		return
	}

	return
}

func (s *shardConn) UpdateOne(query string, args ...interface{}) (err error) {
	return s.UpdateNum(1, query, args...)
}

func (s *shardConn) UpdateNum(num int64, query string, args ...interface{}) (err error) {
	rowsAffected, err := s.Update(query, args...)
	if err != nil {
		return
	}
	if rowsAffected != num {
		return errors.New(fmt.Sprint("UpdateOne affected ", rowsAffected, " rows. Query: ", query, " Args: ", args))
	}
	return
}

func (s *shardConn) Update(query string, args ...interface{}) (rowsAffected int64, err error) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}

	rowsAffected, err = res.RowsAffected()
	return
}

func (s *shardConn) InsertIgnoreId(query string, args ...interface{}) (err error) {
	_, err = s.Insert(query, args...)
	return
}

func IsDuplicateEntryError(err error) bool {
	return strings.Contains(err.Error(), "Duplicate entry")
}
func (s *shardConn) InsertIgnoreDuplicates(query string, args ...interface{}) (err error) {
	_, err = s.Insert(query, args...)
	if err != nil && IsDuplicateEntryError(err) {
		err = nil
	}
	return
}

func (s *shardConn) Insert(query string, args ...interface{}) (id int64, err error) {
	res, err := s.Exec(query, args...)
	if err != nil {
		return
	}
	id, err = res.LastInsertId()
	return
}

func (s *shardConn) Select(output interface{}, sql string, args ...interface{}) error {
	// Check types
	var outputPtr = reflect.ValueOf(output)
	if outputPtr.Kind() != reflect.Ptr {
		return errors.New("fun/sql.Select: expects a pointer to a slice of items")
	}
	var outputReflection = reflect.Indirect(outputPtr)
	if outputReflection.Kind() != reflect.Slice {
		return errors.New("fun/sql.Select: expects items to be a slice")
	}
	if outputReflection.Len() != 0 {
		return errors.New("fun/sql.Select: expects items to be empty")
	}
	outputItemType := outputReflection.Type().Elem().Elem()
	if outputItemType.Kind() != reflect.Struct {
		return errors.New("fun/sql.Select: expects items to be a slice of structs")
	}

	// Query DB
	var rows, err = s.Query(sql, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	outputReflection.Set(reflect.MakeSlice(outputReflection.Type(), 0, 0))
	// Reflect onto structs
	columns, err := rows.Columns()
	if err != nil {
		return err
	}

	structType := outputReflection.Type().Elem()
	for rows.Next() {
		structPtrVal := reflect.New(structType.Elem())
		outputItemStructVal := structPtrVal.Elem()
		err = structFromRow(outputItemStructVal, columns, rows, sql)
		if err != nil {
			return err
		}

		outputReflection.Set(reflect.Append(outputReflection, structPtrVal))
	}

	err = rows.Err()
	if err != nil {
		return err
	}

	return nil
}

const scanOneTypeError = "fun/sql.SelectOne: expects a **struct, e.g var person *Person; c.SelectOne(&person, sql)"

func (s *shardConn) SelectOne(output interface{}, query string, args ...interface{}) error {
	return s.scanOne(output, query, true, args...)
}
func (s *shardConn) SelectMaybe(output interface{}, query string, args ...interface{}) error {
	return s.scanOne(output, query, false, args...)
}
func (s *shardConn) scanOne(output interface{}, query string, required bool, args ...interface{}) error {
	// Check types
	var outputReflectionPtr = reflect.ValueOf(output)
	if !outputReflectionPtr.IsValid() {
		panic(scanOneTypeError)
	}
	if outputReflectionPtr.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}
	var outputReflection = outputReflectionPtr.Elem()
	if outputReflection.Kind() != reflect.Ptr {
		panic(scanOneTypeError)
	}

	// Query DB
	var rows, err = s.Query(query, args...)
	if err != nil {
		return err
	}
	defer rows.Close()

	// Reflect onto struct
	columns, err := rows.Columns()
	if err != nil {
		return err
	}
	if !rows.Next() {
		if required {
			return errors.New("SelectOne got 0 rows. Query: " + query + " Args: " + fmt.Sprint(args))
		} else {
			return nil
		}
	}

	var vStruct reflect.Value
	if outputReflection.IsNil() {
		structPtrVal := reflect.New(outputReflection.Type().Elem())
		outputReflection.Set(structPtrVal)
		vStruct = structPtrVal.Elem()
	} else {
		vStruct = outputReflection.Elem()
	}

	err = structFromRow(vStruct, columns, rows, query)
	if err != nil {
		return err
	}

	if rows.Next() {
		return errors.New("fun/sql.SelectOne: got multiple rows. Query: " + query + " Args: " + fmt.Sprint(args))
	}

	err = rows.Err()
	if err != nil {
		return err
	}

	return nil
}

type scanError struct {
	err   error
	query string
}

func (s *scanError) Error() string {
	return s.err.Error() + " [SQL: " + s.query + "]"
}

func structFromRow(outputItemStructVal reflect.Value, columns []string, rows *sql.Rows, query string) (err error) {
	vals := make([]interface{}, len(columns))
	for i, _ := range columns {
		vals[i] = &sql.RawBytes{}
		// vals[i] = &[]byte{}
	}
	err = rows.Scan(vals...)
	if err != nil {
		err = &scanError{err, query}
		return
	}

	var uintVal uint64
	var intVal int64
	for i, column := range columns {
		bytes := []byte(*vals[i].(*sql.RawBytes))
		// bytes := []byte(*vals[i].(*[]byte))
		if bytes == nil {
			continue // Leave struct field empty
		}
		var outputItemField = outputItemStructVal.FieldByName(column)
		switch outputItemField.Kind() {
		case reflect.String:
			outputItemField.SetString(string(bytes))
		case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
			uintVal, err = strconv.ParseUint(string(bytes), 10, 64)
			if err != nil {
				return
			}
			outputItemField.SetUint(reflect.ValueOf(uintVal).Uint())
		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
			intVal, err = strconv.ParseInt(string(bytes), 10, 64)
			if err != nil {
				return
			}
			outputItemField.SetInt(reflect.ValueOf(intVal).Int())
		default:
			if outputItemField.Kind() == reflect.Slice { // && outputItemField. == reflect.Uint8 {
				// byte slice
				outputItemField.SetBytes(bytes)
			} else {
				err = errors.New("fun/sql: Bad row value for column " + column + ": " + outputItemField.Kind().String())
				return
			}
		}
	}

	return
}
<|endoftext|>


<commit_before>package gosql

import . "github.com/suboat/go-sql-kit"

func OrderStringJSONtoSQL(str string) (string, error) {
	return "", nil
}

type SQLOrderRoot struct {
	OrderRoot
}

func (o *SQLOrderRoot) String() (statement string) {
	if o.Value == nil || len(o.Value) == 0 {
		return
	}
	for _, iv := range o.Value {
		if v, ok := iv.(OrderValue); ok {
			v.Field
		}
	}

	return ""
}
<commit_msg>feat: order sql<commit_after>package gosql

import (
	. "github.com/suboat/go-sql-kit"
	"strings"
)

type SQLOrder struct {
	RuleMapping
	OrderRoot
}

func NewSQLOrder() *SQLOrder {
	return new(SQLOrder)
}

func (s *SQLOrder) String() string {
	if s.Value == nil || len(s.Value) == 0 {
		return ""
	}
	set := make([]string, 0, len(s.Value))
	for _, iv := range s.Value {
		if v, ok := iv.(*OrderValue); ok {
			if s.IsAllowed(v.Field) {
				if v.IsASC() {
					set = append(set, s.GetMapping(v.Field)+" ASC")
				} else {
					set = append(set, s.GetMapping(v.Field)+" DESC")
				}
			}
		}
	}
	if len(set) == 0 {
		return ""
	}
	return "ORDER BY " + strings.Join(set, ", ")
}

func (s *SQLOrder) JSONStringToSQL(str string) (string, error) {
	if err := s.ParseJSONString(str); err != nil {
		return "", err
	}
	return s.String(), nil
}

func (s *SQLOrder) JSONStringsToSQL(strs []string) (string, error) {
	if err := s.ParseJSONStrings(strs); err != nil {
		return "", err
	}
	return s.String(), nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"time"
)

type AliveRequest struct {
	DeviceID string `json:"device_id"`
	Timeout  int32  `json:"timeout"`
}

type DeviceTimer struct {
	DeviceID    string
	DeviceTimer *time.Timer
}

func (timer DeviceTimer) startTimer() {
	<-timer.DeviceTimer.C
	notifyDeviceTimerExpired(timer.DeviceID)
}

var timers_map = make(map[string]DeviceTimer)

func notifyDeviceTimerExpired(device_id string) {
	log.Printf("DeviceID: %s expired!\n", device_id)
	return
}

func handleAlivePost(rw http.ResponseWriter, request *http.Request) {
	aliverequest := parseAlivePost(request.Body)
	log.Printf("DeviceID: %s, Timeout: %d\n", aliverequest.DeviceID, aliverequest.Timeout)

	timer, timer_found := timers_map[aliverequest.DeviceID]

	if timer_found {
		timer.DeviceTimer.Reset(time.Millisecond * time.Duration(aliverequest.Timeout))
	} else {
		timer := time.NewTimer(time.Millisecond * time.Duration(aliverequest.Timeout))
		device_timer := DeviceTimer{aliverequest.DeviceID, timer}
		timers_map[aliverequest.DeviceID] = device_timer
		go device_timer.startTimer()
	}
}

func parseAlivePost(body io.ReadCloser) AliveRequest {
	aliverequest_decoder := json.NewDecoder(body)

	var aliverequest AliveRequest
	err_aliverequest := aliverequest_decoder.Decode(&aliverequest)

	if err_aliverequest != nil {
		log.Fatalf("Error decoding aliverequest: %s", err_aliverequest)
	}

	return aliverequest
}

func main() {
	log.Println("Starting AliveIM service...")
	http.HandleFunc("/", handleAlivePost)
	http.ListenAndServe("localhost:5000", nil)
}
<commit_msg>Remove DeviceTimer from memory if expired<commit_after>package main

import (
	"encoding/json"
	"io"
	"log"
	"net/http"
	"time"
)

type AliveRequest struct {
	DeviceID string `json:"device_id"`
	Timeout  int32  `json:"timeout"`
}

type DeviceTimer struct {
	DeviceID    string
	DeviceTimer *time.Timer
}

func (timer DeviceTimer) startTimer() {
	<-timer.DeviceTimer.C
	notifyDeviceTimerExpired(timer.DeviceID)
}

var timers_map = make(map[string]DeviceTimer)

func notifyDeviceTimerExpired(device_id string) {
	log.Printf("DeviceID: %s expired!\n", device_id)
	delete(timers_map, device_id)
	return
}

func handleAlivePost(rw http.ResponseWriter, request *http.Request) {
	aliverequest := parseAlivePost(request.Body)
	log.Printf("DeviceID: %s, Timeout: %d\n", aliverequest.DeviceID, aliverequest.Timeout)

	timer, timer_found := timers_map[aliverequest.DeviceID]

	if timer_found {
		timer.DeviceTimer.Reset(time.Millisecond * time.Duration(aliverequest.Timeout))
	} else {
		timer := time.NewTimer(time.Millisecond * time.Duration(aliverequest.Timeout))
		device_timer := DeviceTimer{aliverequest.DeviceID, timer}
		timers_map[aliverequest.DeviceID] = device_timer
		go device_timer.startTimer()
	}
}

func parseAlivePost(body io.ReadCloser) AliveRequest {
	aliverequest_decoder := json.NewDecoder(body)

	var aliverequest AliveRequest
	err_aliverequest := aliverequest_decoder.Decode(&aliverequest)

	if err_aliverequest != nil {
		log.Fatalf("Error decoding aliverequest: %s", err_aliverequest)
	}

	return aliverequest
}

func main() {
	log.Println("Starting AliveIM service...")
	http.HandleFunc("/", handleAlivePost)
	http.ListenAndServe("localhost:5000", nil)
}
<|endoftext|>


<commit_before>package api

import(
  "net/http"
  "encoding/json"
)

type Book struct {
  Id          string  `json:"id"`
  Title       string  `json:"title"`
  Description string  `json:"description"`
  Color       string  `json:"color"`
}

type Api struct {
  RootPath string
}

func New(rootPath string) http.Handler {
  return Api{rootPath};
}

func (s Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  book := Book{"1", "Dark river", "The story of ...", "blue"}
  books := []Book{book}

  json.NewEncoder(w).Encode(books)
}
<commit_msg>Some wishful thinking types<commit_after>package api

import(
  "net/http"
  "encoding/json"
)

type Book struct {
  Id          string  `json:"id"`
  Title       string  `json:"title"`
  Description string  `json:"description"`
  Color       string  `json:"color"`
}

type Page struct {
  Id        int       `json:"id"`
  Text      string    `json:"text"`
  Choices   []Choice  `json:"choices"`
}

type Choice struct {
  Id         int      `json:"id"`
  Text       string   `json:"text"`
  NextPageId int      `json:"nextPageId"`
}

type Api struct {
  RootPath string
}

func New(rootPath string) http.Handler {
  return Api{rootPath};
}

func (s Api) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  book := Book{"1", "Dark river", "The story of ...", "blue"}
  books := []Book{book}

  json.NewEncoder(w).Encode(books)
}
<|endoftext|>


<commit_before>package api

import (
	"github.com/gorilla/securecookie"
	"github.com/jllopis/try5/store"
	"github.com/mgutz/logxi/v1"
	"github.com/unrolled/render"
)

type ApiContext struct {
	DB            store.Storer
	Render        *render.Render
	CookieHandler *securecookie.SecureCookie
}

type logMessage struct {
	Status string `json:"status"`
	Action string `json:"action"`
	Info   string `json:"info,omitempty"`
	Table  string `json:"table,omitempty"`
	Code   string `json:"code,omitempty"`
	ID     int64  `json:"id,omitempty"`
}

var logger log.Logger

func init() {
	logger = log.New("try5")
}
<commit_msg>renamed ID to UID as string<commit_after>package api

import (
	"github.com/gorilla/securecookie"
	"github.com/jllopis/try5/store"
	"github.com/mgutz/logxi/v1"
	"github.com/unrolled/render"
)

type ApiContext struct {
	DB            store.Storer
	Render        *render.Render
	CookieHandler *securecookie.SecureCookie
}

type logMessage struct {
	Status string `json:"status"`
	Action string `json:"action"`
	Info   string `json:"info,omitempty"`
	Table  string `json:"table,omitempty"`
	Code   string `json:"code,omitempty"`
	UID    string `json:"id,omitempty"`
}

var logger log.Logger

func init() {
	logger = log.New("try5")
}
<|endoftext|>


<commit_before>package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/stretchr/graceful"
)

const (
	apiTimeout = 5 * time.Second
)

// handleHTTPRequest is a wrapper function that handles all incoming calls to
// the API.
func handleHTTPRequest(mux *http.ServeMux, url string, handler http.HandlerFunc) {
	mux.HandleFunc(url, func(w http.ResponseWriter, req *http.Request) {
		// prevent access from sources other than siac and Sia-UI
		if !strings.Contains(req.UserAgent(), "Sia-Agent") && !strings.Contains(req.UserAgent(), "Sia-Miner") && req.UserAgent() != "" && !strings.Contains(req.UserAgent(), "Electron") && !strings.Contains(req.UserAgent(), "AtomShell") {
			writeError(w, "Browser access disabled due to security vulnerability. Use Sia-UI or siac.", http.StatusInternalServerError)
			return
		}
		handler(w, req)
	})
}

// initAPI determines which functions handle each API call.
func (srv *Server) initAPI(addr string) {
	mux := http.NewServeMux()

	// 404 Calls
	handleHTTPRequest(mux, "/", srv.unrecognizedCallHandler)

	// Daemon API Calls - Unfinished
	handleHTTPRequest(mux, "/daemon/constants", srv.daemonConstantsHandler)
	handleHTTPRequest(mux, "/daemon/stop", srv.daemonStopHandler)
	handleHTTPRequest(mux, "/daemon/version", srv.daemonVersionHandler)
	handleHTTPRequest(mux, "/daemon/updates/apply", srv.daemonUpdatesApplyHandler)
	handleHTTPRequest(mux, "/daemon/updates/check", srv.daemonUpdatesCheckHandler)

	// Consensus API Calls
	if srv.cs != nil {
		handleHTTPRequest(mux, "/consensus", srv.consensusHandler) // GET
	}

	// Gateway API Calls - Unfinished
	if srv.gateway != nil {
		handleHTTPRequest(mux, "/gateway/status", srv.gatewayStatusHandler)
		handleHTTPRequest(mux, "/gateway/peers/add", srv.gatewayPeersAddHandler)
		handleHTTPRequest(mux, "/gateway/peers/remove", srv.gatewayPeersRemoveHandler)
	}

	// Host API Calls - Unfinished
	if srv.host != nil {
		handleHTTPRequest(mux, "/host/announce", srv.hostAnnounceHandler)
		handleHTTPRequest(mux, "/host/configure", srv.hostConfigureHandler)
		handleHTTPRequest(mux, "/host/status", srv.hostStatusHandler)
	}

	// HostDB API Calls - Unfinished
	if srv.hostdb != nil {
		handleHTTPRequest(mux, "/hostdb/hosts/active", srv.hostdbHostsActiveHandler)
		handleHTTPRequest(mux, "/hostdb/hosts/all", srv.hostdbHostsAllHandler)
	}

	// Miner API Calls - Unfinished
	if srv.miner != nil {
		handleHTTPRequest(mux, "/miner/start", srv.minerStartHandler)
		handleHTTPRequest(mux, "/miner/status", srv.minerStatusHandler)
		handleHTTPRequest(mux, "/miner/stop", srv.minerStopHandler)
		handleHTTPRequest(mux, "/miner/blockforwork", srv.minerBlockforworkHandler)
		handleHTTPRequest(mux, "/miner/submitblock", srv.minerSubmitblockHandler)
		handleHTTPRequest(mux, "/miner/headerforwork", srv.minerHeaderforworkHandler)
		handleHTTPRequest(mux, "/miner/submitheader", srv.minerSubmitheaderHandler)
	}

	// Renter API Calls - Unfinished
	if srv.renter != nil {
		handleHTTPRequest(mux, "/renter/downloadqueue", srv.renterDownloadqueueHandler)
		handleHTTPRequest(mux, "/renter/files/delete", srv.renterFilesDeleteHandler)
		handleHTTPRequest(mux, "/renter/files/download", srv.renterFilesDownloadHandler)
		handleHTTPRequest(mux, "/renter/files/list", srv.renterFilesListHandler)
		handleHTTPRequest(mux, "/renter/files/load", srv.renterFilesLoadHandler)
		handleHTTPRequest(mux, "/renter/files/loadascii", srv.renterFilesLoadAsciiHandler)
		handleHTTPRequest(mux, "/renter/files/rename", srv.renterFilesRenameHandler)
		handleHTTPRequest(mux, "/renter/files/share", srv.renterFilesShareHandler)
		handleHTTPRequest(mux, "/renter/files/shareascii", srv.renterFilesShareAsciiHandler)
		handleHTTPRequest(mux, "/renter/files/upload", srv.renterFilesUploadHandler)
		handleHTTPRequest(mux, "/renter/status", srv.renterStatusHandler)
	}

	// TransactionPool API Calls - Unfinished
	if srv.tpool != nil {
		handleHTTPRequest(mux, "/transactionpool/transactions", srv.transactionpoolTransactionsHandler)
	}

	// Wallet API Calls
	if srv.wallet != nil {
		handleHTTPRequest(mux, "/wallet", srv.walletHandler)                           // GET
		handleHTTPRequest(mux, "/wallet/address", srv.walletAddressHandler)            // GET
		handleHTTPRequest(mux, "/wallet/addresses", srv.walletAddressesHandler)        // GET
		handleHTTPRequest(mux, "/wallet/backup", srv.walletBackupHandler)              // POST
		handleHTTPRequest(mux, "/wallet/encrypt", srv.walletEncryptHandler)            // POST - COMPATv0.4.0
		handleHTTPRequest(mux, "/wallet/init", srv.walletInitHandler)                  // POST
		handleHTTPRequest(mux, "/wallet/load/033x", srv.walletLoad033xHandler)         // POST
		handleHTTPRequest(mux, "/wallet/load/seed", srv.walletLoadSeedHandler)         // POST
		handleHTTPRequest(mux, "/wallet/lock", srv.walletLockHandler)                  // POST
		handleHTTPRequest(mux, "/wallet/seeds", srv.walletSeedsHandler)                // GET
		handleHTTPRequest(mux, "/wallet/siacoins", srv.walletSiacoinsHandler)          // POST
		handleHTTPRequest(mux, "/wallet/siafunds", srv.walletSiafundsHandler)          // POST
		handleHTTPRequest(mux, "/wallet/transaction/", srv.walletTransactionHandler)   // $(id) GET
		handleHTTPRequest(mux, "/wallet/transactions", srv.walletTransactionsHandler)  // GET
		handleHTTPRequest(mux, "/wallet/transactions/", srv.walletTransactionsHandler) // $(addr) GET
		handleHTTPRequest(mux, "/wallet/unlock", srv.walletUnlockHandler)              // POST
	}

	// BlockExplorer API Calls - Unfinished
	if srv.exp != nil {
		handleHTTPRequest(mux, "/explorer/status", srv.explorerStatusHandler)
		handleHTTPRequest(mux, "/explorer/blockdata", srv.explorerBlockDataHandler)
		handleHTTPRequest(mux, "/explorer/gethash", srv.explorerGetHashHandler)
	}

	// Create graceful HTTP server
	srv.apiServer = &graceful.Server{
		Timeout: apiTimeout,
		Server:  &http.Server{Addr: addr, Handler: mux},
	}
}

// unrecognizedCallHandler handles calls to unknown pages (404).
func (srv *Server) unrecognizedCallHandler(w http.ResponseWriter, req *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, "404 - Refer to API.md")
}

// writeError an error to the API caller.
func writeError(w http.ResponseWriter, msg string, err int) {
	http.Error(w, msg, err)
}

// writeJSON writes the object to the ResponseWriter. If the encoding fails, an
// error is written instead.
func writeJSON(w http.ResponseWriter, obj interface{}) {
	if json.NewEncoder(w).Encode(obj) != nil {
		http.Error(w, "Failed to encode response", http.StatusInternalServerError)
	}
}

// writeSuccess writes the success json object ({"Success":true}) to the
// ResponseWriter
func writeSuccess(w http.ResponseWriter) {
	writeJSON(w, struct{ Success bool }{true})
}
<commit_msg>Revert "Remove default go user-agent"<commit_after>package api

import (
	"encoding/json"
	"fmt"
	"net/http"
	"strings"
	"time"

	"github.com/stretchr/graceful"
)

const (
	apiTimeout = 5 * time.Second
)

// handleHTTPRequest is a wrapper function that handles all incoming calls to
// the API.
func handleHTTPRequest(mux *http.ServeMux, url string, handler http.HandlerFunc) {
	mux.HandleFunc(url, func(w http.ResponseWriter, req *http.Request) {
		// prevent access from sources other than siac and Sia-UI
		if !strings.Contains(req.UserAgent(), "Sia-Agent") && !strings.Contains(req.UserAgent(), "Sia-Miner") && req.UserAgent() != "" && req.UserAgent() != "Go 1.1 package http" && !strings.Contains(req.UserAgent(), "Electron") && !strings.Contains(req.UserAgent(), "AtomShell") {
			writeError(w, "Browser access disabled due to security vulnerability. Use Sia-UI or siac.", http.StatusInternalServerError)
			return
		}
		handler(w, req)
	})
}

// initAPI determines which functions handle each API call.
func (srv *Server) initAPI(addr string) {
	mux := http.NewServeMux()

	// 404 Calls
	handleHTTPRequest(mux, "/", srv.unrecognizedCallHandler)

	// Daemon API Calls - Unfinished
	handleHTTPRequest(mux, "/daemon/constants", srv.daemonConstantsHandler)
	handleHTTPRequest(mux, "/daemon/stop", srv.daemonStopHandler)
	handleHTTPRequest(mux, "/daemon/version", srv.daemonVersionHandler)
	handleHTTPRequest(mux, "/daemon/updates/apply", srv.daemonUpdatesApplyHandler)
	handleHTTPRequest(mux, "/daemon/updates/check", srv.daemonUpdatesCheckHandler)

	// Consensus API Calls
	if srv.cs != nil {
		handleHTTPRequest(mux, "/consensus", srv.consensusHandler) // GET
	}

	// Gateway API Calls - Unfinished
	if srv.gateway != nil {
		handleHTTPRequest(mux, "/gateway/status", srv.gatewayStatusHandler)
		handleHTTPRequest(mux, "/gateway/peers/add", srv.gatewayPeersAddHandler)
		handleHTTPRequest(mux, "/gateway/peers/remove", srv.gatewayPeersRemoveHandler)
	}

	// Host API Calls - Unfinished
	if srv.host != nil {
		handleHTTPRequest(mux, "/host/announce", srv.hostAnnounceHandler)
		handleHTTPRequest(mux, "/host/configure", srv.hostConfigureHandler)
		handleHTTPRequest(mux, "/host/status", srv.hostStatusHandler)
	}

	// HostDB API Calls - Unfinished
	if srv.hostdb != nil {
		handleHTTPRequest(mux, "/hostdb/hosts/active", srv.hostdbHostsActiveHandler)
		handleHTTPRequest(mux, "/hostdb/hosts/all", srv.hostdbHostsAllHandler)
	}

	// Miner API Calls - Unfinished
	if srv.miner != nil {
		handleHTTPRequest(mux, "/miner/start", srv.minerStartHandler)
		handleHTTPRequest(mux, "/miner/status", srv.minerStatusHandler)
		handleHTTPRequest(mux, "/miner/stop", srv.minerStopHandler)
		handleHTTPRequest(mux, "/miner/blockforwork", srv.minerBlockforworkHandler)
		handleHTTPRequest(mux, "/miner/submitblock", srv.minerSubmitblockHandler)
		handleHTTPRequest(mux, "/miner/headerforwork", srv.minerHeaderforworkHandler)
		handleHTTPRequest(mux, "/miner/submitheader", srv.minerSubmitheaderHandler)
	}

	// Renter API Calls - Unfinished
	if srv.renter != nil {
		handleHTTPRequest(mux, "/renter/downloadqueue", srv.renterDownloadqueueHandler)
		handleHTTPRequest(mux, "/renter/files/delete", srv.renterFilesDeleteHandler)
		handleHTTPRequest(mux, "/renter/files/download", srv.renterFilesDownloadHandler)
		handleHTTPRequest(mux, "/renter/files/list", srv.renterFilesListHandler)
		handleHTTPRequest(mux, "/renter/files/load", srv.renterFilesLoadHandler)
		handleHTTPRequest(mux, "/renter/files/loadascii", srv.renterFilesLoadAsciiHandler)
		handleHTTPRequest(mux, "/renter/files/rename", srv.renterFilesRenameHandler)
		handleHTTPRequest(mux, "/renter/files/share", srv.renterFilesShareHandler)
		handleHTTPRequest(mux, "/renter/files/shareascii", srv.renterFilesShareAsciiHandler)
		handleHTTPRequest(mux, "/renter/files/upload", srv.renterFilesUploadHandler)
		handleHTTPRequest(mux, "/renter/status", srv.renterStatusHandler)
	}

	// TransactionPool API Calls - Unfinished
	if srv.tpool != nil {
		handleHTTPRequest(mux, "/transactionpool/transactions", srv.transactionpoolTransactionsHandler)
	}

	// Wallet API Calls
	if srv.wallet != nil {
		handleHTTPRequest(mux, "/wallet", srv.walletHandler)                           // GET
		handleHTTPRequest(mux, "/wallet/address", srv.walletAddressHandler)            // GET
		handleHTTPRequest(mux, "/wallet/addresses", srv.walletAddressesHandler)        // GET
		handleHTTPRequest(mux, "/wallet/backup", srv.walletBackupHandler)              // POST
		handleHTTPRequest(mux, "/wallet/encrypt", srv.walletEncryptHandler)            // POST - COMPATv0.4.0
		handleHTTPRequest(mux, "/wallet/init", srv.walletInitHandler)                  // POST
		handleHTTPRequest(mux, "/wallet/load/033x", srv.walletLoad033xHandler)         // POST
		handleHTTPRequest(mux, "/wallet/load/seed", srv.walletLoadSeedHandler)         // POST
		handleHTTPRequest(mux, "/wallet/lock", srv.walletLockHandler)                  // POST
		handleHTTPRequest(mux, "/wallet/seeds", srv.walletSeedsHandler)                // GET
		handleHTTPRequest(mux, "/wallet/siacoins", srv.walletSiacoinsHandler)          // POST
		handleHTTPRequest(mux, "/wallet/siafunds", srv.walletSiafundsHandler)          // POST
		handleHTTPRequest(mux, "/wallet/transaction/", srv.walletTransactionHandler)   // $(id) GET
		handleHTTPRequest(mux, "/wallet/transactions", srv.walletTransactionsHandler)  // GET
		handleHTTPRequest(mux, "/wallet/transactions/", srv.walletTransactionsHandler) // $(addr) GET
		handleHTTPRequest(mux, "/wallet/unlock", srv.walletUnlockHandler)              // POST
	}

	// BlockExplorer API Calls - Unfinished
	if srv.exp != nil {
		handleHTTPRequest(mux, "/explorer/status", srv.explorerStatusHandler)
		handleHTTPRequest(mux, "/explorer/blockdata", srv.explorerBlockDataHandler)
		handleHTTPRequest(mux, "/explorer/gethash", srv.explorerGetHashHandler)
	}

	// Create graceful HTTP server
	srv.apiServer = &graceful.Server{
		Timeout: apiTimeout,
		Server:  &http.Server{Addr: addr, Handler: mux},
	}
}

// unrecognizedCallHandler handles calls to unknown pages (404).
func (srv *Server) unrecognizedCallHandler(w http.ResponseWriter, req *http.Request) {
	w.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(w, "404 - Refer to API.md")
}

// writeError an error to the API caller.
func writeError(w http.ResponseWriter, msg string, err int) {
	http.Error(w, msg, err)
}

// writeJSON writes the object to the ResponseWriter. If the encoding fails, an
// error is written instead.
func writeJSON(w http.ResponseWriter, obj interface{}) {
	if json.NewEncoder(w).Encode(obj) != nil {
		http.Error(w, "Failed to encode response", http.StatusInternalServerError)
	}
}

// writeSuccess writes the success json object ({"Success":true}) to the
// ResponseWriter
func writeSuccess(w http.ResponseWriter) {
	writeJSON(w, struct{ Success bool }{true})
}
<|endoftext|>


<commit_before>//Package api implements the endpoints and utilities necessary to present
//a consistent API to autobd-nodes

package api

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/tywkeene/autobd/index"
	"github.com/tywkeene/autobd/logging"
	"github.com/tywkeene/autobd/options"
	"github.com/tywkeene/autobd/packing"
	"github.com/tywkeene/autobd/version"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

type Node struct {
	Address string
	Version string
	Online  string
	Synced  bool
}

var CurrentNodes map[string]*Node

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.Writer.Write(b)
}

//Check and make sure the client wants or can handle gzip, and replace the writer if it
//can, if not, simply use the normal http.ResponseWriter
func GzipHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

//GetQueryValue() takes a name of a key:value pair to fetchf rom a URL encoded query,
//a http.ResponseWriter 'w', and a http.Request 'r'. In the event that an error is encountered
//the error will be returned to the client via logging facilities that use 'w' and 'r'
func GetQueryValue(name string, w http.ResponseWriter, r *http.Request) string {
	query, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Query parse error"), http.StatusInternalServerError)
		return ""
	}
	value := query.Get(name)
	if len(value) == 0 || value == "" {
		if name != "uuid" {
			log.Error(err)
			logging.LogHttpErr(w, r, fmt.Errorf("Must specify %s", name), http.StatusBadRequest)
			return ""
		}
	}
	return value
}

//ServeIndex() is the http handler for the "/index" API endpoint.
//It takes the requested directory passed as a url parameter "dir" i.e "/index?dir=/"
//
//It will then generate a index by calling api.GetQueryValue(), then writes it to the client as a
//map[string]*index.Index encoded in json
func ServeIndex(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)

	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	updateNodeOnline(uuid)

	dir := GetQueryValue("dir", w, r)
	if dir == "" {
		log.Error("No directory defined")
		logging.LogHttpErr(w, r, fmt.Errorf("Must define directory"), http.StatusInternalServerError)
		return
	}
	dirIndex, err := index.GetIndex(dir)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting index"), http.StatusInternalServerError)
		return
	}
	serial, _ := json.MarshalIndent(&dirIndex, "  ", "  ")
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", "Autobd v"+version.Server())
	io.WriteString(w, string(serial))

}

//ServeServerVer() is the http handler for the "/version" http API endpoint.
//It writes the json encoded struct version.VersionInfo to the client
func ServeServerVer(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	serialVer, _ := json.MarshalIndent(&version.VersionInfo{version.Server(), version.Commit()}, "  ", "  ")

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", "Autobd v"+version.Server())
	io.WriteString(w, string(serialVer))
}

//ServeSync() is the http handler for the "/sync" http API endpoint.
//It takes the requested directory or file name passed as a url parameter "grab" i.e "/sync?grab=file1"
//
//If the requested file is a directory, it will be tarballed and the "Content-Type" http-header will be
//set to "application/x-tar".
//If the file is a normal file, it will be served with http.ServeContent(), with the Content-Type http-header
//set by http.ServeContent()
func ServeSync(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	grab := GetQueryValue("grab", w, r)
	if grab == "" {
		return
	}
	fd, err := os.Open(grab)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting file"), http.StatusInternalServerError)
		return
	}
	defer fd.Close()
	info, err := fd.Stat()
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting file"), http.StatusInternalServerError)
		return
	}
	if info.IsDir() == true {
		w.Header().Set("Content-Type", "application/x-tar")
		if err := packing.PackDir(grab, w); err != nil {
			log.Error(err)
			logging.LogHttpErr(w, r, fmt.Errorf("Error packing directory"), http.StatusInternalServerError)
			return
		}
		return
	}
	http.ServeContent(w, r, grab, info.ModTime(), fd)
	updateNodeSynced(uuid, true)
	updateNodeOnline(uuid)
}

//Identify() is the http handler for the "/identify" API endpoint
//It takes a node UUID and node version as json encoded strings
//The node is added to the CurrentNodes map, with the RFC850 timestamp
func Identify(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	version := GetQueryValue("version", w, r)
	if CurrentNodes == nil {
		CurrentNodes = make(map[string]*Node)
	}
	CurrentNodes[uuid] = &Node{r.RemoteAddr, version, time.Now().Format(time.RFC850), false}
	log.Printf("New node UUID: %s Address: %s Version: %s", uuid, r.RemoteAddr, version)
}

func updateNodeSynced(uuid string, val bool) {
	node := CurrentNodes[uuid]
	node.Synced = val
}

func updateNodeOnline(address string) {
	node := CurrentNodes[address]
	node.Online = time.Now().Format(time.RFC850)
}

func validateNode(uuid string) bool {
	_, ok := CurrentNodes[uuid]
	return ok
}

//ListNodes() is the http handler for the "/nodes" API endpoint
//It returns the CurrentNodes map encoded in json
func ListNodes(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	serial, _ := json.MarshalIndent(&CurrentNodes, " ", " ")
	io.WriteString(w, string(serial))
}

//HeartBeat() is the http handler for the "/heartbeat" API endpoint
//Nodes will request this every config.HeartbeatInterval and the server will update
//their respective online timestamp
func HeartBeat(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	updateNodeOnline(uuid)
}

func SetupRoutes() {
	http.HandleFunc("/v"+version.Major()+"/index", GzipHandler(ServeIndex))
	http.HandleFunc("/v"+version.Major()+"/sync", GzipHandler(ServeSync))
	http.HandleFunc("/v"+version.Major()+"/identify", GzipHandler(Identify))
	if options.Config.NodeEndpoint == true {
		http.HandleFunc("/v"+version.Major()+"/nodes", GzipHandler(ListNodes))
	}
	http.HandleFunc("/v"+version.Major()+"/heartbeat", GzipHandler(HeartBeat))
	http.HandleFunc("/version", GzipHandler(ServeServerVer))
}
<commit_msg>Fixed typo<commit_after>//Package api implements the endpoints and utilities necessary to present
//a consistent API to autobd-nodes

package api

import (
	"compress/gzip"
	"encoding/json"
	"fmt"
	log "github.com/Sirupsen/logrus"
	"github.com/tywkeene/autobd/index"
	"github.com/tywkeene/autobd/logging"
	"github.com/tywkeene/autobd/options"
	"github.com/tywkeene/autobd/packing"
	"github.com/tywkeene/autobd/version"
	"io"
	"net/http"
	"net/url"
	"os"
	"strings"
	"time"
)

type Node struct {
	Address string
	Version string
	Online  string
	Synced  bool
}

var CurrentNodes map[string]*Node

type gzipResponseWriter struct {
	io.Writer
	http.ResponseWriter
}

func (w gzipResponseWriter) Write(b []byte) (int, error) {
	return w.Writer.Write(b)
}

//Check and make sure the client wants or can handle gzip, and replace the writer if it
//can, if not, simply use the normal http.ResponseWriter
func GzipHandler(fn http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		if !strings.Contains(r.Header.Get("Accept-Encoding"), "gzip") {
			fn(w, r)
			return
		}
		w.Header().Set("Content-Encoding", "gzip")
		gz := gzip.NewWriter(w)
		defer gz.Close()
		gzr := gzipResponseWriter{Writer: gz, ResponseWriter: w}
		fn(gzr, r)
	}
}

//GetQueryValue() takes a name of a key:value pair to fetchf rom a URL encoded query,
//a http.ResponseWriter 'w', and a http.Request 'r'. In the event that an error is encountered
//the error will be returned to the client via logging facilities that use 'w' and 'r'
func GetQueryValue(name string, w http.ResponseWriter, r *http.Request) string {
	query, err := url.ParseQuery(r.URL.RawQuery)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Query parse error"), http.StatusInternalServerError)
		return ""
	}
	value := query.Get(name)
	if len(value) == 0 || value == "" {
		if name != "uuid" {
			log.Error(err)
			logging.LogHttpErr(w, r, fmt.Errorf("Must specify %s", name), http.StatusBadRequest)
			return ""
		}
	}
	return value
}

//ServeIndex() is the http handler for the "/index" API endpoint.
//It takes the requested directory passed as a url parameter "dir" i.e "/index?dir=/"
//
//It will then generate a index by calling api.GetIndex(), then writes it to the client as a
//map[string]*index.Index encoded in json
func ServeIndex(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)

	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	updateNodeOnline(uuid)

	dir := GetQueryValue("dir", w, r)
	if dir == "" {
		log.Error("No directory defined")
		logging.LogHttpErr(w, r, fmt.Errorf("Must define directory"), http.StatusInternalServerError)
		return
	}
	dirIndex, err := index.GetIndex(dir)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting index"), http.StatusInternalServerError)
		return
	}
	serial, _ := json.MarshalIndent(&dirIndex, "  ", "  ")
	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", "Autobd v"+version.Server())
	io.WriteString(w, string(serial))

}

//ServeServerVer() is the http handler for the "/version" http API endpoint.
//It writes the json encoded struct version.VersionInfo to the client
func ServeServerVer(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	serialVer, _ := json.MarshalIndent(&version.VersionInfo{version.Server(), version.Commit()}, "  ", "  ")

	w.Header().Set("Content-Type", "application/json")
	w.Header().Set("Server", "Autobd v"+version.Server())
	io.WriteString(w, string(serialVer))
}

//ServeSync() is the http handler for the "/sync" http API endpoint.
//It takes the requested directory or file name passed as a url parameter "grab" i.e "/sync?grab=file1"
//
//If the requested file is a directory, it will be tarballed and the "Content-Type" http-header will be
//set to "application/x-tar".
//If the file is a normal file, it will be served with http.ServeContent(), with the Content-Type http-header
//set by http.ServeContent()
func ServeSync(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	grab := GetQueryValue("grab", w, r)
	if grab == "" {
		return
	}
	fd, err := os.Open(grab)
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting file"), http.StatusInternalServerError)
		return
	}
	defer fd.Close()
	info, err := fd.Stat()
	if err != nil {
		log.Error(err)
		logging.LogHttpErr(w, r, fmt.Errorf("Error getting file"), http.StatusInternalServerError)
		return
	}
	if info.IsDir() == true {
		w.Header().Set("Content-Type", "application/x-tar")
		if err := packing.PackDir(grab, w); err != nil {
			log.Error(err)
			logging.LogHttpErr(w, r, fmt.Errorf("Error packing directory"), http.StatusInternalServerError)
			return
		}
		return
	}
	http.ServeContent(w, r, grab, info.ModTime(), fd)
	updateNodeSynced(uuid, true)
	updateNodeOnline(uuid)
}

//Identify() is the http handler for the "/identify" API endpoint
//It takes a node UUID and node version as json encoded strings
//The node is added to the CurrentNodes map, with the RFC850 timestamp
func Identify(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	version := GetQueryValue("version", w, r)
	if CurrentNodes == nil {
		CurrentNodes = make(map[string]*Node)
	}
	CurrentNodes[uuid] = &Node{r.RemoteAddr, version, time.Now().Format(time.RFC850), false}
	log.Printf("New node UUID: %s Address: %s Version: %s", uuid, r.RemoteAddr, version)
}

func updateNodeSynced(uuid string, val bool) {
	node := CurrentNodes[uuid]
	node.Synced = val
}

func updateNodeOnline(address string) {
	node := CurrentNodes[address]
	node.Online = time.Now().Format(time.RFC850)
}

func validateNode(uuid string) bool {
	_, ok := CurrentNodes[uuid]
	return ok
}

//ListNodes() is the http handler for the "/nodes" API endpoint
//It returns the CurrentNodes map encoded in json
func ListNodes(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	serial, _ := json.MarshalIndent(&CurrentNodes, " ", " ")
	io.WriteString(w, string(serial))
}

//HeartBeat() is the http handler for the "/heartbeat" API endpoint
//Nodes will request this every config.HeartbeatInterval and the server will update
//their respective online timestamp
func HeartBeat(w http.ResponseWriter, r *http.Request) {
	logging.LogHttp(r)
	uuid := GetQueryValue("uuid", w, r)
	if validateNode(uuid) == false {
		log.Error("Invalid or empty node UUID")
		logging.LogHttpErr(w, r, fmt.Errorf("Invalid node UUID"), http.StatusUnauthorized)
		return
	}
	updateNodeOnline(uuid)
}

func SetupRoutes() {
	http.HandleFunc("/v"+version.Major()+"/index", GzipHandler(ServeIndex))
	http.HandleFunc("/v"+version.Major()+"/sync", GzipHandler(ServeSync))
	http.HandleFunc("/v"+version.Major()+"/identify", GzipHandler(Identify))
	if options.Config.NodeEndpoint == true {
		http.HandleFunc("/v"+version.Major()+"/nodes", GzipHandler(ListNodes))
	}
	http.HandleFunc("/v"+version.Major()+"/heartbeat", GzipHandler(HeartBeat))
	http.HandleFunc("/version", GzipHandler(ServeServerVer))
}
<|endoftext|>


<commit_before>package api

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"

	"github.com/Pterodactyl/wings/config"
)

type InternalAPI struct {
	router *gin.Engine
}

func NewAPI() InternalAPI {
	return InternalAPI{}
}

// Configure the API and begin listening on the configured IP and Port.
func (api *InternalAPI) Listen() {
	listener := fmt.Sprintf("%s:%d", viper.GetString(config.APIHost), viper.GetInt(config.APIPort))

	if !viper.GetBool(config.Debug) {
		gin.SetMode(gin.ReleaseMode)
	}

	api.router = gin.Default()
	api.RegisterRoutes()

	api.router.Run(listener)
	log.Info("Now listening on %s", listener)
	log.Fatal(http.ListenAndServe(listener, nil))
}
<commit_msg>Lets not, please.<commit_after>package api

import (
	"fmt"
	"net/http"

	"github.com/gin-gonic/gin"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/viper"

	"github.com/Pterodactyl/wings/config"
)

type InternalAPI struct {
	router *gin.Engine
}

func NewAPI() InternalAPI {
	return InternalAPI{}
}

// Configure the API and begin listening on the configured IP and Port.
func (api *InternalAPI) Listen() {
	listener := fmt.Sprintf("%s:%d", viper.GetString(config.APIHost), viper.GetInt(config.APIPort))

	if !viper.GetBool(config.Debug) {
		gin.SetMode(gin.ReleaseMode)
	}

	api.router = gin.Default()
	api.router.RedirectTrailingSlash = false
	api.RegisterRoutes()

	api.router.Run(listener)
	log.Info("Now listening on %s", listener)
	log.Fatal(http.ListenAndServe(listener, nil))
}
<|endoftext|>


<commit_before>package api

import (
	"context"
	"encoding/base64"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/gorilla/mux"

	"github.com/reviewboard/rb-gateway/config"
	"github.com/reviewboard/rb-gateway/repositories"
)

const (
	PrivateTokenHeader = "PRIVATE-TOKEN"
)

type API struct {
	config config.Config
	router *mux.Router
}

// Return a new router for the API.
func New(cfg config.Config) API {
	api := API{
		config: cfg,
		router: mux.NewRouter(),
	}

	api.router.Path("/session").
		Methods("GET").
		HandlerFunc(api.getSession)

	// The following routes all require authorization.
	repoRoutes := api.router.PathPrefix("/repos/{repo}").Subrouter()
	repoRoutes.Use(api.withAuthorizationRequired)
	repoRoutes.Use(api.withRepository)

	routeTable := []struct {
		methods []string
		path    string
		handler http.Handler
	}{
		{[]string{"GET"}, "/branches", http.HandlerFunc(api.getBranches)},
		{[]string{"GET"}, "/branches/{branch}/commits", http.HandlerFunc(api.getCommits)},
		{[]string{"GET"}, "/commits/{commit-id}", http.HandlerFunc(api.getCommit)},
		{[]string{"GET"}, "/commits/{commit-id}/path/{path}", http.HandlerFunc(api.getFileByCommit)},
		{[]string{"HEAD"}, "/commits/{commit-id}/path/{path}", http.HandlerFunc(api.getFileExistsByCommit)},
		{[]string{"GET"}, "/file/{file-id}", http.HandlerFunc(api.getFile)},
		{[]string{"HEAD"}, "/file/{file-id}", http.HandlerFunc(api.getFileExists)},
	}

	for _, route := range routeTable {
		repoRoutes.Path(route.path).
			Methods(route.methods...).
			Handler(route.handler)
	}

	return api
}

func (api *API) SetConfig(newConfig config.Config) {
	api.config = newConfig
}

// A middleware for wrapping routes that require a repository.
//
// If the requested repository exists, it will be provided through the context
// as `"repo"`. Otherwise, an appropriate error will be returned.
func (api API) withRepository(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		repoName := mux.Vars(r)["repo"]

		var repo repositories.Repository
		var exists bool

		if len(repoName) == 0 {
			http.Error(w, "Repository not provided.", http.StatusBadRequest)
		} else if repo, exists = api.config.Repositories[repoName]; !exists {
			http.Error(w, "Repository not found.", http.StatusNotFound)
		} else {
			ctx := context.WithValue(r.Context(), "repo", repo)
			next.ServeHTTP(w, r.WithContext(ctx))
		}
	})
}

// TODO: Replace this with actual token logic.
func (api API) withAuthorizationRequired(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		privateToken := r.Header.Get(PrivateTokenHeader)

		var payload []byte
		var err error
		var pair []string

		if len(privateToken) == 0 {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if payload, err = base64.StdEncoding.DecodeString(privateToken); err != nil {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if pair = strings.SplitN(string(payload), ":", 2); len(pair) != 2 {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if !api.validateCredentials(pair[0], pair[1]) {
			http.Error(w, "Authorization failed.", http.StatusUnauthorized)
		} else {
			next.ServeHTTP(w, r)
		}
	})
}

// Serve the HTTP request.
func (api API) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	loggingMiddleware(api.router).ServeHTTP(w, r)
}

func (api *API) validateCredentials(username, password string) bool {
	return username == api.config.Username && password == api.config.Password
}

func (api *API) CreateSession(r *http.Request) (*Session, error) {
	username, password, ok := r.BasicAuth()
	if !ok {
		return nil, errors.New("Invalid Authorization header.")
	}

	if !api.validateCredentials(username, password) {
		return nil, errors.New("Authorization failed.")
	}

	// TODO: replace with an actual token.
	credentials := []byte(fmt.Sprintf("%s:%s", username, password))
	token := base64.StdEncoding.EncodeToString(credentials)
	return &Session{token}, nil
}
<commit_msg>Prevent timing attacks when validating credentials<commit_after>package api

import (
	"context"
	"crypto/subtle"
	"encoding/base64"
	"errors"
	"fmt"
	"net/http"
	"strings"

	"github.com/gorilla/mux"

	"github.com/reviewboard/rb-gateway/config"
	"github.com/reviewboard/rb-gateway/repositories"
)

const (
	PrivateTokenHeader = "PRIVATE-TOKEN"
)

type API struct {
	config config.Config
	router *mux.Router
}

// Return a new router for the API.
func New(cfg config.Config) API {
	api := API{
		config: cfg,
		router: mux.NewRouter(),
	}

	api.router.Path("/session").
		Methods("GET").
		HandlerFunc(api.getSession)

	// The following routes all require authorization.
	repoRoutes := api.router.PathPrefix("/repos/{repo}").Subrouter()
	repoRoutes.Use(api.withAuthorizationRequired)
	repoRoutes.Use(api.withRepository)

	routeTable := []struct {
		methods []string
		path    string
		handler http.Handler
	}{
		{[]string{"GET"}, "/branches", http.HandlerFunc(api.getBranches)},
		{[]string{"GET"}, "/branches/{branch}/commits", http.HandlerFunc(api.getCommits)},
		{[]string{"GET"}, "/commits/{commit-id}", http.HandlerFunc(api.getCommit)},
		{[]string{"GET"}, "/commits/{commit-id}/path/{path}", http.HandlerFunc(api.getFileByCommit)},
		{[]string{"HEAD"}, "/commits/{commit-id}/path/{path}", http.HandlerFunc(api.getFileExistsByCommit)},
		{[]string{"GET"}, "/file/{file-id}", http.HandlerFunc(api.getFile)},
		{[]string{"HEAD"}, "/file/{file-id}", http.HandlerFunc(api.getFileExists)},
	}

	for _, route := range routeTable {
		repoRoutes.Path(route.path).
			Methods(route.methods...).
			Handler(route.handler)
	}

	return api
}

func (api *API) SetConfig(newConfig config.Config) {
	api.config = newConfig
}

// A middleware for wrapping routes that require a repository.
//
// If the requested repository exists, it will be provided through the context
// as `"repo"`. Otherwise, an appropriate error will be returned.
func (api API) withRepository(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		repoName := mux.Vars(r)["repo"]

		var repo repositories.Repository
		var exists bool

		if len(repoName) == 0 {
			http.Error(w, "Repository not provided.", http.StatusBadRequest)
		} else if repo, exists = api.config.Repositories[repoName]; !exists {
			http.Error(w, "Repository not found.", http.StatusNotFound)
		} else {
			ctx := context.WithValue(r.Context(), "repo", repo)
			next.ServeHTTP(w, r.WithContext(ctx))
		}
	})
}

// TODO: Replace this with actual token logic.
func (api API) withAuthorizationRequired(next http.Handler) http.Handler {
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		privateToken := r.Header.Get(PrivateTokenHeader)

		var payload []byte
		var err error
		var pair []string

		if len(privateToken) == 0 {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if payload, err = base64.StdEncoding.DecodeString(privateToken); err != nil {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if pair = strings.SplitN(string(payload), ":", 2); len(pair) != 2 {
			http.Error(w, "Bad private token.", http.StatusBadRequest)
		} else if !api.validateCredentials(pair[0], pair[1]) {
			http.Error(w, "Authorization failed.", http.StatusUnauthorized)
		} else {
			next.ServeHTTP(w, r)
		}
	})
}

// Serve the HTTP request.
func (api API) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	loggingMiddleware(api.router).ServeHTTP(w, r)
}

func (api *API) validateCredentials(username, password string) bool {
	validUsername := subtle.ConstantTimeCompare([]byte(username), []byte(api.config.Username))
	validPassword := subtle.ConstantTimeCompare([]byte(password), []byte(api.config.Password))

	return validUsername + validPassword == 2
}

func (api *API) CreateSession(r *http.Request) (*Session, error) {
	username, password, ok := r.BasicAuth()
	if !ok {
		return nil, errors.New("Invalid Authorization header.")
	}

	if !api.validateCredentials(username, password) {
		return nil, errors.New("Authorization failed.")
	}

	// TODO: replace with an actual token.
	credentials := []byte(fmt.Sprintf("%s:%s", username, password))
	token := base64.StdEncoding.EncodeToString(credentials)
	return &Session{token}, nil
}
<|endoftext|>


<commit_before>// Test APP
package main

import (
	"fmt"
	"github.com/dim13/golb"
	"log"
	"net/http"
)

const listen = ":8000"

func root(w http.ResponseWriter, r *http.Request, s []string) {
	fmt.Fprint(w, s)
}

func main() {
	d := golb.Open("test.json")

	a := &golb.Article{
		Title: "Test title",
		Body: "empty body",
		Tags: []string{"no", "tags", "at all"},
		Author: "me@example.com",
	}
	d.Articles.Add(a)
	a.Publish()

	c := &golb.Comment{
		Name: "anonymous coward",
		Email: "none@example.com",
		URL: "http://example.com",
		Comment: "empty",
	}
	a.Comments.Add(c)
	c.Publish()

	if err := d.Write(); err != nil {
		log.Fatal(err)
	}
	if err := d.Read(); err != nil {
		log.Fatal(err)
	}

	/*
	re := new(golb.ReHandler)
	re.AddRoute("^/(\\d+)/(.*)$", root)
	if err := http.ListenAndServe(listen, re); err != nil {
		log.Fatal(err)
	}
	 */
}
<commit_msg>test find<commit_after>// Test APP
package main

import (
	"fmt"
	"github.com/dim13/golb"
	"log"
	"net/http"
)

const listen = ":8000"

func root(w http.ResponseWriter, r *http.Request, s []string) {
	fmt.Fprint(w, s)
}

func main() {
	d := golb.Open("test.json")

	a := &golb.Article{
		Title: "Test title",
		Body: "empty body",
		Tags: []string{"no", "tags", "at all"},
		Author: "me@example.com",
	}
	d.Articles.Add(a)

	c := &golb.Comment{
		Name: "anonymous coward",
		Email: "none@example.com",
		URL: "http://example.com",
		Comment: "empty",
	}
	a.Comments.Add(c)
	c.Publish()

	z, err := d.Articles.Find("test-title")
	if err == nil {
		z.Publish()
	}

	if err := d.Write(); err != nil {
		log.Fatal(err)
	}
	if err := d.Read(); err != nil {
		log.Fatal(err)
	}

	/*
	re := new(golb.ReHandler)
	re.AddRoute("^/(\\d+)/(.*)$", root)
	if err := http.ListenAndServe(listen, re); err != nil {
		log.Fatal(err)
	}
	 */
}
<|endoftext|>


<commit_before>package app

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/frozzare/shed/config"
	"github.com/frozzare/shed/repository"
	"github.com/imdario/mergo"
)

var (
	ErrInvalidOptions = errors.New("Invalid options arguments")
)

// App represents the application struct.
type App struct {
	opts *Options
}

// Options represents the application options.
type Options struct {
	Config     config.Config
	Repository repository.Repository
}

// NewApp creates a new application.
func NewApp(opts *Options) (*App, error) {
	if opts == nil {
		return nil, ErrInvalidOptions
	}

	app := &App{opts: opts}

	app.prepare()

	return app, nil
}

// prepare prepares the application.
func (a *App) prepare() {
	os.Setenv("SHED_HOST", a.Host())
}

// Config returns application config.
func (a *App) Config() config.Config {
	config := a.opts.Config.Branches[a.opts.Repository.Branch]
	mergo.Merge(&config, a.opts.Config)
	return config
}

// Repository returns application repository.
func (a *App) Repository() repository.Repository {
	return a.opts.Repository
}

// Host returns the application host.
func (a *App) Host() string {
	repo := a.Repository()

	// Let's allow specific hosts for different branches.
	if len(a.opts.Config.Branches[repo.Branch].Host) > 0 {
		return a.opts.Config.Branches[repo.Branch].Host
	}

	// Add leading dot to host name if missing.
	host := a.opts.Config.Host
	if host[0] != '.' {
		host = "." + host
	}

	return repo.Slug + host
}

// URL returns the url to the application.
func (a *App) URL() string {
	scheme := "http"
	port := a.Config().Docker.Proxy.HTTPPort
	if len(a.Config().Docker.Proxy.HTTPSPort) > 0 {
		scheme = "https"
		port = a.Config().Docker.Proxy.HTTPSPort
	}

	if strings.Contains(port, ":") {
		p := strings.Split(port, ":")
		port = p[0]
	}

	if len(port) > 0 {
		port = ":" + port
	}

	if port == "443" || port == "80" {
		port = ""
	}

	return fmt.Sprintf("%s://%s%s", scheme, a.Host(), port)
}
<commit_msg>Add support for wildcard branches<commit_after>package app

import (
	"errors"
	"fmt"
	"os"
	"strings"

	"github.com/frozzare/shed/config"
	"github.com/frozzare/shed/repository"
	"github.com/imdario/mergo"
)

var (
	ErrInvalidOptions = errors.New("Invalid options arguments")
)

// App represents the application struct.
type App struct {
	opts *Options
}

// Options represents the application options.
type Options struct {
	Config     config.Config
	Repository repository.Repository
}

// NewApp creates a new application.
func NewApp(opts *Options) (*App, error) {
	if opts == nil {
		return nil, ErrInvalidOptions
	}

	app := &App{opts: opts}

	app.prepare()

	return app, nil
}

// prepare prepares the application.
func (a *App) prepare() {
	os.Setenv("SHED_HOST", a.Host())
}

// Config returns application config.
func (a *App) Config() config.Config {
	config := a.opts.Config.Branches[a.opts.Repository.Branch]
	mergo.Merge(&config, a.opts.Config)
	return config
}

// Repository returns application repository.
func (a *App) Repository() repository.Repository {
	return a.opts.Repository
}

// Host returns the application host.
func (a *App) Host() string {
	repo := a.Repository()

	for _, name := range []string{repo.Branch, "*"} {
		// Let's allow specific hosts for different branches.
		if len(a.opts.Config.Branches[name].Host) > 0 {
			return a.opts.Config.Branches[name].Host
		}
	}

	// Add leading dot to host name if missing.
	host := a.opts.Config.Host
	if host[0] != '.' {
		host = "." + host
	}

	return repo.Slug + host
}

// URL returns the url to the application.
func (a *App) URL() string {
	scheme := "http"
	port := a.Config().Docker.Proxy.HTTPPort
	if len(a.Config().Docker.Proxy.HTTPSPort) > 0 {
		scheme = "https"
		port = a.Config().Docker.Proxy.HTTPSPort
	}

	if strings.Contains(port, ":") {
		p := strings.Split(port, ":")
		port = p[0]
	}

	if len(port) > 0 {
		port = ":" + port
	}

	if port == "443" || port == "80" {
		port = ""
	}

	return fmt.Sprintf("%s://%s%s", scheme, a.Host(), port)
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"github.com/heysquirrel/tribe/git"
	"github.com/jroimartin/gocui"
	"io"
	"log"
)

type App struct {
	Gui  *gocui.Gui
	Done chan struct{}
}

func New() *App {
	a := new(App)
	a.Done = make(chan struct{})

	var err error
	a.Gui, err = gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}

	a.Gui.SetManagerFunc(a.Layout)
	a.setKeyBindings()

	return a
}

func (a *App) Loop() {
	err := a.Gui.MainLoop()
	if err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func (a *App) Close() {
	close(a.Done)
	a.Gui.Close()
}

func (a *App) currentFileChanged() {
	file := a.currentFileSelection()
	a.setFrequentContributors(git.FrequentContributors(file))
}

func (a *App) setFrequentContributors(contributors []*git.Contributor) {
	a.updateContributors(func(w io.ReadWriter) {
		for _, contributor := range contributors {
			fmt.Fprintf(w, "%s\t\t\t\t---\t%d commit(s)\tlast commit: %s\n",
				contributor.Name, contributor.Count, contributor.RelativeDate)

		}
	})
}
<commit_msg>Using a table renderer to render frequent contributors<commit_after>package app

import (
	"github.com/heysquirrel/tribe/git"
	"github.com/jroimartin/gocui"
	"github.com/olekukonko/tablewriter"
	"io"
	"log"
	"strconv"
)

type App struct {
	Gui  *gocui.Gui
	Done chan struct{}
}

func New() *App {
	a := new(App)
	a.Done = make(chan struct{})

	var err error
	a.Gui, err = gocui.NewGui(gocui.OutputNormal)
	if err != nil {
		log.Panicln(err)
	}

	a.Gui.SetManagerFunc(a.Layout)
	a.setKeyBindings()

	return a
}

func (a *App) Loop() {
	err := a.Gui.MainLoop()
	if err != nil && err != gocui.ErrQuit {
		log.Panicln(err)
	}
}

func (a *App) Close() {
	close(a.Done)
	a.Gui.Close()
}

func (a *App) currentFileChanged() {
	file := a.currentFileSelection()
	a.setFrequentContributors(git.FrequentContributors(file))
}

func (a *App) setFrequentContributors(contributors []*git.Contributor) {
	a.updateContributors(func(w io.ReadWriter) {
		table := tablewriter.NewWriter(w)
		table.SetHeader([]string{"Name", "Commits", "Last Commit"})
		table.SetBorder(false)

		for _, contributor := range contributors {
			table.Append([]string{contributor.Name, strconv.Itoa(contributor.Count), contributor.RelativeDate})
		}

		table.Render()
	})
}
<|endoftext|>


<commit_before>package app

import (
	"fmt"
	"io/ioutil"

	"github.com/rancher/types/apis/management.cattle.io/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func ReadTLSConfig(config *Config) error {
	var err error

	if config.ListenConfig != nil {
		return nil
	}

	lc := &v3.ListenConfig{
		TypeMeta: metav1.TypeMeta{
			Kind:       "ListenConfig",
			APIVersion: "management.cattle.io/v3",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: "cli-config",
		},
		Enabled: true,
	}

	lc.CACerts, err = readPEM("/etc/rancher/ssl/cacerts.pem")
	if err != nil {
		return err
	}

	lc.Key, err = readPEM("/etc/rancher/ssl/key.pem")
	if err != nil {
		return err
	}

	lc.Cert, err = readPEM("/etc/rancher/ssl/cert.pem")
	if err != nil {
		return err
	}

	lc.Mode = "https"
	if len(config.ACMEDomains) > 0 {
		lc.Mode = "acme"
		lc.Domains = config.ACMEDomains
	}

	valid := false
	if lc.CACerts != "" && lc.Key != "" && lc.Cert != "" {
		valid = true
	} else if lc.Key == "" && lc.Cert == "" {
		valid = true
	}

	if !valid {
		return fmt.Errorf("invalid SSL configuration found, please set all (cacerts, cert, key), cacerts only, or none")
	}

	config.ListenConfig = lc

	return nil
}

func readPEM(path string) (string, error) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", nil
	}

	return string(content), nil
}
<commit_msg>Change TLS validation<commit_after>package app

import (
	"fmt"
	"io/ioutil"

	"github.com/rancher/types/apis/management.cattle.io/v3"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func ReadTLSConfig(config *Config) error {
	var err error

	if config.ListenConfig != nil {
		return nil
	}

	lc := &v3.ListenConfig{
		TypeMeta: metav1.TypeMeta{
			Kind:       "ListenConfig",
			APIVersion: "management.cattle.io/v3",
		},
		ObjectMeta: metav1.ObjectMeta{
			Name: "cli-config",
		},
		Enabled: true,
	}

	lc.CACerts, err = readPEM("/etc/rancher/ssl/cacerts.pem")
	if err != nil {
		return err
	}

	lc.Key, err = readPEM("/etc/rancher/ssl/key.pem")
	if err != nil {
		return err
	}

	lc.Cert, err = readPEM("/etc/rancher/ssl/cert.pem")
	if err != nil {
		return err
	}

	lc.Mode = "https"
	if len(config.ACMEDomains) > 0 {
		lc.Mode = "acme"
		lc.Domains = config.ACMEDomains
	}

	valid := false
	if lc.Key != "" && lc.Cert != "" {
		valid = true
	} else if lc.Key == "" && lc.Cert == "" {
		valid = true
	}

	if !valid {
		return fmt.Errorf("invalid SSL configuration found, please set cert/key, cert/key/cacerts, cacerts only, or none")
	}

	config.ListenConfig = lc

	return nil
}

func readPEM(path string) (string, error) {
	content, err := ioutil.ReadFile(path)
	if err != nil {
		return "", nil
	}

	return string(content), nil
}
<|endoftext|>


<commit_before>package main

// Applet imports
import (
	"github.com/surma/gobox/applets/cat"
	"github.com/surma/gobox/applets/chroot"
	"github.com/surma/gobox/applets/echo"
	"github.com/surma/gobox/applets/grep"
	"github.com/surma/gobox/applets/gzip"
	"github.com/surma/gobox/applets/head"
	"github.com/surma/gobox/applets/httpd"
	"github.com/surma/gobox/applets/kill"
	"github.com/surma/gobox/applets/ls"
	"github.com/surma/gobox/applets/mkdir"
	"github.com/surma/gobox/applets/mknod"
	"github.com/surma/gobox/applets/mount"
	"github.com/surma/gobox/applets/ps"
	"github.com/surma/gobox/applets/rm"
	"github.com/surma/gobox/applets/shell"
	"github.com/surma/gobox/applets/telnetd"
	"github.com/surma/gobox/applets/umount"
	"github.com/surma/gobox/applets/wget"
)

// This map contains the mappings from callname
// to applet function.
var Applets map[string]Applet = map[string]Applet{
	"echo":    echo.Echo,
	"shell":   shell.Shell,
	"sh":   shell.Shell,
	"telnetd": telnetd.Telnetd,
	"ls":      ls.Ls,
	"rm":      rm.Rm,
	"httpd":   httpd.Httpd,
	"wget":    wget.Wget,
	"kill":    kill.Kill,
	"cat":     cat.Cat,
	"mknod":   mknod.Mknod,
	"mount":   mount.Mount,
	"umount":  umount.Umount,
	"chroot":  chroot.Chroot,
	"ps":      ps.Ps,
	"mkdir":   mkdir.Mkdir,
	"head":    head.Head,
	"grep":    grep.Grep,
	"gzip":    gzip.Gzip,
	"gunzip":  gzip.Gunzip,
	"zcat":    gzip.Zcat,
}

// Signature of applet functions.
// call is like os.Argv, and therefore contains the
// name of the applet itself in call[0].
// If the returned error is not nil, it is printed
// to stdout.
type Applet func(call []string) error
<commit_msg>gofmt<commit_after>package main

// Applet imports
import (
	"github.com/surma/gobox/applets/cat"
	"github.com/surma/gobox/applets/chroot"
	"github.com/surma/gobox/applets/echo"
	"github.com/surma/gobox/applets/grep"
	"github.com/surma/gobox/applets/gzip"
	"github.com/surma/gobox/applets/head"
	"github.com/surma/gobox/applets/httpd"
	"github.com/surma/gobox/applets/kill"
	"github.com/surma/gobox/applets/ls"
	"github.com/surma/gobox/applets/mkdir"
	"github.com/surma/gobox/applets/mknod"
	"github.com/surma/gobox/applets/mount"
	"github.com/surma/gobox/applets/ps"
	"github.com/surma/gobox/applets/rm"
	"github.com/surma/gobox/applets/shell"
	"github.com/surma/gobox/applets/telnetd"
	"github.com/surma/gobox/applets/umount"
	"github.com/surma/gobox/applets/wget"
)

// This map contains the mappings from callname
// to applet function.
var Applets map[string]Applet = map[string]Applet{
	"echo":    echo.Echo,
	"shell":   shell.Shell,
	"sh":      shell.Shell,
	"telnetd": telnetd.Telnetd,
	"ls":      ls.Ls,
	"rm":      rm.Rm,
	"httpd":   httpd.Httpd,
	"wget":    wget.Wget,
	"kill":    kill.Kill,
	"cat":     cat.Cat,
	"mknod":   mknod.Mknod,
	"mount":   mount.Mount,
	"umount":  umount.Umount,
	"chroot":  chroot.Chroot,
	"ps":      ps.Ps,
	"mkdir":   mkdir.Mkdir,
	"head":    head.Head,
	"grep":    grep.Grep,
	"gzip":    gzip.Gzip,
	"gunzip":  gzip.Gunzip,
	"zcat":    gzip.Zcat,
}

// Signature of applet functions.
// call is like os.Argv, and therefore contains the
// name of the applet itself in call[0].
// If the returned error is not nil, it is printed
// to stdout.
type Applet func(call []string) error
<|endoftext|>