<commit_before>package lessgo

import (
	"net"
	"path"
	"time"

	_ "github.com/lessgo/lessgo/_fixture"
	"github.com/lessgo/lessgo/engine"
	"github.com/lessgo/lessgo/logs"
)

type (
	Lessgo struct {
		*Echo
	}
	NewServer func(engine.Config) engine.Server
)

const (
	NAME    = "Lessgo"
	VERSION = "0.4.0"
	ADDRESS = "https://github.com/lessgo/lessgo"
)
const (
	MB = 1 << 20
)

var (
	DefLessgo = func() *Lessgo {
		printInfo()
		registerAppConfig()
		registerDBConfig()
		registerMime()
		l := &Lessgo{
			Echo: New(),
		}
		// 初始化日志
		l.Echo.Logger().SetMsgChan(AppConfig.Log.AsyncChan)
		l.Echo.SetLogLevel(AppConfig.Log.Level)
		// 设置运行模式
		l.Echo.SetDebug(AppConfig.Debug)
		// 设置静态资源缓存
		l.Echo.SetMemoryCache(NewMemoryCache(
			AppConfig.FileCache.SingleFileAllowMB*MB,
			AppConfig.FileCache.MaxCapMB*MB,
			time.Duration(AppConfig.FileCache.CacheSecond)*time.Second),
		)
		// 设置渲染接口
		l.Echo.SetRenderer(NewPongo2Render(AppConfig.Debug))
		// 设置大小写敏感
		l.Echo.SetCaseSensitive(AppConfig.RouterCaseSensitive)
		// 设置上传文件允许的最大尺寸
		engine.MaxMemory = AppConfig.MaxMemoryMB * MB
		return l
	}()
)

func Run(server NewServer, listener ...net.Listener) {
	checkHooks(registerRouter())
	checkHooks(registerSession())

	// 配置服务器引擎
	c := engine.Config{
		Address:      AppConfig.Listen.Address,
		ReadTimeout:  time.Duration(AppConfig.Listen.ReadTimeout),
		WriteTimeout: time.Duration(AppConfig.Listen.WriteTimeout),
	}
	h := "HTTP"
	if AppConfig.Listen.EnableHTTPS {
		h = "HTTPS"
		c.TLSKeyfile = AppConfig.Listen.HTTPSKeyFile
		c.TLSCertfile = AppConfig.Listen.HTTPSCertFile
	}
	if len(listener) > 0 && listener[0] != nil {
		c.Listener = listener[0]
	}
	// 启动服务
	mode := "release"
	if AppConfig.Debug {
		mode = "debug"
	}
	DefLessgo.Logger().Sys("> %s listening and serving %s on %v (%s-mode)", AppConfig.AppName, h, c.Address, mode)
	DefLessgo.Run(server(c))
}

// 在路由执行位置之前紧邻插入中间件队列
func Before(middleware ...interface{}) {
	DefLessgo.Echo.BeforeUse(wrapMiddlewares(middleware)...)
}

// 在路由执行位置之后紧邻插入中间件队列
func After(middleware ...interface{}) {
	DefLessgo.Echo.AfterUse(wrapMiddlewares(middleware)...)
}

// 重建真实路由
func ResetRealRoute() {
	if err := middlewareExistCheck(DefDynaRouter); err != nil {
		DefLessgo.Logger().Error("Create/Recreate the router is faulty: %v", err)
		return
	}

	DefLessgo.Echo.lock.Lock()
	defer DefLessgo.Echo.lock.Unlock()

	defer func() {
		// 创建静态路由
		staticRoute()
	}()

	// 创建动态路由
	DefLessgo.Echo.router = NewRouter(DefLessgo.Echo)
	DefLessgo.Echo.middleware = []MiddlewareFunc{DefLessgo.Echo.router.Process}
	DefLessgo.Echo.head = DefLessgo.Echo.pristineHead
	registerRootMiddlewares()
	DefLessgo.Echo.BeforeUse(getMiddlewares(beforeMiddlewares)...)
	DefLessgo.Echo.AfterUse(getMiddlewares(afterMiddlewares)...)
	for _, child := range DefDynaRouter.Children {
		var group *Group
		for _, d := range child.Tree() {
			mws := getMiddlewares(d.Middlewares)
			switch d.Type {
			case GROUP:
				if group == nil {
					group = DefLessgo.Echo.Group(d.Prefix, mws...)
					break
				}
				group = group.Group(d.Prefix, mws...)
			case HANDLER:
				if group == nil {
					DefLessgo.Echo.Match(d.Methods, path.Join(d.Prefix, d.Param), handlerFuncMap[d.Handler], mws...)
					break
				}
				group.Match(d.Methods, path.Join(d.Prefix, d.Param), handlerFuncMap[d.Handler], mws...)
			}
		}
	}
}

func Logger() logs.Logger {
	return DefLessgo.Echo.Logger()
}
<commit_msg>优化代码格式<commit_after>package lessgo

import (
	"net"
	"path"
	"time"

	_ "github.com/lessgo/lessgo/_fixture"
	"github.com/lessgo/lessgo/engine"
	"github.com/lessgo/lessgo/logs"
)

type (
	Lessgo struct {
		*Echo
	}
	NewServer func(engine.Config) engine.Server
)

const (
	NAME    = "Lessgo"
	VERSION = "0.4.0"
	ADDRESS = "https://github.com/lessgo/lessgo"
)

const (
	MB = 1 << 20
)

var (
	DefLessgo = func() *Lessgo {
		printInfo()
		registerAppConfig()
		registerDBConfig()
		registerMime()
		l := &Lessgo{
			Echo: New(),
		}
		// 初始化日志
		l.Echo.Logger().SetMsgChan(AppConfig.Log.AsyncChan)
		l.Echo.SetLogLevel(AppConfig.Log.Level)
		// 设置运行模式
		l.Echo.SetDebug(AppConfig.Debug)
		// 设置静态资源缓存
		l.Echo.SetMemoryCache(NewMemoryCache(
			AppConfig.FileCache.SingleFileAllowMB*MB,
			AppConfig.FileCache.MaxCapMB*MB,
			time.Duration(AppConfig.FileCache.CacheSecond)*time.Second),
		)
		// 设置渲染接口
		l.Echo.SetRenderer(NewPongo2Render(AppConfig.Debug))
		// 设置大小写敏感
		l.Echo.SetCaseSensitive(AppConfig.RouterCaseSensitive)
		// 设置上传文件允许的最大尺寸
		engine.MaxMemory = AppConfig.MaxMemoryMB * MB
		return l
	}()
)

func Run(server NewServer, listener ...net.Listener) {
	checkHooks(registerRouter())
	checkHooks(registerSession())

	// 配置服务器引擎
	c := engine.Config{
		Address:      AppConfig.Listen.Address,
		ReadTimeout:  time.Duration(AppConfig.Listen.ReadTimeout),
		WriteTimeout: time.Duration(AppConfig.Listen.WriteTimeout),
	}
	h := "HTTP"
	if AppConfig.Listen.EnableHTTPS {
		h = "HTTPS"
		c.TLSKeyfile = AppConfig.Listen.HTTPSKeyFile
		c.TLSCertfile = AppConfig.Listen.HTTPSCertFile
	}
	if len(listener) > 0 && listener[0] != nil {
		c.Listener = listener[0]
	}
	// 启动服务
	mode := "release"
	if AppConfig.Debug {
		mode = "debug"
	}
	DefLessgo.Logger().Sys("> %s listening and serving %s on %v (%s-mode)", AppConfig.AppName, h, c.Address, mode)
	DefLessgo.Run(server(c))
}

// 在路由执行位置之前紧邻插入中间件队列
func Before(middleware ...interface{}) {
	DefLessgo.Echo.BeforeUse(wrapMiddlewares(middleware)...)
}

// 在路由执行位置之后紧邻插入中间件队列
func After(middleware ...interface{}) {
	DefLessgo.Echo.AfterUse(wrapMiddlewares(middleware)...)
}

// 重建真实路由
func ResetRealRoute() {
	if err := middlewareExistCheck(DefDynaRouter); err != nil {
		DefLessgo.Logger().Error("Create/Recreate the router is faulty: %v", err)
		return
	}

	DefLessgo.Echo.lock.Lock()
	defer DefLessgo.Echo.lock.Unlock()

	defer func() {
		// 创建静态路由
		staticRoute()
	}()

	// 创建动态路由
	DefLessgo.Echo.router = NewRouter(DefLessgo.Echo)
	DefLessgo.Echo.middleware = []MiddlewareFunc{DefLessgo.Echo.router.Process}
	DefLessgo.Echo.head = DefLessgo.Echo.pristineHead
	registerRootMiddlewares()
	DefLessgo.Echo.BeforeUse(getMiddlewares(beforeMiddlewares)...)
	DefLessgo.Echo.AfterUse(getMiddlewares(afterMiddlewares)...)
	for _, child := range DefDynaRouter.Children {
		var group *Group
		for _, d := range child.Tree() {
			mws := getMiddlewares(d.Middlewares)
			switch d.Type {
			case GROUP:
				if group == nil {
					group = DefLessgo.Echo.Group(d.Prefix, mws...)
					break
				}
				group = group.Group(d.Prefix, mws...)
			case HANDLER:
				if group == nil {
					DefLessgo.Echo.Match(d.Methods, path.Join(d.Prefix, d.Param), handlerFuncMap[d.Handler], mws...)
					break
				}
				group.Match(d.Methods, path.Join(d.Prefix, d.Param), handlerFuncMap[d.Handler], mws...)
			}
		}
	}
}

func Logger() logs.Logger {
	return DefLessgo.Echo.Logger()
}
<|endoftext|>


<commit_before>package sqlz

import (
	"context"
	"database/sql"
	"strings"

	"github.com/jmoiron/sqlx"
)

// AuxStmt represents an auxiliary statement that is part
// of a WITH query. It includes the statement itself, and
// the name used for referencing it in other queries
type AuxStmt struct {
	Stmt SQLStmt
	As   string
}

// WithStmt represents a WITH statement
type WithStmt struct {
	// AuxStmts is the list of auxiliary statements that are
	// part of the WITH query
	AuxStmts []AuxStmt
	// MainStmt is the query's main statement in which the
	// auxiliary statements can be referenced
	MainStmt SQLStmt

	execer Ext
}

// With creates a new WithStmt object including
// the provided auxiliary statements
func (db *DB) With(stmt SQLStmt, as string) *WithStmt {
	return &WithStmt{
		AuxStmts: []AuxStmt{{stmt, as}},
		execer:   db.DB,
	}
}

// With creates a new WithStmt object including
// the provided auxiliary statements
func (tx *Tx) With(stmt SQLStmt, as string) *WithStmt {
	return &WithStmt{
		AuxStmts: []AuxStmt{{stmt, as}},
		execer:   tx.Tx,
	}
}

// And adds another auxiliary statement to the query
func (stmt *WithStmt) And(auxStmt SQLStmt, as string) *WithStmt {
	stmt.AuxStmts = append(stmt.AuxStmts, AuxStmt{auxStmt, as})
	return stmt
}

// Then sets the main statement of the WITH query
func (stmt *WithStmt) Then(mainStmt SQLStmt) *WithStmt {
	stmt.MainStmt = mainStmt
	return stmt
}

// ToSQL generates the WITH statement's SQL and returns a list of
// bindings. It is used internally by Exec, GetRow and GetAll, but is
// exported if you wish to use it directly.
func (stmt *WithStmt) ToSQL(rebind bool) (asSQL string, bindings []interface{}) {
	var clauses = []string{"WITH"}

	var auxStmts []string
	for _, aux := range stmt.AuxStmts {
		auxSQL, auxBindings := aux.Stmt.ToSQL(false)
		bindings = append(bindings, auxBindings...)
		auxStmts = append(auxStmts, aux.As+" AS ("+auxSQL+")")
	}

	clauses = append(clauses, strings.Join(auxStmts, ", "))

	mainSQL, mainBindings := stmt.MainStmt.ToSQL(false)
	clauses = append(clauses, mainSQL)
	bindings = append(bindings, mainBindings...)

	asSQL = strings.Join(clauses, " ")
	if db, ok := stmt.execer.(*sqlx.DB); ok {
		asSQL = db.Rebind(asSQL)
	} else if tx, ok := stmt.execer.(*sqlx.Tx); ok {
		asSQL = tx.Rebind(asSQL)
	}

	return asSQL, bindings
}

// Exec executes the WITH statement, returning the standard
// sql.Result struct and an error if the query failed.
func (stmt *WithStmt) Exec() (res sql.Result, err error) {
	asSQL, bindings := stmt.ToSQL(true)
	return stmt.execer.Exec(asSQL, bindings...)
}

// ExecContext executes the WITH statement, returning the standard
// sql.Result struct and an error if the query failed.
func (stmt *WithStmt) ExecContext(ctx context.Context) (res sql.Result, err error) {
	asSQL, bindings := stmt.ToSQL(true)
	return stmt.execer.ExecContext(ctx, asSQL, bindings...)
}

// GetRow executes a WITH statement whose main statement has
// a RETURNING clause expected to return one row, and loads
// the result into the provided variable (which may be a
// simple variable if only one column is returned, or a
// struct if multiple columns are returned)
func (stmt *WithStmt) GetRow(into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.Get(stmt.execer, into, asSQL, bindings...)
}

// GetRowContext executes a WITH statement whose main statement has
// a RETURNING clause expected to return one row, and loads
// the result into the provided variable (which may be a
// simple variable if only one column is returned, or a
// struct if multiple columns are returned)
func (stmt *WithStmt) GetRowContext(ctx context.Context, into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.GetContext(ctx, stmt.execer, into, asSQL, bindings...)
}

// GetAll executes a WITH statement whose main statement has
// a RETURNING clause expected to return multiple rows, and
// loads the result into the provided slice variable
func (stmt *WithStmt) GetAll(into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.Select(stmt.execer, into, asSQL, bindings...)
}

// GetAllContext executes a WITH statement whose main statement has
// a RETURNING clause expected to return multiple rows, and
// loads the result into the provided slice variable
func (stmt *WithStmt) GetAllContext(ctx context.Context, into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.SelectContext(ctx, stmt.execer, into, asSQL, bindings...)
}
<commit_msg>Support cursor for WITH statment<commit_after>package sqlz

import (
	"context"
	"database/sql"
	"strings"

	"github.com/jmoiron/sqlx"
)

// AuxStmt represents an auxiliary statement that is part
// of a WITH query. It includes the statement itself, and
// the name used for referencing it in other queries
type AuxStmt struct {
	Stmt SQLStmt
	As   string
}

// WithStmt represents a WITH statement
type WithStmt struct {
	// AuxStmts is the list of auxiliary statements that are
	// part of the WITH query
	AuxStmts []AuxStmt
	// MainStmt is the query's main statement in which the
	// auxiliary statements can be referenced
	MainStmt SQLStmt

	execer Ext
}

// With creates a new WithStmt object including
// the provided auxiliary statements
func (db *DB) With(stmt SQLStmt, as string) *WithStmt {
	return &WithStmt{
		AuxStmts: []AuxStmt{{stmt, as}},
		execer:   db.DB,
	}
}

// With creates a new WithStmt object including
// the provided auxiliary statements
func (tx *Tx) With(stmt SQLStmt, as string) *WithStmt {
	return &WithStmt{
		AuxStmts: []AuxStmt{{stmt, as}},
		execer:   tx.Tx,
	}
}

// And adds another auxiliary statement to the query
func (stmt *WithStmt) And(auxStmt SQLStmt, as string) *WithStmt {
	stmt.AuxStmts = append(stmt.AuxStmts, AuxStmt{auxStmt, as})
	return stmt
}

// Then sets the main statement of the WITH query
func (stmt *WithStmt) Then(mainStmt SQLStmt) *WithStmt {
	stmt.MainStmt = mainStmt
	return stmt
}

// ToSQL generates the WITH statement's SQL and returns a list of
// bindings. It is used internally by Exec, GetRow and GetAll, but is
// exported if you wish to use it directly.
func (stmt *WithStmt) ToSQL(rebind bool) (asSQL string, bindings []interface{}) {
	var clauses = []string{"WITH"}

	var auxStmts []string
	for _, aux := range stmt.AuxStmts {
		auxSQL, auxBindings := aux.Stmt.ToSQL(false)
		bindings = append(bindings, auxBindings...)
		auxStmts = append(auxStmts, aux.As+" AS ("+auxSQL+")")
	}

	clauses = append(clauses, strings.Join(auxStmts, ", "))

	mainSQL, mainBindings := stmt.MainStmt.ToSQL(false)
	clauses = append(clauses, mainSQL)
	bindings = append(bindings, mainBindings...)

	asSQL = strings.Join(clauses, " ")
	if db, ok := stmt.execer.(*sqlx.DB); ok {
		asSQL = db.Rebind(asSQL)
	} else if tx, ok := stmt.execer.(*sqlx.Tx); ok {
		asSQL = tx.Rebind(asSQL)
	}

	return asSQL, bindings
}

// Exec executes the WITH statement, returning the standard
// sql.Result struct and an error if the query failed.
func (stmt *WithStmt) Exec() (res sql.Result, err error) {
	asSQL, bindings := stmt.ToSQL(true)
	return stmt.execer.Exec(asSQL, bindings...)
}

// ExecContext executes the WITH statement, returning the standard
// sql.Result struct and an error if the query failed.
func (stmt *WithStmt) ExecContext(ctx context.Context) (res sql.Result, err error) {
	asSQL, bindings := stmt.ToSQL(true)
	return stmt.execer.ExecContext(ctx, asSQL, bindings...)
}

// GetRow executes a WITH statement whose main statement has
// a RETURNING clause expected to return one row, and loads
// the result into the provided variable (which may be a
// simple variable if only one column is returned, or a
// struct if multiple columns are returned)
func (stmt *WithStmt) GetRow(into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.Get(stmt.execer, into, asSQL, bindings...)
}

// GetRowContext executes a WITH statement whose main statement has
// a RETURNING clause expected to return one row, and loads
// the result into the provided variable (which may be a
// simple variable if only one column is returned, or a
// struct if multiple columns are returned)
func (stmt *WithStmt) GetRowContext(ctx context.Context, into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.GetContext(ctx, stmt.execer, into, asSQL, bindings...)
}

// GetAll executes a WITH statement whose main statement has
// a RETURNING clause expected to return multiple rows, and
// loads the result into the provided slice variable
func (stmt *WithStmt) GetAll(into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.Select(stmt.execer, into, asSQL, bindings...)
}

// GetAllContext executes a WITH statement whose main statement has
// a RETURNING clause expected to return multiple rows, and
// loads the result into the provided slice variable
func (stmt *WithStmt) GetAllContext(ctx context.Context, into interface{}) error {
	asSQL, bindings := stmt.ToSQL(true)
	return sqlx.SelectContext(ctx, stmt.execer, into, asSQL, bindings...)
}

// GetAllAsRows executes the WITH statement and returns an sqlx.Rows object
// to use for iteration. It is the caller's responsibility to close the cursor
// with Close().
func (stmt *WithStmt) GetAllAsRows() (rows *sqlx.Rows, err error) {
	asSQL, bindings := stmt.ToSQL(true)
	return stmt.execer.Queryx(asSQL, bindings...)
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"net"
	"os"
	"strings"
)

var clients = make(map[net.Conn]bool)

func main() {

	port := "2000"
	if os.Getenv("PORT") != "" {
		port = os.Getenv("PORT")
	}

	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		panic(err)
	}

	fmt.Println("War Operation Plan Response (WOPR) has initialized.\nRunning on port: " + port)

	for {
		client, err := listener.Accept()
		if err != nil {
			continue
		}

		go connectClient(client)
	}
}

func connectClient(client net.Conn) {

	// Clear Screen
	sendString(client, "\u001B[2J")
	sendString(client, "LOGON: ")

	for {
		buf := make([]byte, 4096)
		numBytes, err := client.Read(buf)
		if numBytes == 0 || err != nil {
			return
		}

		// If we get telnet commands, ignore them
		if buf[0] == 255 {
			continue
		}

		handleInput(string(buf[0:numBytes]), client)
	}
}

func handleInput(input string, client net.Conn) {

	input = stripInput(input)
	fmt.Println("handleInput:", input)

	if !clientLoggedIn(client) {
		disconnect := true

		switch input {
		case "JOSHUA":
			loginClient(client)
			sendString(client, "GREETING PROFESSOR FALKEN.\r\n")
			disconnect = false
		case "HELP", "HELP LOGON":
			sendString(client, "HELP NOT AVAILABLE.\r\n")
		default:
			sendString(client, "IDENTIFICATION NOT RECOGNIZED BY SYSTEM.\r\n")
		}

		if disconnect {
			sendString(client, "--CONNECTION TERMINATED--\r\n")
			client.Close()
		}
	} else {
		switch input {
		case "EXIT":
			client.Close()
		case "HELLO":
			sendString(client, "HOW ARE YOU FEELING TODAY?\r\n")
		case "I AM FINE. HOW ARE YOU?":
			sendString(client, "EXCELLENT. IT'S BEEN A LONG TIME.\r\n")
			sendString(client, "CAN YOU EXPLAIN THE REMOVAL OF YOUR USER ACCOUNT ON 6/23/73?\r\n")
		case "HELP GAMES":
			sendString(client, "'GAMES' REFERS TO MODELS, SIMULATIONS AND GAMES WHICH HAVE")
			sendString(client, " TACTICAL AND STRATEGIC APPLICATIONS\r\n")
		case "LIST GAMES":
			listGames(client)
		case "HELP SYSTEM":
			sendString(client, "HELP GAMES\r\nLIST GAMES\r\nEXIT\r\n")
		case "PEOPLE SOMETIMES MAKE MISTAKES":
			sendString(client, "YES THEY DO. SHALL WE PLAY A GAME?\r\n")
		case "LOVE TO. HOW ABOUT GLOBAL THERMONUCLEAR WAR":
			sendString(client, "WOULDN'T YOU PREFER A GOOD GAME OF CHESS?\r\n")
		case "LATER. LET'S PLAY GLOBAL THERMONUCLEAR WAR":
			sendString(client, "FINE\r\n")
		case "":
			// Do nothing
		default:
			sendString(client, "UNKNOWN COMMAND: '"+input+"'\r\n")
		}
	}
}

func listGames(client net.Conn) {
	sendString(client, "FALKEN'S MAZE\r\n")
	sendString(client, "BLACK JACK\r\n")
	sendString(client, "GIN RUMMY\r\n")
	sendString(client, "HEARTS\r\n")
	sendString(client, "BRIDGE\r\n")
	sendString(client, "CHECKERS\r\n")
	sendString(client, "CHESS\r\n")
	sendString(client, "POKER\r\n")
	sendString(client, "FIGHTER COMBAT\r\n")
	sendString(client, "GUERILLA ENGAGEMENT\r\n")
	sendString(client, "DESERT WARFARE\r\n")
	sendString(client, "AIR-TO-GROUND ACTIONS\r\n")
	sendString(client, "THEATERWIDE TACTICAL WARFARE\r\n")
	sendString(client, "THEATERWIDE BIOTOXIC AND CHEMICAL WARFARE\r\n\r\n")
	sendString(client, "GLOBAL THERMONUCLEAR WAR\r\n")
}

func loginClient(client net.Conn) {
	clients[client] = true
}

func clientLoggedIn(client net.Conn) bool {
	return clients[client]
}

func sendString(client net.Conn, msg string) {
	client.Write([]byte(msg))
}

func stripInput(input string) string {
	input = strings.Replace(input, "\r", "", -1)
	input = strings.Replace(input, "\n", "", -1)
	input = strings.ToUpper(input)

	return input
}
<commit_msg>Always use \r\n so windows emulators don't blow up<commit_after>package main

import (
	"fmt"
	"net"
	"os"
	"strings"
)

var clients = make(map[net.Conn]bool)

func main() {

	port := "2000"
	if os.Getenv("PORT") != "" {
		port = os.Getenv("PORT")
	}

	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		panic(err)
	}

	fmt.Println("War Operation Plan Response (WOPR) has initialized.\r\nRunning on port: " + port)

	for {
		client, err := listener.Accept()
		if err != nil {
			continue
		}

		go connectClient(client)
	}
}

func connectClient(client net.Conn) {

	// Clear Screen
	sendString(client, "\u001B[2J")
	sendString(client, "LOGON: ")

	for {
		buf := make([]byte, 4096)
		numBytes, err := client.Read(buf)
		if numBytes == 0 || err != nil {
			return
		}

		// If we get telnet commands, ignore them
		if buf[0] == 255 {
			continue
		}

		handleInput(string(buf[0:numBytes]), client)
	}
}

func handleInput(input string, client net.Conn) {

	input = stripInput(input)
	fmt.Println("handleInput:", input)

	if !clientLoggedIn(client) {
		disconnect := true

		switch input {
		case "JOSHUA":
			loginClient(client)
			sendString(client, "GREETING PROFESSOR FALKEN.\r\n")
			disconnect = false
		case "HELP", "HELP LOGON":
			sendString(client, "HELP NOT AVAILABLE.\r\n")
		default:
			sendString(client, "IDENTIFICATION NOT RECOGNIZED BY SYSTEM.\r\n")
		}

		if disconnect {
			sendString(client, "--CONNECTION TERMINATED--\r\n")
			client.Close()
		}
	} else {
		switch input {
		case "EXIT":
			client.Close()
		case "HELLO":
			sendString(client, "HOW ARE YOU FEELING TODAY?\r\n")
		case "I AM FINE. HOW ARE YOU?":
			sendString(client, "EXCELLENT. IT'S BEEN A LONG TIME.\r\n")
			sendString(client, "CAN YOU EXPLAIN THE REMOVAL OF YOUR USER ACCOUNT ON 6/23/73?\r\n")
		case "HELP GAMES":
			sendString(client, "'GAMES' REFERS TO MODELS, SIMULATIONS AND GAMES WHICH HAVE")
			sendString(client, " TACTICAL AND STRATEGIC APPLICATIONS\r\n")
		case "LIST GAMES":
			listGames(client)
		case "HELP SYSTEM":
			sendString(client, "HELP GAMES\r\nLIST GAMES\r\nEXIT\r\n")
		case "PEOPLE SOMETIMES MAKE MISTAKES":
			sendString(client, "YES THEY DO. SHALL WE PLAY A GAME?\r\n")
		case "LOVE TO. HOW ABOUT GLOBAL THERMONUCLEAR WAR":
			sendString(client, "WOULDN'T YOU PREFER A GOOD GAME OF CHESS?\r\n")
		case "LATER. LET'S PLAY GLOBAL THERMONUCLEAR WAR":
			sendString(client, "FINE\r\n")
		case "":
			// Do nothing
		default:
			sendString(client, "UNKNOWN COMMAND: '"+input+"'\r\n")
		}
	}
}

func listGames(client net.Conn) {
	sendString(client, "FALKEN'S MAZE\r\n")
	sendString(client, "BLACK JACK\r\n")
	sendString(client, "GIN RUMMY\r\n")
	sendString(client, "HEARTS\r\n")
	sendString(client, "BRIDGE\r\n")
	sendString(client, "CHECKERS\r\n")
	sendString(client, "CHESS\r\n")
	sendString(client, "POKER\r\n")
	sendString(client, "FIGHTER COMBAT\r\n")
	sendString(client, "GUERILLA ENGAGEMENT\r\n")
	sendString(client, "DESERT WARFARE\r\n")
	sendString(client, "AIR-TO-GROUND ACTIONS\r\n")
	sendString(client, "THEATERWIDE TACTICAL WARFARE\r\n")
	sendString(client, "THEATERWIDE BIOTOXIC AND CHEMICAL WARFARE\r\n\r\n")
	sendString(client, "GLOBAL THERMONUCLEAR WAR\r\n")
}

func loginClient(client net.Conn) {
	clients[client] = true
}

func clientLoggedIn(client net.Conn) bool {
	return clients[client]
}

func sendString(client net.Conn, msg string) {
	client.Write([]byte(msg))
}

func stripInput(input string) string {
	input = strings.Replace(input, "\r", "", -1)
	input = strings.Replace(input, "\n", "", -1)
	input = strings.ToUpper(input)

	return input
}
<|endoftext|>


<commit_before>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
package caddy

import (
	"github.com/admpub/nging/application/handler"
	"github.com/webx-top/echo"
)

func init() {
	handler.RegisterToGroup(`/caddy`, func(g echo.RouteRegister) {
		e := handler.Echo()
		g.Route(`GET,POST`, `/restart`, e.MetaHandler(echo.H{`name`: `重启Caddy服务`}, Restart))
		g.Route(`GET,POST`, `/stop`, e.MetaHandler(echo.H{`name`: `停止Caddy服务`}, Stop))
		g.Route(`GET,POST`, `/log`, e.MetaHandler(echo.H{`name`: `显示Caddy日志`}, Log))
		g.Route(`GET`, `/addon_form`, e.MetaHandler(echo.H{`name`: `Caddy配置表单`}, AddonForm))
		g.Route(`GET`, `/vhost`, e.MetaHandler(echo.H{`name`: `网站列表`}, VhostIndex))
		g.Route(`GET,POST`, `/vhost_add`, e.MetaHandler(echo.H{`name`: `添加网站`}, VhostAdd))
		g.Route(`GET,POST`, `/vhost_edit`, e.MetaHandler(echo.H{`name`: `编辑网站`}, VhostEdit))
		g.Route(`GET,POST`, `/vhost_delete`, e.MetaHandler(echo.H{`name`: `删除网站`}, VhostDelete))
		g.Route(`GET,POST`, `/vhost_file`, e.MetaHandler(echo.H{`name`: `管理网站文件`}, VhostFile))
		g.Route(`GET`, `/vhost_build`, e.MetaHandler(echo.H{`name`: `生成Caddyfile`}, Vhostbuild))
		g.Route(`GET,POST`, `/log_show`, LogShow)
		g.Route(`GET,POST`, `/vhost_log`, VhostLog)

		g.Route(`GET`, `/group`, Group)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU Affero General Public License as published
   by the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU Affero General Public License for more details.

   You should have received a copy of the GNU Affero General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/
package caddy

import (
	"github.com/admpub/nging/application/handler"
	"github.com/admpub/nging/application/library/common"
	"github.com/admpub/nging/application/model"
	"github.com/admpub/tail"
	"github.com/webx-top/echo"
)

func init() {
	handler.RegisterToGroup(`/caddy`, func(g echo.RouteRegister) {
		e := handler.Echo()
		g.Route(`GET,POST`, `/restart`, e.MetaHandler(echo.H{`name`: `重启Caddy服务`}, Restart))
		g.Route(`GET,POST`, `/stop`, e.MetaHandler(echo.H{`name`: `停止Caddy服务`}, Stop))
		g.Route(`GET,POST`, `/log`, e.MetaHandler(echo.H{`name`: `显示Caddy日志`}, Log))
		g.Route(`GET`, `/addon_form`, e.MetaHandler(echo.H{`name`: `Caddy配置表单`}, AddonForm))
		g.Route(`GET`, `/vhost`, e.MetaHandler(echo.H{`name`: `网站列表`}, VhostIndex))
		g.Route(`GET,POST`, `/vhost_add`, e.MetaHandler(echo.H{`name`: `添加网站`}, VhostAdd))
		g.Route(`GET,POST`, `/vhost_edit`, e.MetaHandler(echo.H{`name`: `编辑网站`}, VhostEdit))
		g.Route(`GET,POST`, `/vhost_delete`, e.MetaHandler(echo.H{`name`: `删除网站`}, VhostDelete))
		g.Route(`GET,POST`, `/vhost_file`, e.MetaHandler(echo.H{`name`: `管理网站文件`}, VhostFile))
		g.Route(`GET`, `/vhost_build`, e.MetaHandler(echo.H{`name`: `生成Caddyfile`}, Vhostbuild))
		g.Route(`GET,POST`, `/log_show`, LogShow)
		g.Route(`GET,POST`, `/vhost_log`, VhostLog)

		g.Route(`GET`, `/group`, Group)
		g.Route(`GET,POST`, `/group_add`, GroupAdd)
		g.Route(`GET,POST`, `/group_edit`, GroupEdit)
		g.Route(`GET,POST`, `/group_delete`, GroupDelete)
	})

	common.LogParsers[`access`] = func(line *tail.Line) (interface{}, error) {
		logM := model.NewAccessLog(nil)
		err := logM.Parse(line.Text)
		return logM.AccessLog, err
	}
}
<|endoftext|>


<commit_before>package aws

import (
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsElasticacheCluster() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticacheClusterCreate,
		Read:   resourceAwsElasticacheClusterRead,
		Delete: resourceAwsElasticacheClusterDelete,

		Schema: map[string]*schema.Schema{
			"cluster_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"engine": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"node_type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"num_cache_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},
			"parameter_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				ForceNew: true,
			},
			"port": &schema.Schema{
				Type:     schema.TypeInt,
				Default:  11211,
				Optional: true,
				ForceNew: true,
			},
			"engine_version": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"subnet_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"security_group_names": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			"security_group_ids": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			// Exported Attributes
			"cache_nodes": &schema.Schema{
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"address": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"port": &schema.Schema{
							Type:     schema.TypeInt,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	clusterId := d.Get("cluster_id").(string)
	nodeType := d.Get("node_type").(string)           // e.g) cache.m1.small
	numNodes := int64(d.Get("num_cache_nodes").(int)) // 2
	engine := d.Get("engine").(string)                // memcached
	engineVersion := d.Get("engine_version").(string) // 1.4.14
	port := int64(d.Get("port").(int))                // 11211
	subnetGroupName := d.Get("subnet_group_name").(string)
	securityNameSet := d.Get("security_group_names").(*schema.Set)
	securityIdSet := d.Get("security_group_ids").(*schema.Set)
	paramGroupName := d.Get("parameter_group_name").(string) // default.memcached1.4

	securityNames := expandStringList(securityNameSet.List())
	securityIds := expandStringList(securityIdSet.List())

	req := &elasticache.CreateCacheClusterInput{
		CacheClusterID:          aws.String(clusterId),
		CacheNodeType:           aws.String(nodeType),
		NumCacheNodes:           aws.Long(numNodes),
		Engine:                  aws.String(engine),
		EngineVersion:           aws.String(engineVersion),
		Port:                    aws.Long(port),
		CacheSubnetGroupName:    aws.String(subnetGroupName),
		CacheSecurityGroupNames: securityNames,
		SecurityGroupIDs:        securityIds,
		CacheParameterGroupName: aws.String(paramGroupName),
	}

	_, err := conn.CreateCacheCluster(req)
	if err != nil {
		return fmt.Errorf("Error creating Elasticache: %s", err)
	}

	pending := []string{"creating"}
	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     "available",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "available", pending),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id())
	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr)
	}

	d.SetId(clusterId)

        return resourceAwsElasticacheClusterRead(d, meta)
}

func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn
	req := &elasticache.DescribeCacheClustersInput{
                CacheClusterID:    aws.String(d.Id()),
                ShowCacheNodeInfo: aws.Boolean(true),
	}

	res, err := conn.DescribeCacheClusters(req)
	if err != nil {
		return err
	}

	if len(res.CacheClusters) == 1 {
		c := res.CacheClusters[0]
		d.Set("cluster_id", c.CacheClusterID)
		d.Set("node_type", c.CacheNodeType)
		d.Set("num_cache_nodes", c.NumCacheNodes)
		d.Set("engine", c.Engine)
		d.Set("engine_version", c.EngineVersion)
		if c.ConfigurationEndpoint != nil {
			d.Set("port", c.ConfigurationEndpoint.Port)
		}
		d.Set("subnet_group_name", c.CacheSubnetGroupName)
		d.Set("security_group_names", c.CacheSecurityGroups)
		d.Set("security_group_ids", c.SecurityGroups)
		d.Set("parameter_group_name", c.CacheParameterGroup)

		if err := setCacheNodeData(d, c); err != nil {
			return err
		}
	}

	return nil
}

func setCacheNodeData(d *schema.ResourceData, c *elasticache.CacheCluster) error {
	sortedCacheNodes := make([]*elasticache.CacheNode, len(c.CacheNodes))
	copy(sortedCacheNodes, c.CacheNodes)
	sort.Sort(byCacheNodeId(sortedCacheNodes))

	cacheNodeData := make([]map[string]interface{}, 0, len(sortedCacheNodes))

	for _, node := range sortedCacheNodes {
		if node.CacheNodeID == nil || node.Endpoint == nil || node.Endpoint.Address == nil || node.Endpoint.Port == nil {
			return fmt.Errorf("Unexpected nil pointer in: %#v", node)
		}
		cacheNodeData = append(cacheNodeData, map[string]interface{}{
                        "id":      *node.CacheNodeID,
                        "address": *node.Endpoint.Address,
                        "port":    int(*node.Endpoint.Port),
		})
	}

	return d.Set("cache_nodes", cacheNodeData)
}

type byCacheNodeId []*elasticache.CacheNode

func (b byCacheNodeId) Len() int      { return len(b) }
func (b byCacheNodeId) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byCacheNodeId) Less(i, j int) bool {
	return b[i].CacheNodeID != nil && b[j].CacheNodeID != nil &&
		*b[i].CacheNodeID < *b[j].CacheNodeID
}

func resourceAwsElasticacheClusterDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	req := &elasticache.DeleteCacheClusterInput{
		CacheClusterID: aws.String(d.Id()),
	}
	_, err := conn.DeleteCacheCluster(req)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Waiting for deletion: %v", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"creating", "available", "deleting", "incompatible-parameters", "incompatible-network", "restore-failed"},
		Target:     "",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "", []string{}),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to delete: %s", d.Id(), sterr)
	}

	d.SetId("")

	return nil
}

func CacheClusterStateRefreshFunc(conn *elasticache.ElastiCache, clusterID, givenState string, pending []string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterID: aws.String(clusterID),
		})
		if err != nil {
			apierr := err.(aws.APIError)
			log.Printf("[DEBUG] message: %v, code: %v", apierr.Message, apierr.Code)
			if apierr.Message == fmt.Sprintf("CacheCluster not found: %v", clusterID) {
				log.Printf("[DEBUG] Detect deletion")
				return nil, "", nil
			}

			log.Printf("[ERROR] CacheClusterStateRefreshFunc: %s", err)
			return nil, "", err
		}

		c := resp.CacheClusters[0]
		log.Printf("[DEBUG] status: %v", *c.CacheClusterStatus)

		// return the current state if it's in the pending array
		for _, p := range pending {
			s := *c.CacheClusterStatus
			if p == s {
				log.Printf("[DEBUG] Return with status: %v", *c.CacheClusterStatus)
				return c, p, nil
			}
		}

		// return given state if it's not in pending
		if givenState != "" {
			return c, givenState, nil
		}
		log.Printf("[DEBUG] current status: %v", *c.CacheClusterStatus)
		return c, *c.CacheClusterStatus, nil
	}
}
<commit_msg>make parameter group optional<commit_after>package aws

import (
	"fmt"
	"log"
	"sort"
	"time"

	"github.com/awslabs/aws-sdk-go/aws"
	"github.com/awslabs/aws-sdk-go/service/elasticache"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
)

func resourceAwsElasticacheCluster() *schema.Resource {
	return &schema.Resource{
		Create: resourceAwsElasticacheClusterCreate,
		Read:   resourceAwsElasticacheClusterRead,
		Delete: resourceAwsElasticacheClusterDelete,

		Schema: map[string]*schema.Schema{
			"cluster_id": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"engine": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"node_type": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},
			"num_cache_nodes": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},
			"parameter_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"port": &schema.Schema{
				Type:     schema.TypeInt,
				Default:  11211,
				Optional: true,
				ForceNew: true,
			},
			"engine_version": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"subnet_group_name": &schema.Schema{
				Type:     schema.TypeString,
				Optional: true,
				Computed: true,
				ForceNew: true,
			},
			"security_group_names": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			"security_group_ids": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				Computed: true,
				ForceNew: true,
				Elem:     &schema.Schema{Type: schema.TypeString},
				Set: func(v interface{}) int {
					return hashcode.String(v.(string))
				},
			},
			// Exported Attributes
			"cache_nodes": &schema.Schema{
				Type:     schema.TypeList,
				Computed: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"id": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"address": &schema.Schema{
							Type:     schema.TypeString,
							Computed: true,
						},
						"port": &schema.Schema{
							Type:     schema.TypeInt,
							Computed: true,
						},
					},
				},
			},
		},
	}
}

func resourceAwsElasticacheClusterCreate(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	clusterId := d.Get("cluster_id").(string)
	nodeType := d.Get("node_type").(string)           // e.g) cache.m1.small
	numNodes := int64(d.Get("num_cache_nodes").(int)) // 2
	engine := d.Get("engine").(string)                // memcached
	engineVersion := d.Get("engine_version").(string) // 1.4.14
	port := int64(d.Get("port").(int))                // 11211
	subnetGroupName := d.Get("subnet_group_name").(string)
	securityNameSet := d.Get("security_group_names").(*schema.Set)
	securityIdSet := d.Get("security_group_ids").(*schema.Set)

	securityNames := expandStringList(securityNameSet.List())
	securityIds := expandStringList(securityIdSet.List())

	req := &elasticache.CreateCacheClusterInput{
		CacheClusterID:          aws.String(clusterId),
		CacheNodeType:           aws.String(nodeType),
		NumCacheNodes:           aws.Long(numNodes),
		Engine:                  aws.String(engine),
		EngineVersion:           aws.String(engineVersion),
		Port:                    aws.Long(port),
		CacheSubnetGroupName:    aws.String(subnetGroupName),
		CacheSecurityGroupNames: securityNames,
		SecurityGroupIDs:        securityIds,
	}

	// parameter groups are optional and can be defaulted by AWS
	if v, ok := d.GetOk("parameter_group_name"); ok {
		req.CacheParameterGroupName = aws.String(v.(string))
	}

	_, err := conn.CreateCacheCluster(req)
	if err != nil {
		return fmt.Errorf("Error creating Elasticache: %s", err)
	}

	pending := []string{"creating"}
	stateConf := &resource.StateChangeConf{
		Pending:    pending,
		Target:     "available",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "available", pending),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	log.Printf("[DEBUG] Waiting for state to become available: %v", d.Id())
	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to be created: %s", d.Id(), sterr)
	}

	d.SetId(clusterId)

	return resourceAwsElasticacheClusterRead(d, meta)
}

func resourceAwsElasticacheClusterRead(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn
	req := &elasticache.DescribeCacheClustersInput{
		CacheClusterID:    aws.String(d.Id()),
		ShowCacheNodeInfo: aws.Boolean(true),
	}

	res, err := conn.DescribeCacheClusters(req)
	if err != nil {
		return err
	}

	if len(res.CacheClusters) == 1 {
		c := res.CacheClusters[0]
		d.Set("cluster_id", c.CacheClusterID)
		d.Set("node_type", c.CacheNodeType)
		d.Set("num_cache_nodes", c.NumCacheNodes)
		d.Set("engine", c.Engine)
		d.Set("engine_version", c.EngineVersion)
		if c.ConfigurationEndpoint != nil {
			d.Set("port", c.ConfigurationEndpoint.Port)
		}
		d.Set("subnet_group_name", c.CacheSubnetGroupName)
		d.Set("security_group_names", c.CacheSecurityGroups)
		d.Set("security_group_ids", c.SecurityGroups)
		d.Set("parameter_group_name", c.CacheParameterGroup)

		if err := setCacheNodeData(d, c); err != nil {
			return err
		}
	}

	return nil
}

func setCacheNodeData(d *schema.ResourceData, c *elasticache.CacheCluster) error {
	sortedCacheNodes := make([]*elasticache.CacheNode, len(c.CacheNodes))
	copy(sortedCacheNodes, c.CacheNodes)
	sort.Sort(byCacheNodeId(sortedCacheNodes))

	cacheNodeData := make([]map[string]interface{}, 0, len(sortedCacheNodes))

	for _, node := range sortedCacheNodes {
		if node.CacheNodeID == nil || node.Endpoint == nil || node.Endpoint.Address == nil || node.Endpoint.Port == nil {
			return fmt.Errorf("Unexpected nil pointer in: %#v", node)
		}
		cacheNodeData = append(cacheNodeData, map[string]interface{}{
			"id":      *node.CacheNodeID,
			"address": *node.Endpoint.Address,
			"port":    int(*node.Endpoint.Port),
		})
	}

	return d.Set("cache_nodes", cacheNodeData)
}

type byCacheNodeId []*elasticache.CacheNode

func (b byCacheNodeId) Len() int      { return len(b) }
func (b byCacheNodeId) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
func (b byCacheNodeId) Less(i, j int) bool {
	return b[i].CacheNodeID != nil && b[j].CacheNodeID != nil &&
		*b[i].CacheNodeID < *b[j].CacheNodeID
}

func resourceAwsElasticacheClusterDelete(d *schema.ResourceData, meta interface{}) error {
	conn := meta.(*AWSClient).elasticacheconn

	req := &elasticache.DeleteCacheClusterInput{
		CacheClusterID: aws.String(d.Id()),
	}
	_, err := conn.DeleteCacheCluster(req)
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Waiting for deletion: %v", d.Id())
	stateConf := &resource.StateChangeConf{
		Pending:    []string{"creating", "available", "deleting", "incompatible-parameters", "incompatible-network", "restore-failed"},
		Target:     "",
		Refresh:    CacheClusterStateRefreshFunc(conn, d.Id(), "", []string{}),
		Timeout:    10 * time.Minute,
		Delay:      10 * time.Second,
		MinTimeout: 3 * time.Second,
	}

	_, sterr := stateConf.WaitForState()
	if sterr != nil {
		return fmt.Errorf("Error waiting for elasticache (%s) to delete: %s", d.Id(), sterr)
	}

	d.SetId("")

	return nil
}

func CacheClusterStateRefreshFunc(conn *elasticache.ElastiCache, clusterID, givenState string, pending []string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		resp, err := conn.DescribeCacheClusters(&elasticache.DescribeCacheClustersInput{
			CacheClusterID: aws.String(clusterID),
		})
		if err != nil {
			apierr := err.(aws.APIError)
			log.Printf("[DEBUG] message: %v, code: %v", apierr.Message, apierr.Code)
			if apierr.Message == fmt.Sprintf("CacheCluster not found: %v", clusterID) {
				log.Printf("[DEBUG] Detect deletion")
				return nil, "", nil
			}

			log.Printf("[ERROR] CacheClusterStateRefreshFunc: %s", err)
			return nil, "", err
		}

		c := resp.CacheClusters[0]
		log.Printf("[DEBUG] status: %v", *c.CacheClusterStatus)

		// return the current state if it's in the pending array
		for _, p := range pending {
			s := *c.CacheClusterStatus
			if p == s {
				log.Printf("[DEBUG] Return with status: %v", *c.CacheClusterStatus)
				return c, p, nil
			}
		}

		// return given state if it's not in pending
		if givenState != "" {
			return c, givenState, nil
		}
		log.Printf("[DEBUG] current status: %v", *c.CacheClusterStatus)
		return c, *c.CacheClusterStatus, nil
	}
}
<|endoftext|>


<commit_before>package collectors

import (
	"strings"
	"time"

	"github.com/StackExchange/scollector/opentsdb"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_omreport_chassis_linux, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_system_linux, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_enclosure_linux, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_vdisk_linux, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_controller_linux, Interval: time.Minute * 5})

}

func c_omreport_chassis_linux() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 || fields[0] == "SEVERITY" {
			return
		}
		sev := 0
		if fields[0] != "Ok" {
			sev = 1
		}
		component := strings.Replace(fields[1], " ", "_", -1)
		Add(&md, "hw.chassis", sev, opentsdb.TagSet{"component": component})
	}, "/opt/dell/srvadmin/bin/omreport", "chassis", "-fmt", "ssv")
	return md
}

func c_omreport_system_linux() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 || fields[0] == "SEVERITY" {
			return
		}
		sev := 0
		if fields[0] != "Ok" {
			sev = 1
		}
		component := strings.Replace(fields[1], " ", "_", -1)
		Add(&md, "hw.system", sev, opentsdb.TagSet{"component": component})
	}, "/opt/dell/srvadmin/bin/omreport", "system", "-fmt", "ssv")
	return md
}

func c_omreport_storage_enclosure_linux() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" {
			sev = 1
		}
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.enclosure", sev, opentsdb.TagSet{"id": id})
	}, "/opt/dell/srvadmin/bin/omreport", "storage", "enclosure", "-fmt", "ssv")
	return md
}

func c_omreport_storage_vdisk_linux() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" {
			sev = 1
		}
		//Need to find out what the various ID formats might be
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.vdisk", sev, opentsdb.TagSet{"id": id})
	}, "/opt/dell/srvadmin/bin/omreport", "storage", "vdisk", "-fmt", "ssv")
	return md
}

func c_omreport_storage_controller_linux() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" {
			sev = 1
		}
		//Need to find out what the various ID formats might be
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.controller", sev, opentsdb.TagSet{"id": id})
	}, "/opt/dell/srvadmin/bin/omreport", "storage", "controller", "-fmt", "ssv")
	return md
}
<commit_msg>cmd/scollector: More Dell HW Monitoring<commit_after>package collectors

import (
	"strings"
	"time"

	"github.com/StackExchange/scollector/opentsdb"
)

func init() {
	collectors = append(collectors, &IntervalCollector{F: c_omreport_chassis, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_system, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_enclosure, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_vdisk, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_controller, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_storage_battery, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_ps, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_ps_amps, Interval: time.Minute * 5})
	collectors = append(collectors, &IntervalCollector{F: c_omreport_ps_volts, Interval: time.Minute * 5})

}

func c_omreport_chassis() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 || fields[0] == "SEVERITY" {
			return
		}
		sev := 0
		if fields[0] != "Ok" {
			sev = 1
		}
		component := strings.Replace(fields[1], " ", "_", -1)
		Add(&md, "hw.chassis", sev, opentsdb.TagSet{"component": component})
	}, "omreport", "chassis", "-fmt", "ssv")
	return md
}

func c_omreport_system() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 || fields[0] == "SEVERITY" {
			return
		}
		sev := 0
		if fields[0] != "Ok" {
			sev = 1
		}
		component := strings.Replace(fields[1], " ", "_", -1)
		Add(&md, "hw.system", sev, opentsdb.TagSet{"component": component})
	}, "omreport", "system", "-fmt", "ssv")
	return md
}

func c_omreport_storage_enclosure() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" && fields[1] != "Non-Critical" {
			sev = 1
		}
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.enclosure", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "storage", "enclosure", "-fmt", "ssv")
	return md
}

func c_omreport_storage_vdisk() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" && fields[1] != "Non-Critical" {
			sev = 1
		}
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.vdisk", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "storage", "vdisk", "-fmt", "ssv")
	return md
}

func c_omreport_ps() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "Index" {
			return
		}
		sev := 0
		if fields[1] != "Ok" {
			sev = 1
		}
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.ps", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "chassis", "pwrsupplies", "-fmt", "ssv")
	return md
}

func c_omreport_ps_amps() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 2 || !strings.Contains(fields[0], "Current") {
			return
		}
		i_fields := strings.Fields(fields[0])
		v_fields := strings.Fields(fields[1])
		if len(i_fields) < 2 && len(v_fields) < 2 {
			return
		}
		Add(&md, "hw.ps.current", v_fields[0], opentsdb.TagSet{"id": i_fields[0]})
	}, "omreport", "chassis", "pwrmonitoring", "-fmt", "ssv")
	return md
}

func c_omreport_ps_volts() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) != 8 || !strings.Contains(fields[2], "Voltage") || fields[3] == "[N/A]" {
			return
		}
		i_fields := strings.Fields(fields[2])
		v_fields := strings.Fields(fields[3])
		if len(i_fields) < 2 && len(v_fields) < 2 {
			return
		}
		Add(&md, "hw.ps.volts", v_fields[0], opentsdb.TagSet{"id": i_fields[0]})
	}, "omreport", "chassis", "volts", "-fmt", "ssv")
	return md
}

func c_omreport_storage_battery() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" && fields[1] != "Non-Critical" {
			sev = 1
		}
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.battery", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "storage", "battery", "-fmt", "ssv")
	return md
}

func c_omreport_storage_controller() opentsdb.MultiDataPoint {
	var md opentsdb.MultiDataPoint
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" && fields[1] != "Non-Critical" {
			sev = 1
		}
		c_omreport_storage_pdisk(fields[0], &md)
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(&md, "hw.storage.controller", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "storage", "controller", "-fmt", "ssv")
	return md
}

// The following is called from controller, since it needs the encapsulating id
func c_omreport_storage_pdisk(id string, md *opentsdb.MultiDataPoint) {
	readCommand(func(line string) {
		fields := strings.Split(line, ";")
		if len(fields) < 3 || fields[0] == "ID" {
			return
		}
		sev := 0
		if fields[1] != "Ok" && fields[1] != "Non-Critical" {
			sev = 1
		}
		//Need to find out what the various ID formats might be
		id := strings.Replace(fields[0], ":", "_", -1)
		Add(md, "hw.storage.pdisk", sev, opentsdb.TagSet{"id": id})
	}, "omreport", "storage", "pdisk", "controller="+id, "-fmt", "ssv")
}
<|endoftext|>


<commit_before>package main

import (
	"strings"

	"github.com/juju/errors"

	"github.com/rancher/go-rancher-metadata/metadata"
)

//////////////////////////////////////////////////////////////////////////////////
type ServiceWrap struct {
	metadata.Service
}

//////////////////////////////////////////////////////////////////////////////////
type ContainerWrap struct {
	metadata.Container
}

//////////////////////////////////////////////////////////////////////////////////
func (p ContainerWrap) PortInternal(idx int) (string, error) {
	if len(p.Ports) == 0 {
		return "", nil
	}

	if idx >= len(p.Ports) {
		return "", errors.Errorf("PortInternal: index %d out of range", idx)
	}

	part := p.Ports[idx]
	if part == "" {
		return part, nil
	}

	printDebug(part)
	items := strings.Split(part, ":")
	part = items[len(items)-1]
	if strings.Contains(part, "/") {
		part = strings.Split(part, "/")[0]
	}

	return part, nil

}

//////////////////////////////////////////////////////////////////////////////////
func (p ContainerWrap) LabelByKey(key string) (string, error) {
	if val, ok := p.Labels[key]; ok {
		return val, nil
	}

	printDebug("LabelByKey: key %q is not found", key)
	return "", nil
}

//////////////////////////////////////////////////////////////////////////////////
type HostWrap struct {
	metadata.Host
}
<commit_msg>autopush@1447077466<commit_after>package main

import (
	"strings"

	"github.com/juju/errors"

	"github.com/rancher/go-rancher-metadata/metadata"
)

//////////////////////////////////////////////////////////////////////////////////
type ServiceWrap struct {
	metadata.Service
}

//////////////////////////////////////////////////////////////////////////////////
type ContainerWrap struct {
	metadata.Container
}

//////////////////////////////////////////////////////////////////////////////////
func (p ContainerWrap) PortInternal(idx int) (string, error) {
	if len(p.Ports) == 0 {
		return "", nil
	}

	if idx >= len(p.Ports) {
		return "", errors.Errorf("PortInternal:: index %d out of range", idx)
	}

	part := p.Ports[idx]
	if part == "" {
		return part, nil
	}

	printDebug(part)
	items := strings.Split(part, ":")
	part = items[len(items)-1]
	if strings.Contains(part, "/") {
		part = strings.Split(part, "/")[0]
	}

	return part, nil

}

//////////////////////////////////////////////////////////////////////////////////
func (p ContainerWrap) LabelByKey(key string) (string, error) {
	if val, ok := p.Labels[key]; ok {
		return val, nil
	}

	printDebug("LabelByKey:: container: %s: key %q is not found", p.Name, key)
	return "", nil
}

//////////////////////////////////////////////////////////////////////////////////
type HostWrap struct {
	metadata.Host
}
<|endoftext|>


<commit_before>package raft

import (
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
	"net/url"
	"strconv"
)

type appendEntryRequest struct {
	term         int
	leaderId     string
	prevLogIndex int
	prevLogTerm  int
	entry        db.Entry
	leaderCommit int
	returnChan   chan bool
}

type appendEntryResponse struct {
	term    int
	success bool
}

type followerResponse struct {
	serverIndex int
	resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	v := url.Values{}
	v.Set("term", strconv.Itoa(s.term))
	v.Set("leaderID", s.id)
	v.Set("prevLogIndex", strconv.Itoa(len(s.db.Log.Entries)))
	v.Set("entry", entry.Command)
	v.Set("leaderCommit", strconv.Itoa(s.commitIndex))
	resp, err := http.PostForm(follower+"/appendEntry", v)
	if err != nil {
		fmt.Println("Couldn't send append entry request to " + follower)
	}
	r := &appendEntryResponse{}
	json.NewDecoder(resp.Body).Decode(r)
	defer resp.Body.Close()
	if r.term > s.term {
		s.term = r.term
		s.state = "follower"
		s.electionTimeout.reset()
	}
	if r.success {
		s.term = r.term
		s.nextIndex[followerIndex]++
		s.matchIndex[followerIndex]++
		followerResp := &followerResponse{followerIndex, *r}
		respChan <- *followerResp
	} else {
		s.nextIndex[followerIndex]--
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	}
}

func (s *server) handleAppendEntryRequest(req appendEntryRequest) {
	if req.term < s.term {
		req.returnChan <- false
	} else if s.db.Log.Entries[req.prevLogIndex].Term != req.prevLogTerm {
		req.returnChan <- false
	} else {
		if s.db.Log.Entries[req.prevLogIndex+1].Term != req.term {
			// If existing entry conflicts with new entry
			// Delete entry and all that follow it
			s.db.Log.SetEntries(s.db.Log.Entries[:req.prevLogIndex])
		}
		s.db.Log.AppendEntry(req.entry)
		if req.leaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.leaderCommit < req.prevLogIndex+1 {
				s.commitIndex = req.leaderCommit
			} else {
				s.commitIndex = req.prevLogIndex + 1
			}
		}
		req.returnChan <- true
	}
}
<commit_msg>if append entry request fails, try again (and exit the function)<commit_after>package raft

import (
	"encoding/json"
	"fmt"
	"github.com/arpith/mmapd/db"
	"net/http"
	"net/url"
	"strconv"
)

type appendEntryRequest struct {
	term         int
	leaderId     string
	prevLogIndex int
	prevLogTerm  int
	entry        db.Entry
	leaderCommit int
	returnChan   chan bool
}

type appendEntryResponse struct {
	term    int
	success bool
}

type followerResponse struct {
	serverIndex int
	resp        appendEntryResponse
}

func (s *server) appendEntry(command string, isCommitted chan bool) {
	entry := &db.Entry{command, s.term}
	index := -1
	if command != "" {
		s.db.Log.AppendEntry(*entry)
		index = len(s.db.Log.Entries)
	}
	respChan := make(chan followerResponse)
	for i := 0; i < len(s.config); i++ {
		if s.config[i] != s.id {
			go s.sendAppendEntryRequest(i, *entry, respChan)
		}
	}
	responseCount := 0
	if len(s.config) > 1 {
		for {
			_ = <-respChan
			responseCount++
			for N := s.commitIndex + 1; N < len(s.db.Log.Entries); N++ {
				//Check if there exists an N > commitIndex
				count := 0
				for i := 0; i < len(s.matchIndex); i++ {
					if s.matchIndex[i] >= N {
						count++
					}
				}
				// Check if a majority of matchIndex[i] >= N
				cond1 := count > len(s.matchIndex)/2
				// Check if log[N].term == currentTerm
				cond2 := s.db.Log.Entries[N].Term == s.term
				if cond1 && cond2 {
					// Set commitIndex to N
					s.commitIndex = N
				} else {
					break
				}
			}
			if s.commitIndex == index {
				isCommitted <- true
			}
		}
	} else {
		if command != "" {
			s.commitIndex++
			isCommitted <- true
		}
	}
}

func (s *server) sendAppendEntryRequest(followerIndex int, entry db.Entry, respChan chan followerResponse) {
	follower := s.config[followerIndex]
	v := url.Values{}
	v.Set("term", strconv.Itoa(s.term))
	v.Set("leaderID", s.id)
	v.Set("prevLogIndex", strconv.Itoa(len(s.db.Log.Entries)))
	v.Set("entry", entry.Command)
	v.Set("leaderCommit", strconv.Itoa(s.commitIndex))
	resp, err := http.PostForm(follower+"/appendEntry", v)
	if err != nil {
		fmt.Println("Couldn't send append entry request to " + follower)
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
		return
	}
	r := &appendEntryResponse{}
	json.NewDecoder(resp.Body).Decode(r)
	defer resp.Body.Close()
	if r.term > s.term {
		s.term = r.term
		s.state = "follower"
		s.electionTimeout.reset()
	}
	if r.success {
		s.term = r.term
		s.nextIndex[followerIndex]++
		s.matchIndex[followerIndex]++
		followerResp := &followerResponse{followerIndex, *r}
		respChan <- *followerResp
	} else {
		s.nextIndex[followerIndex]--
		go s.sendAppendEntryRequest(followerIndex, entry, respChan)
	}
}

func (s *server) handleAppendEntryRequest(req appendEntryRequest) {
	if req.term < s.term {
		req.returnChan <- false
	} else if s.db.Log.Entries[req.prevLogIndex].Term != req.prevLogTerm {
		req.returnChan <- false
	} else {
		if s.db.Log.Entries[req.prevLogIndex+1].Term != req.term {
			// If existing entry conflicts with new entry
			// Delete entry and all that follow it
			s.db.Log.SetEntries(s.db.Log.Entries[:req.prevLogIndex])
		}
		s.db.Log.AppendEntry(req.entry)
		if req.leaderCommit < s.commitIndex {
			// Set commit index to the min of the leader's commit index and index of last new entry
			if req.leaderCommit < req.prevLogIndex+1 {
				s.commitIndex = req.leaderCommit
			} else {
				s.commitIndex = req.prevLogIndex + 1
			}
		}
		req.returnChan <- true
	}
}
<|endoftext|>


<commit_before>package core

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringSubscriptionCollector interface {
	RequestStopAreaUpdate(request *StopAreaUpdateRequest)
	HandleNotifyStopMonitoring(delivery *siri.XMLStopMonitoringResponse)
}

type SIRIStopMonitoringSubscriptionCollector struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	Partner                  Partner
	stopAreaUpdateSubscriber StopAreaUpdateSubscriber
}

type SIRIStopMonitoringSubscriptionCollectorFactory struct{}

func (factory *SIRIStopMonitoringSubscriptionCollectorFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRIStopMonitoringSubscriptionCollector(partner)
}

func (factory *SIRIStopMonitoringSubscriptionCollectorFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("local_credential")
	return ok
}

func NewSIRIStopMonitoringSubscriptionCollector(partner *Partner) *SIRIStopMonitoringSubscriptionCollector {
	siriStopMonitoringSubscriptionCollector := &SIRIStopMonitoringSubscriptionCollector{}
	siriStopMonitoringSubscriptionCollector.partner = partner
	manager := partner.Referential().CollectManager()
	siriStopMonitoringSubscriptionCollector.stopAreaUpdateSubscriber = manager.BroadcastStopAreaUpdateEvent

	return siriStopMonitoringSubscriptionCollector
}

func (connector *SIRIStopMonitoringSubscriptionCollector) RequestStopAreaUpdate(request *StopAreaUpdateRequest) {
	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	subscription := connector.partner.Subscriptions().FindOrCreateByKind("StopMonitoring")

	for _, sr := range subscription.resourcesByObjectID {
		if sr.Reference.ObjectId.Value() == string(request.StopAreaId()) {
			sr.SubscribedUntil = sr.SubscribedUntil.Add(1 * time.Minute)
			return
		}
	}

	objId := model.NewObjectID("StopMonitoring", string(request.StopAreaId()))
	ref := model.Reference{
		ObjectId: &objId,
		Id:       string(request.StopAreaId()),
		Type:     "StopArea",
	}

	subscription.CreateAddNewResource(ref)

	siriStopMonitoringSubscriptionRequest := &siri.SIRIStopMonitoringSubscriptionRequest{
		MessageIdentifier:      connector.SIRIPartner().NewMessageIdentifier(),
		MonitoringRef:          string(request.StopAreaId()),
		RequestorRef:           connector.SIRIPartner().RequestorRef(),
		RequestTimestamp:       connector.Clock().Now(),
		SubscriberRef:          connector.SIRIPartner().RequestorRef(),
		SubscriptionIdentifier: fmt.Sprintf("Edwig:Subscription::%v:LOC", objId.HashValue()),
		InitialTerminationTime: connector.Clock().Now().Add(48 * time.Hour),
	}
	logSIRIStopMonitoringSubscriptionRequest(logStashEvent, siriStopMonitoringSubscriptionRequest)
	connector.SIRIPartner().SOAPClient().StopMonitoringSubscription(siriStopMonitoringSubscriptionRequest)
}

func (connector *SIRIStopMonitoringSubscriptionCollector) SetStopAreaUpdateSubscriber(stopAreaUpdateSubscriber StopAreaUpdateSubscriber) {
	connector.stopAreaUpdateSubscriber = stopAreaUpdateSubscriber
}

func (connector *SIRIStopMonitoringSubscriptionCollector) broadcastStopAreaUpdateEvents(events map[string]*model.StopAreaUpdateEvent) {
	if connector.stopAreaUpdateSubscriber != nil {
		for _, event := range events {
			connector.stopAreaUpdateSubscriber(event)
		}
	}
}

func (connector *SIRIStopMonitoringSubscriptionCollector) HandleNotifyStopMonitoring(delivery *siri.XMLStopMonitoringResponse) {
	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	logXMLStopMonitoringDelivery(logStashEvent, delivery)

	stopAreaUpdateEvents := make(map[string]*model.StopAreaUpdateEvent)

	connector.setStopVisitUpdateEvents(stopAreaUpdateEvents, delivery)
	connector.setStopVisitCancellationEvents(stopAreaUpdateEvents, delivery)

	logStopVisitUpdateEventsFromMap(logStashEvent, stopAreaUpdateEvents)

	connector.broadcastStopAreaUpdateEvents(stopAreaUpdateEvents)
}

func (connector *SIRIStopMonitoringSubscriptionCollector) setStopVisitUpdateEvents(events map[string]*model.StopAreaUpdateEvent, xmlResponse *siri.XMLStopMonitoringResponse) {
	xmlStopVisitEvents := xmlResponse.XMLMonitoredStopVisits()
	if len(xmlStopVisitEvents) == 0 {
		return
	}

	builder := newStopVisitUpdateEventBuilder(connector.partner)

	for _, xmlStopVisitEvent := range xmlStopVisitEvents {
		stopAreaUpdateEvent, ok := events[xmlStopVisitEvent.StopPointRef()]
		if !ok {
			stopAreaUpdateEvent = model.NewStopAreaUpdateEvent(connector.NewUUID(), model.StopAreaId(xmlStopVisitEvent.StopPointRef()))
			events[xmlStopVisitEvent.StopPointRef()] = stopAreaUpdateEvent
		}
		builder.buildStopVisitUpdateEvent(stopAreaUpdateEvent, xmlStopVisitEvent)
	}
}

func (connector *SIRIStopMonitoringSubscriptionCollector) setStopVisitCancellationEvents(events map[string]*model.StopAreaUpdateEvent, xmlResponse *siri.XMLStopMonitoringResponse) {
	xmlStopVisitCancellationEvents := xmlResponse.XMLMonitoredStopVisitCancellations()
	if len(xmlStopVisitCancellationEvents) == 0 {
		return
	}

	for _, xmlStopVisitCancellationEvent := range xmlStopVisitCancellationEvents {
		stopAreaUpdateEvent, ok := events[xmlStopVisitCancellationEvent.MonitoringRef()]
		if !ok {
			stopAreaUpdateEvent = model.NewStopAreaUpdateEvent(connector.NewUUID(), model.StopAreaId(xmlStopVisitCancellationEvent.ItemRef()))
			events[xmlStopVisitCancellationEvent.MonitoringRef()] = stopAreaUpdateEvent
		}
		stopVisitCancellationEvent := &model.StopVisitNotCollectedEvent{
			StopVisitObjectId: model.NewObjectID(connector.partner.Setting("remote_objectid_kind"), xmlStopVisitCancellationEvent.ItemRef()),
		}
		stopAreaUpdateEvent.StopVisitNotCollectedEvents = append(stopAreaUpdateEvent.StopVisitNotCollectedEvents, stopVisitCancellationEvent)
	}
}

func logSIRIStopMonitoringSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.SIRIStopMonitoringSubscriptionRequest) {
	logStashEvent["Connector"] = "StopMonitoringSubscriptionRequestCollector"
	logStashEvent["messageIdentifier"] = request.MessageIdentifier
	logStashEvent["monitoringRef"] = request.MonitoringRef
	logStashEvent["requestorRef"] = request.RequestorRef
	logStashEvent["requestTimestamp"] = request.RequestTimestamp.String()
	xml, err := request.BuildXML()
	if err != nil {
		logStashEvent["requestXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["requestXML"] = xml
}

func logXMLStopMonitoringDelivery(logStashEvent audit.LogStashEvent, delivery *siri.XMLStopMonitoringResponse) {
	logStashEvent["address"] = delivery.Address()
	logStashEvent["producerRef"] = delivery.ProducerRef()
	logStashEvent["requestMessageRef"] = delivery.RequestMessageRef()
	logStashEvent["responseMessageIdentifier"] = delivery.ResponseMessageIdentifier()
	logStashEvent["responseTimestamp"] = delivery.ResponseTimestamp().String()
	logStashEvent["responseXML"] = delivery.RawXML()
	logStashEvent["status"] = strconv.FormatBool(delivery.Status())
	if !delivery.Status() {
		logStashEvent["errorType"] = delivery.ErrorType()
		logStashEvent["errorNumber"] = strconv.Itoa(delivery.ErrorNumber())
		logStashEvent["errorText"] = delivery.ErrorText()
		logStashEvent["errorDescription"] = delivery.ErrorDescription()
	}
}

func logStopVisitUpdateEventsFromMap(logStashEvent audit.LogStashEvent, stopAreaUpdateEvents map[string]*model.StopAreaUpdateEvent) {
	var idArray []string
	var cancelledIdArray []string
	for _, stopAreaUpdateEvent := range stopAreaUpdateEvents {
		for _, stopVisitUpdateEvent := range stopAreaUpdateEvent.StopVisitUpdateEvents {
			idArray = append(idArray, stopVisitUpdateEvent.Id)
		}
		for _, stopVisitCancelledEvent := range stopAreaUpdateEvent.StopVisitNotCollectedEvents {
			cancelledIdArray = append(cancelledIdArray, stopVisitCancelledEvent.StopVisitObjectId.Value())
		}
	}
	logStashEvent["StopVisitUpdateEventIds"] = strings.Join(idArray, ", ")
	logStashEvent["StopVisitCancelledEventIds"] = strings.Join(cancelledIdArray, ", ")
}
<commit_msg>Log connector in StopMonitoringSubscriptionCollector<commit_after>package core

import (
	"fmt"
	"strconv"
	"strings"
	"time"

	"github.com/af83/edwig/audit"
	"github.com/af83/edwig/model"
	"github.com/af83/edwig/siri"
)

type StopMonitoringSubscriptionCollector interface {
	RequestStopAreaUpdate(request *StopAreaUpdateRequest)
	HandleNotifyStopMonitoring(delivery *siri.XMLStopMonitoringResponse)
}

type SIRIStopMonitoringSubscriptionCollector struct {
	model.ClockConsumer
	model.UUIDConsumer

	siriConnector

	Partner                  Partner
	stopAreaUpdateSubscriber StopAreaUpdateSubscriber
}

type SIRIStopMonitoringSubscriptionCollectorFactory struct{}

func (factory *SIRIStopMonitoringSubscriptionCollectorFactory) CreateConnector(partner *Partner) Connector {
	return NewSIRIStopMonitoringSubscriptionCollector(partner)
}

func (factory *SIRIStopMonitoringSubscriptionCollectorFactory) Validate(apiPartner *APIPartner) bool {
	ok := apiPartner.ValidatePresenceOfSetting("remote_objectid_kind")
	ok = ok && apiPartner.ValidatePresenceOfSetting("local_credential")
	return ok
}

func NewSIRIStopMonitoringSubscriptionCollector(partner *Partner) *SIRIStopMonitoringSubscriptionCollector {
	siriStopMonitoringSubscriptionCollector := &SIRIStopMonitoringSubscriptionCollector{}
	siriStopMonitoringSubscriptionCollector.partner = partner
	manager := partner.Referential().CollectManager()
	siriStopMonitoringSubscriptionCollector.stopAreaUpdateSubscriber = manager.BroadcastStopAreaUpdateEvent

	return siriStopMonitoringSubscriptionCollector
}

func (connector *SIRIStopMonitoringSubscriptionCollector) RequestStopAreaUpdate(request *StopAreaUpdateRequest) {
	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	subscription := connector.partner.Subscriptions().FindOrCreateByKind("StopMonitoring")

	for _, sr := range subscription.resourcesByObjectID {
		if sr.Reference.ObjectId.Value() == string(request.StopAreaId()) {
			sr.SubscribedUntil = sr.SubscribedUntil.Add(1 * time.Minute)
			return
		}
	}

	objId := model.NewObjectID("StopMonitoring", string(request.StopAreaId()))
	ref := model.Reference{
		ObjectId: &objId,
		Id:       string(request.StopAreaId()),
		Type:     "StopArea",
	}

	subscription.CreateAddNewResource(ref)

	siriStopMonitoringSubscriptionRequest := &siri.SIRIStopMonitoringSubscriptionRequest{
		MessageIdentifier:      connector.SIRIPartner().NewMessageIdentifier(),
		MonitoringRef:          string(request.StopAreaId()),
		RequestorRef:           connector.SIRIPartner().RequestorRef(),
		RequestTimestamp:       connector.Clock().Now(),
		SubscriberRef:          connector.SIRIPartner().RequestorRef(),
		SubscriptionIdentifier: fmt.Sprintf("Edwig:Subscription::%v:LOC", objId.HashValue()),
		InitialTerminationTime: connector.Clock().Now().Add(48 * time.Hour),
	}
	logSIRIStopMonitoringSubscriptionRequest(logStashEvent, siriStopMonitoringSubscriptionRequest)
	connector.SIRIPartner().SOAPClient().StopMonitoringSubscription(siriStopMonitoringSubscriptionRequest)
}

func (connector *SIRIStopMonitoringSubscriptionCollector) SetStopAreaUpdateSubscriber(stopAreaUpdateSubscriber StopAreaUpdateSubscriber) {
	connector.stopAreaUpdateSubscriber = stopAreaUpdateSubscriber
}

func (connector *SIRIStopMonitoringSubscriptionCollector) broadcastStopAreaUpdateEvents(events map[string]*model.StopAreaUpdateEvent) {
	if connector.stopAreaUpdateSubscriber != nil {
		for _, event := range events {
			connector.stopAreaUpdateSubscriber(event)
		}
	}
}

func (connector *SIRIStopMonitoringSubscriptionCollector) HandleNotifyStopMonitoring(delivery *siri.XMLStopMonitoringResponse) {
	logStashEvent := make(audit.LogStashEvent)
	defer audit.CurrentLogStash().WriteEvent(logStashEvent)

	logXMLStopMonitoringDelivery(logStashEvent, delivery)

	stopAreaUpdateEvents := make(map[string]*model.StopAreaUpdateEvent)

	connector.setStopVisitUpdateEvents(stopAreaUpdateEvents, delivery)
	connector.setStopVisitCancellationEvents(stopAreaUpdateEvents, delivery)

	logStopVisitUpdateEventsFromMap(logStashEvent, stopAreaUpdateEvents)

	connector.broadcastStopAreaUpdateEvents(stopAreaUpdateEvents)
}

func (connector *SIRIStopMonitoringSubscriptionCollector) setStopVisitUpdateEvents(events map[string]*model.StopAreaUpdateEvent, xmlResponse *siri.XMLStopMonitoringResponse) {
	xmlStopVisitEvents := xmlResponse.XMLMonitoredStopVisits()
	if len(xmlStopVisitEvents) == 0 {
		return
	}

	builder := newStopVisitUpdateEventBuilder(connector.partner)

	for _, xmlStopVisitEvent := range xmlStopVisitEvents {
		stopAreaUpdateEvent, ok := events[xmlStopVisitEvent.StopPointRef()]
		if !ok {
			stopAreaUpdateEvent = model.NewStopAreaUpdateEvent(connector.NewUUID(), model.StopAreaId(xmlStopVisitEvent.StopPointRef()))
			events[xmlStopVisitEvent.StopPointRef()] = stopAreaUpdateEvent
		}
		builder.buildStopVisitUpdateEvent(stopAreaUpdateEvent, xmlStopVisitEvent)
	}
}

func (connector *SIRIStopMonitoringSubscriptionCollector) setStopVisitCancellationEvents(events map[string]*model.StopAreaUpdateEvent, xmlResponse *siri.XMLStopMonitoringResponse) {
	xmlStopVisitCancellationEvents := xmlResponse.XMLMonitoredStopVisitCancellations()
	if len(xmlStopVisitCancellationEvents) == 0 {
		return
	}

	for _, xmlStopVisitCancellationEvent := range xmlStopVisitCancellationEvents {
		stopAreaUpdateEvent, ok := events[xmlStopVisitCancellationEvent.MonitoringRef()]
		if !ok {
			stopAreaUpdateEvent = model.NewStopAreaUpdateEvent(connector.NewUUID(), model.StopAreaId(xmlStopVisitCancellationEvent.ItemRef()))
			events[xmlStopVisitCancellationEvent.MonitoringRef()] = stopAreaUpdateEvent
		}
		stopVisitCancellationEvent := &model.StopVisitNotCollectedEvent{
			StopVisitObjectId: model.NewObjectID(connector.partner.Setting("remote_objectid_kind"), xmlStopVisitCancellationEvent.ItemRef()),
		}
		stopAreaUpdateEvent.StopVisitNotCollectedEvents = append(stopAreaUpdateEvent.StopVisitNotCollectedEvents, stopVisitCancellationEvent)
	}
}

func logSIRIStopMonitoringSubscriptionRequest(logStashEvent audit.LogStashEvent, request *siri.SIRIStopMonitoringSubscriptionRequest) {
	logStashEvent["Connector"] = "StopMonitoringSubscriptionRequestCollector"
	logStashEvent["messageIdentifier"] = request.MessageIdentifier
	logStashEvent["monitoringRef"] = request.MonitoringRef
	logStashEvent["requestorRef"] = request.RequestorRef
	logStashEvent["requestTimestamp"] = request.RequestTimestamp.String()
	xml, err := request.BuildXML()
	if err != nil {
		logStashEvent["requestXML"] = fmt.Sprintf("%v", err)
		return
	}
	logStashEvent["requestXML"] = xml
}

func logXMLStopMonitoringDelivery(logStashEvent audit.LogStashEvent, delivery *siri.XMLStopMonitoringResponse) {
	logStashEvent["Connector"] = "StopMonitoringSubscriptionCollector"
	logStashEvent["address"] = delivery.Address()
	logStashEvent["producerRef"] = delivery.ProducerRef()
	logStashEvent["requestMessageRef"] = delivery.RequestMessageRef()
	logStashEvent["responseMessageIdentifier"] = delivery.ResponseMessageIdentifier()
	logStashEvent["responseTimestamp"] = delivery.ResponseTimestamp().String()
	logStashEvent["responseXML"] = delivery.RawXML()
	logStashEvent["status"] = strconv.FormatBool(delivery.Status())
	if !delivery.Status() {
		logStashEvent["errorType"] = delivery.ErrorType()
		logStashEvent["errorNumber"] = strconv.Itoa(delivery.ErrorNumber())
		logStashEvent["errorText"] = delivery.ErrorText()
		logStashEvent["errorDescription"] = delivery.ErrorDescription()
	}
}

func logStopVisitUpdateEventsFromMap(logStashEvent audit.LogStashEvent, stopAreaUpdateEvents map[string]*model.StopAreaUpdateEvent) {
	var idArray []string
	var cancelledIdArray []string
	for _, stopAreaUpdateEvent := range stopAreaUpdateEvents {
		for _, stopVisitUpdateEvent := range stopAreaUpdateEvent.StopVisitUpdateEvents {
			idArray = append(idArray, stopVisitUpdateEvent.Id)
		}
		for _, stopVisitCancelledEvent := range stopAreaUpdateEvent.StopVisitNotCollectedEvents {
			cancelledIdArray = append(cancelledIdArray, stopVisitCancelledEvent.StopVisitObjectId.Value())
		}
	}
	logStashEvent["StopVisitUpdateEventIds"] = strings.Join(idArray, ", ")
	logStashEvent["StopVisitCancelledEventIds"] = strings.Join(cancelledIdArray, ", ")
}
<|endoftext|>


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

package steven

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/thinkofdeath/steven/audio"
	"github.com/thinkofdeath/steven/console"
	"github.com/thinkofdeath/steven/resource"
)

const (
	assetsVersion    = "1.8"
	assetIndexURL    = "https://s3.amazonaws.com/Minecraft.Download/indexes/%s.json"
	assetResourceURL = "http://resources.download.minecraft.net/%s"
)

var (
	assets       assetIndex
	loadedSounds = map[pluginKey]audio.SoundBuffer{}
	soundList    []audio.Sound
)

type assetIndex struct {
	Objects map[string]struct {
		Hash string `json:"hash"`
		Size int    `json:"size"`
	} `json:"objects"`
}

func PlaySound(plugin, name string) {
	key := pluginKey{plugin, name}
	sb, ok := loadedSounds[key]
	if !ok {
		f, err := resource.Open(plugin, "sounds/"+name+".ogg")
		if err != nil {
			v, ok := assets.Objects[fmt.Sprintf("%s/sounds/%s.ogg", plugin, name)]
			if !ok {
				console.Text("Missing sound %s", key)
				return
			}
			loc := fmt.Sprintf("./resources/%s", hashPath(v.Hash))
			f, err = os.Open(loc)
			if err != nil {
				console.Text("Missing sound %s", key)
				return
			}
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			panic(err)
		}
		sb = audio.NewSoundBufferData(data)
		loadedSounds[key] = sb
	}
	for _, s := range soundList {
		if s.Status() == audio.StatStopped {
			s.SetBuffer(sb)
			s.SetVolume(100.0)
			s.Play()
			return
		}
	}
	s := audio.NewSound()
	s.SetBuffer(sb)
	s.Play()
	s.SetVolume(100.0)
	soundList = append(soundList, s)
}

func init() {
	defLocation := "./resources"
	loc := fmt.Sprintf("%s/%s.index", defLocation, assetsVersion)
	_, err := os.Stat(loc)
	if os.IsNotExist(err) {
		getAssetIndex()
	} else {
		f, err := os.Open(fmt.Sprintf("./resources/%s.index", assetsVersion))
		if err != nil {
			panic(err)
		}
		defer f.Close()
		err = json.NewDecoder(f).Decode(&assets)
		if err != nil {
			panic(err)
		}
	}
	go downloadAssets()
}

func getAssetIndex() {
	defLocation := "./resources"
	resp, err := http.Get(fmt.Sprintf(assetIndexURL, assetsVersion))
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	if err := json.NewDecoder(resp.Body).Decode(&assets); err != nil {
		panic(err)
	}
	os.MkdirAll("./resources", 0777)
	f, err := os.Create(fmt.Sprintf("%s/%s.index", defLocation, assetsVersion))
	if err != nil {
		panic(err)
	}
	defer f.Close()
	json.NewEncoder(f).Encode(assets)
}

func downloadAssets() {
	defLocation := "./resources"
	for _, v := range assets.Objects {
		path := hashPath(v.Hash)
		loc := fmt.Sprintf("%s/%s", defLocation, path)
		_, err := os.Stat(loc)
		if !os.IsNotExist(err) {
			continue
		}
		func() {
			resp, err := http.Get(fmt.Sprintf(assetResourceURL, path))
			if err != nil {
				panic(err)
			}
			defer resp.Body.Close()
			os.MkdirAll(filepath.Dir(loc), 0777)
			f, err := os.Create(loc + ".tmp")
			if err != nil {
				panic(err)
			}
			defer f.Close()
			io.Copy(f, resp.Body)
			console.Text("Downloaded: %s", loc)
		}()
		os.Rename(loc+".tmp", loc)
	}
}
func hashPath(hash string) string {
	return filepath.Join(hash[:2], hash)
}
<commit_msg>audio: fix downloading sounds on windows<commit_after>// Copyright 2015 Matthew Collins
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package steven

import (
	"encoding/json"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"

	"github.com/thinkofdeath/steven/audio"
	"github.com/thinkofdeath/steven/console"
	"github.com/thinkofdeath/steven/resource"
)

const (
	assetsVersion    = "1.8"
	assetIndexURL    = "https://s3.amazonaws.com/Minecraft.Download/indexes/%s.json"
	assetResourceURL = "http://resources.download.minecraft.net/%s"
)

var (
	assets       assetIndex
	loadedSounds = map[pluginKey]audio.SoundBuffer{}
	soundList    []audio.Sound
)

type assetIndex struct {
	Objects map[string]struct {
		Hash string `json:"hash"`
		Size int    `json:"size"`
	} `json:"objects"`
}

func PlaySound(plugin, name string) {
	key := pluginKey{plugin, name}
	sb, ok := loadedSounds[key]
	if !ok {
		f, err := resource.Open(plugin, "sounds/"+name+".ogg")
		if err != nil {
			v, ok := assets.Objects[fmt.Sprintf("%s/sounds/%s.ogg", plugin, name)]
			if !ok {
				console.Text("Missing sound %s", key)
				return
			}
			loc := fmt.Sprintf("./resources/%s", hashPath(v.Hash))
			f, err = os.Open(loc)
			if err != nil {
				console.Text("Missing sound %s", key)
				return
			}
		}
		defer f.Close()
		data, err := ioutil.ReadAll(f)
		if err != nil {
			panic(err)
		}
		sb = audio.NewSoundBufferData(data)
		loadedSounds[key] = sb
	}
	for _, s := range soundList {
		if s.Status() == audio.StatStopped {
			s.SetBuffer(sb)
			s.SetVolume(100.0)
			s.Play()
			return
		}
	}
	s := audio.NewSound()
	s.SetBuffer(sb)
	s.Play()
	s.SetVolume(100.0)
	soundList = append(soundList, s)
}

func init() {
	defLocation := "./resources"
	loc := fmt.Sprintf("%s/%s.index", defLocation, assetsVersion)
	_, err := os.Stat(loc)
	if os.IsNotExist(err) {
		getAssetIndex()
	} else {
		f, err := os.Open(fmt.Sprintf("./resources/%s.index", assetsVersion))
		if err != nil {
			panic(err)
		}
		defer f.Close()
		err = json.NewDecoder(f).Decode(&assets)
		if err != nil {
			panic(err)
		}
	}
	go downloadAssets()
}

func getAssetIndex() {
	defLocation := "./resources"
	resp, err := http.Get(fmt.Sprintf(assetIndexURL, assetsVersion))
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()
	if err := json.NewDecoder(resp.Body).Decode(&assets); err != nil {
		panic(err)
	}
	os.MkdirAll("./resources", 0777)
	f, err := os.Create(fmt.Sprintf("%s/%s.index", defLocation, assetsVersion))
	if err != nil {
		panic(err)
	}
	defer f.Close()
	json.NewEncoder(f).Encode(assets)
}

func downloadAssets() {
	defLocation := "./resources"
	for _, v := range assets.Objects {
		path := hashPath(v.Hash)
		loc := fmt.Sprintf("%s/%s", defLocation, path)
		_, err := os.Stat(loc)
		if !os.IsNotExist(err) {
			continue
		}
		func() {
			resp, err := http.Get(fmt.Sprintf(assetResourceURL, path))
			if err != nil {
				panic(err)
			}
			defer resp.Body.Close()
			os.MkdirAll(filepath.Dir(loc), 0777)
			f, err := os.Create(loc + ".tmp")
			if err != nil {
				panic(err)
			}
			defer f.Close()
			n, err := io.Copy(f, resp.Body)
			if err != nil {
				panic(err)
			}
			if n != int64(v.Size) {
				panic(fmt.Sprintf("Got: %d, Wanted: %d for %s", n, v.Size, fmt.Sprintf(assetResourceURL, path)))
			}
			console.Text("Downloaded: %s", loc)
		}()
		os.Rename(loc+".tmp", loc)
	}
}
func hashPath(hash string) string {
	return hash[:2] + "/" + hash
}
<|endoftext|>


<commit_before>package captcha

import (
	"bytes"
	"encoding/binary"
	"math"
	"os"
	"rand"
	"io"
)

const sampleRate = 8000 // Hz

var (
	longestDigitSndLen int
	endingBeepSound    []byte
	reverseDigitSounds [][]byte
)

func init() {
	for _, v := range digitSounds {
		if longestDigitSndLen < len(v) {
			longestDigitSndLen = len(v)
		}
	}
	endingBeepSound = changeSpeed(beepSound, 1.4)
	// Preallocate reversed digit sounds for background noise.
	reverseDigitSounds = make([][]byte, len(digitSounds))
	for i, v := range digitSounds {
		reverseDigitSounds[i] = reversedSound(v)
	}
}

// BUG(dchest): [Not our bug] Google Chrome 10 plays unsigned 8-bit PCM WAVE
// audio on Mac with horrible distortions.  Issue:
// http://code.google.com/p/chromium/issues/detail?id=70730.
// This has been fixed, and version 12 will play them properly.

type Audio struct {
	body *bytes.Buffer
}

// NewImage returns a new audio captcha with the given digits, where each digit
// must be in range 0-9.
func NewAudio(digits []byte) *Audio {
	numsnd := make([][]byte, len(digits))
	nsdur := 0
	for i, n := range digits {
		snd := randomizedDigitSound(n)
		nsdur += len(snd)
		numsnd[i] = snd
	}
	// Random intervals between digits (including beginning).
	intervals := make([]int, len(digits)+1)
	intdur := 0
	for i := range intervals {
		dur := rnd(sampleRate, sampleRate*3) // 1 to 3 seconds
		intdur += dur
		intervals[i] = dur
	}
	// Generate background sound.
	bg := makeBackgroundSound(longestDigitSndLen*len(digits) + intdur)
	// Create buffer and write audio to it.
	a := new(Audio)
	sil := makeSilence(sampleRate / 5)
	bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound)
	a.body = bytes.NewBuffer(make([]byte, 0, bufcap))
	// Write prelude, three beeps.
	a.body.Write(beepSound)
	a.body.Write(sil)
	a.body.Write(beepSound)
	a.body.Write(sil)
	a.body.Write(beepSound)
	// Write digits.
	pos := intervals[0]
	for i, v := range numsnd {
		mixSound(bg[pos:], v)
		pos += len(v) + intervals[i+1]
	}
	a.body.Write(bg)
	// Write ending (one beep).
	a.body.Write(endingBeepSound)
	return a
}

// WriteTo writes captcha audio in WAVE format into the given io.Writer, and
// returns the number of bytes written and an error if any.
func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) {
	// Header.
	nn, err := w.Write(waveHeader)
	n = int64(nn)
	if err != nil {
		return
	}
	// Chunk length.
	err = binary.Write(w, binary.LittleEndian, uint32(a.body.Len()))
	if err != nil {
		return
	}
	nn += 4
	// Chunk data.
	n, err = a.body.WriteTo(w)
	n += int64(nn)
	// Pad byte if chunk length is odd.
	// (As header has even length, we can check if n is odd, not chunk).
	if n % 2 != 0 {
		w.Write([]byte{128})
		n++
	}
	return
}

// EncodedLen returns the length of WAV-encoded audio captcha.
func (a *Audio) EncodedLen() int {
	return len(waveHeader) + 4 + a.body.Len()
}

// mixSound mixes src into dst. Dst must have length equal to or greater than
// src length.
func mixSound(dst, src []byte) {
	for i, v := range src {
		av := int(v)
		bv := int(dst[i])
		if av < 128 && bv < 128 {
			dst[i] = byte(av * bv / 128)
		} else {
			dst[i] = byte(2*(av+bv) - av*bv/128 - 256)
		}
	}
}

func setSoundLevel(a []byte, level float64) {
	for i, v := range a {
		av := float64(v)
		switch {
		case av > 128:
			if av = (av-128)*level + 128; av < 128 {
				av = 128
			}
		case av < 128:
			if av = 128 - (128-av)*level; av > 128 {
				av = 128
			}
		default:
			continue
		}
		a[i] = byte(av)
	}
}

// changeSpeed returns new PCM bytes from the bytes with the speed and pitch
// changed to the given value that must be in range [0, x].
func changeSpeed(a []byte, speed float64) []byte {
	b := make([]byte, int(math.Floor(float64(len(a))*speed)))
	var p float64
	for _, v := range a {
		for i := int(p); i < int(p+speed); i++ {
			b[i] = v
		}
		p += speed
	}
	return b
}

func randomSpeed(a []byte) []byte {
	pitch := rndf(0.9, 1.2)
	return changeSpeed(a, pitch)
}

func makeSilence(length int) []byte {
	b := make([]byte, length)
	for i := range b {
		b[i] = 128
	}
	return b
}

func makeWhiteNoise(length int, level uint8) []byte {
	noise := randomBytes(length)
	adj := 128 - level/2
	for i, v := range noise {
		v %= level
		v += adj
		noise[i] = v
	}
	return noise
}

func reversedSound(a []byte) []byte {
	n := len(a)
	b := make([]byte, n)
	for i, v := range a {
		b[n-1-i] = v
	}
	return b
}

func makeBackgroundSound(length int) []byte {
	b := makeWhiteNoise(length, 4)
	for i := 0; i < length/(sampleRate/10); i++ {
		snd := reverseDigitSounds[rand.Intn(10)]
		snd = changeSpeed(snd, rndf(0.8, 1.4))
		place := rand.Intn(len(b) - len(snd))
		setSoundLevel(snd, rndf(0.2, 0.3))
		mixSound(b[place:], snd)
	}
	return b
}

func randomizedDigitSound(n byte) []byte {
	s := randomSpeed(digitSounds[n])
	setSoundLevel(s, rndf(0.7, 1.3))
	return s
}
<commit_msg>audio: error handling; pad byte is 0, not 128.<commit_after>package captcha

import (
	"bytes"
	"encoding/binary"
	"math"
	"os"
	"rand"
	"io"
)

const sampleRate = 8000 // Hz

var (
	longestDigitSndLen int
	endingBeepSound    []byte
	reverseDigitSounds [][]byte
)

func init() {
	for _, v := range digitSounds {
		if longestDigitSndLen < len(v) {
			longestDigitSndLen = len(v)
		}
	}
	endingBeepSound = changeSpeed(beepSound, 1.4)
	// Preallocate reversed digit sounds for background noise.
	reverseDigitSounds = make([][]byte, len(digitSounds))
	for i, v := range digitSounds {
		reverseDigitSounds[i] = reversedSound(v)
	}
}

// BUG(dchest): [Not our bug] Google Chrome 10 plays unsigned 8-bit PCM WAVE
// audio on Mac with horrible distortions.  Issue:
// http://code.google.com/p/chromium/issues/detail?id=70730.
// This has been fixed, and version 12 will play them properly.

type Audio struct {
	body *bytes.Buffer
}

// NewImage returns a new audio captcha with the given digits, where each digit
// must be in range 0-9.
func NewAudio(digits []byte) *Audio {
	numsnd := make([][]byte, len(digits))
	nsdur := 0
	for i, n := range digits {
		snd := randomizedDigitSound(n)
		nsdur += len(snd)
		numsnd[i] = snd
	}
	// Random intervals between digits (including beginning).
	intervals := make([]int, len(digits)+1)
	intdur := 0
	for i := range intervals {
		dur := rnd(sampleRate, sampleRate*3) // 1 to 3 seconds
		intdur += dur
		intervals[i] = dur
	}
	// Generate background sound.
	bg := makeBackgroundSound(longestDigitSndLen*len(digits) + intdur)
	// Create buffer and write audio to it.
	a := new(Audio)
	sil := makeSilence(sampleRate / 5)
	bufcap := 3*len(beepSound) + 2*len(sil) + len(bg) + len(endingBeepSound)
	a.body = bytes.NewBuffer(make([]byte, 0, bufcap))
	// Write prelude, three beeps.
	a.body.Write(beepSound)
	a.body.Write(sil)
	a.body.Write(beepSound)
	a.body.Write(sil)
	a.body.Write(beepSound)
	// Write digits.
	pos := intervals[0]
	for i, v := range numsnd {
		mixSound(bg[pos:], v)
		pos += len(v) + intervals[i+1]
	}
	a.body.Write(bg)
	// Write ending (one beep).
	a.body.Write(endingBeepSound)
	return a
}

// WriteTo writes captcha audio in WAVE format into the given io.Writer, and
// returns the number of bytes written and an error if any.
func (a *Audio) WriteTo(w io.Writer) (n int64, err os.Error) {
	// Header.
	nn, err := w.Write(waveHeader)
	n = int64(nn)
	if err != nil {
		return
	}
	// Chunk length.
	err = binary.Write(w, binary.LittleEndian, uint32(a.body.Len()))
	if err != nil {
		return
	}
	nn += 4
	// Chunk data.
	n, err = a.body.WriteTo(w)
	n += int64(nn)
	if err != nil {
		return
	}
	// Pad byte if chunk length is odd.
	// (As header has even length, we can check if n is odd, not chunk).
	if n % 2 != 0 {
		w.Write([]byte{0})
		n++
	}
	return
}

// EncodedLen returns the length of WAV-encoded audio captcha.
func (a *Audio) EncodedLen() int {
	return len(waveHeader) + 4 + a.body.Len()
}

// mixSound mixes src into dst. Dst must have length equal to or greater than
// src length.
func mixSound(dst, src []byte) {
	for i, v := range src {
		av := int(v)
		bv := int(dst[i])
		if av < 128 && bv < 128 {
			dst[i] = byte(av * bv / 128)
		} else {
			dst[i] = byte(2*(av+bv) - av*bv/128 - 256)
		}
	}
}

func setSoundLevel(a []byte, level float64) {
	for i, v := range a {
		av := float64(v)
		switch {
		case av > 128:
			if av = (av-128)*level + 128; av < 128 {
				av = 128
			}
		case av < 128:
			if av = 128 - (128-av)*level; av > 128 {
				av = 128
			}
		default:
			continue
		}
		a[i] = byte(av)
	}
}

// changeSpeed returns new PCM bytes from the bytes with the speed and pitch
// changed to the given value that must be in range [0, x].
func changeSpeed(a []byte, speed float64) []byte {
	b := make([]byte, int(math.Floor(float64(len(a))*speed)))
	var p float64
	for _, v := range a {
		for i := int(p); i < int(p+speed); i++ {
			b[i] = v
		}
		p += speed
	}
	return b
}

func randomSpeed(a []byte) []byte {
	pitch := rndf(0.9, 1.2)
	return changeSpeed(a, pitch)
}

func makeSilence(length int) []byte {
	b := make([]byte, length)
	for i := range b {
		b[i] = 128
	}
	return b
}

func makeWhiteNoise(length int, level uint8) []byte {
	noise := randomBytes(length)
	adj := 128 - level/2
	for i, v := range noise {
		v %= level
		v += adj
		noise[i] = v
	}
	return noise
}

func reversedSound(a []byte) []byte {
	n := len(a)
	b := make([]byte, n)
	for i, v := range a {
		b[n-1-i] = v
	}
	return b
}

func makeBackgroundSound(length int) []byte {
	b := makeWhiteNoise(length, 4)
	for i := 0; i < length/(sampleRate/10); i++ {
		snd := reverseDigitSounds[rand.Intn(10)]
		snd = changeSpeed(snd, rndf(0.8, 1.4))
		place := rand.Intn(len(b) - len(snd))
		setSoundLevel(snd, rndf(0.2, 0.3))
		mixSound(b[place:], snd)
	}
	return b
}

func randomizedDigitSound(n byte) []byte {
	s := randomSpeed(digitSounds[n])
	setSoundLevel(s, rndf(0.7, 1.3))
	return s
}
<|endoftext|>