<commit_before>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/negroni"
	api "github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/api/router"
	"github.com/danmane/abalone/go/game"
	"github.com/danmane/abalone/go/operator"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
)

var (
	staticPath = flag.String("static", "./static", "serve static files located in this directory")
	host       = flag.String("host", ":8080", "address:port for HTTP listener")
)

func main() {
	flag.Parse()
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

func run() error {

	conn, err := sql.Open("sqlite3", "sqlite.db")
	if err != nil {
		return err
	}
	ds, err := NewDatastore(conn, "sqlite3")
	if err != nil {
		return err
	}

	if err := ds.DB.AutoMigrate(
		&api.User{},
	).Error; err != nil {
		return err
	}

	r := ConfigureRouter(ds, *staticPath)

	log.Printf("listening at %s", *host)
	log.Fatal(http.ListenAndServe(*host, r))
	return nil
}

func ConfigureRouter(s *api.Services, staticpath string) *mux.Router {
	r := router.NewAPIRouter()
	MountHandlers(r, s)

	// Finally, if none of the above routes match, delegate to the single-page
	// app's client-side router. Rewrite the path in order to load the
	// single-page app's root HTML entrypoint. The app will handle the route.
	r.NotFoundHandler = StaticPathFallback(staticpath)
	return r
}

func MountHandlers(r *mux.Router, ds *api.Services) *mux.Router {
	r.Get(router.GamesRun).HandlerFunc(RunGamesHandler(ds))
	r.Get(router.Players).HandlerFunc(ListPlayersHandler(ds))
	r.Get(router.PlayersCreate).HandlerFunc(CreatePlayersHandler(ds))

	r.Get(router.Users).HandlerFunc(ListUsersHandler(ds))
	r.Get(router.UsersCreate).HandlerFunc(CreateUsersHandler(ds))
	r.Get(router.UsersDelete).HandlerFunc(DeleteUsersHandler(ds))

	r.Get(router.APIBaseRoute).Path("/{rest:.*}").HandlerFunc(http.NotFound)
	return r
}

func StaticPathFallback(path string) http.Handler {
	return negroni.New(
		negroni.NewStatic(http.Dir(path)),
		negroni.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			r.URL.Path = "/"
			http.FileServer(http.Dir(path)).ServeHTTP(w, r)
		})))
}

// RunGamesHandler runs a game between two remote player instances
func RunGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		req := struct {
			BlackPort string
			WhitePort string
		}{}
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		whiteAgent := operator.RemotePlayerInstance{
			APIPlayer: api.Player{},
			Port:      req.WhitePort,
		}
		blackAgent := operator.RemotePlayerInstance{
			APIPlayer: api.Player{},
			Port:      req.BlackPort,
		}
		result := operator.ExecuteGame(&whiteAgent, &blackAgent, operator.Config{
			Start: game.Standard,
			Limit: api.DefaultMoveLimit,
		})
		log.Println(result.Outcome)
		log.Println(result.VictoryReason)
		if err := json.NewEncoder(w).Encode(result); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
}

// CreatePlayersHandler creates a new AI player running on a remote host
func CreatePlayersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// schema := struct {
		// 	Nick    string
		// 	Version string
		// 	Address string
		// }{}
		// if err := json.NewDecoder(r.Body).Decode(&schema); err != nil {
		// 	w.WriteHeader(http.StatusBadRequest)
		// 	fmt.Fprintf(w, "error decoding request: %s", err)
		// 	return
		// }
	}
}

// ListPlayersHandler returns a list of AI players
func ListPlayersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		w.WriteHeader(http.StatusNotImplemented)
	}
}

// CreateUsersHandler creates a new AI player running on a remote host
func CreateUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var u api.User
		if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err := ds.DB.Create(&u).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err := json.NewEncoder(w).Encode(&u); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// ListUsersHandler creates a new AI player running on a remote host
func ListUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var users []api.User
		if err := ds.DB.Find(&users).Error; err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err := json.NewEncoder(w).Encode(&users); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// DeleteUsersHandler creates a new AI player running on a remote host
func DeleteUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := ds.DB.Delete(api.User{ID: id}).Error; err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
<commit_msg>feat(httpd) implement ListPlayersHandler<commit_after>package main

import (
	"database/sql"
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"strconv"

	"github.com/codegangsta/negroni"
	api "github.com/danmane/abalone/go/api"
	"github.com/danmane/abalone/go/api/router"
	"github.com/danmane/abalone/go/game"
	"github.com/danmane/abalone/go/operator"
	"github.com/gorilla/mux"
	_ "github.com/mattn/go-sqlite3"
)

var (
	staticPath = flag.String("static", "./static", "serve static files located in this directory")
	host       = flag.String("host", ":8080", "address:port for HTTP listener")
)

func main() {
	flag.Parse()
	if err := run(); err != nil {
		log.Fatal(err)
	}
}

func run() error {

	conn, err := sql.Open("sqlite3", "sqlite.db")
	if err != nil {
		return err
	}
	ds, err := NewDatastore(conn, "sqlite3")
	if err != nil {
		return err
	}

	if err := ds.DB.AutoMigrate(
		new(api.User),
		new(api.Player),
	).Error; err != nil {
		return err
	}

	r := ConfigureRouter(ds, *staticPath)

	log.Printf("listening at %s", *host)
	log.Fatal(http.ListenAndServe(*host, r))
	return nil
}

func ConfigureRouter(s *api.Services, staticpath string) *mux.Router {
	r := router.NewAPIRouter()
	MountHandlers(r, s)

	// Finally, if none of the above routes match, delegate to the single-page
	// app's client-side router. Rewrite the path in order to load the
	// single-page app's root HTML entrypoint. The app will handle the route.
	r.NotFoundHandler = StaticPathFallback(staticpath)
	return r
}

func MountHandlers(r *mux.Router, ds *api.Services) *mux.Router {
	r.Get(router.GamesRun).HandlerFunc(RunGamesHandler(ds))
	r.Get(router.Players).HandlerFunc(ListPlayersHandler(ds))
	r.Get(router.PlayersCreate).HandlerFunc(CreatePlayersHandler(ds))

	r.Get(router.Users).HandlerFunc(ListUsersHandler(ds))
	r.Get(router.UsersCreate).HandlerFunc(CreateUsersHandler(ds))
	r.Get(router.UsersDelete).HandlerFunc(DeleteUsersHandler(ds))

	r.Get(router.APIBaseRoute).Path("/{rest:.*}").HandlerFunc(http.NotFound)
	return r
}

func StaticPathFallback(path string) http.Handler {
	return negroni.New(
		negroni.NewStatic(http.Dir(path)),
		negroni.Wrap(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			r.URL.Path = "/"
			http.FileServer(http.Dir(path)).ServeHTTP(w, r)
		})))
}

// RunGamesHandler runs a game between two remote player instances
func RunGamesHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		req := struct {
			BlackPort string
			WhitePort string
		}{}
		if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
			w.WriteHeader(http.StatusBadRequest)
			return
		}
		whiteAgent := operator.RemotePlayerInstance{
			APIPlayer: api.Player{},
			Port:      req.WhitePort,
		}
		blackAgent := operator.RemotePlayerInstance{
			APIPlayer: api.Player{},
			Port:      req.BlackPort,
		}
		result := operator.ExecuteGame(&whiteAgent, &blackAgent, operator.Config{
			Start: game.Standard,
			Limit: api.DefaultMoveLimit,
		})
		log.Println(result.Outcome)
		log.Println(result.VictoryReason)
		if err := json.NewEncoder(w).Encode(result); err != nil {
			w.WriteHeader(http.StatusInternalServerError)
			return
		}
	}
}

// CreatePlayersHandler creates a new AI player running on a remote host
func CreatePlayersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// schema := struct {
		// 	Nick    string
		// 	Version string
		// 	Address string
		// }{}
		// if err := json.NewDecoder(r.Body).Decode(&schema); err != nil {
		// 	w.WriteHeader(http.StatusBadRequest)
		// 	fmt.Fprintf(w, "error decoding request: %s", err)
		// 	return
		// }
	}
}

// ListPlayersHandler returns a list of AI players
func ListPlayersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var players []api.Player
		if err := ds.DB.Find(&players).Error; err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err := json.NewEncoder(w).Encode(&players); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// CreateUsersHandler creates a new AI player running on a remote host
func CreateUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var u api.User
		if err := json.NewDecoder(r.Body).Decode(&u); err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err := ds.DB.Create(&u).Error; err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}
		if err := json.NewEncoder(w).Encode(&u); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// ListUsersHandler creates a new AI player running on a remote host
func ListUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		var users []api.User
		if err := ds.DB.Find(&users).Error; err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
		if err := json.NewEncoder(w).Encode(&users); err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}

// DeleteUsersHandler creates a new AI player running on a remote host
func DeleteUsersHandler(ds *api.Services) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		id, err := strconv.ParseInt(mux.Vars(r)["id"], 10, 64)
		if err != nil {
			http.Error(w, err.Error(), http.StatusBadRequest)
			return
		}

		if err := ds.DB.Delete(api.User{ID: id}).Error; err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	}
}
<|endoftext|>


<commit_before>package aoc17

import (
	"aoc17/problems/p01"
	"aoc17/problems/p02"
	"aoc17/problems/p03"
	"aoc17/problems/p04"
	"aoc17/problems/p05"
	"aoc17/problems/p06"
	"aoc17/problems/p07"
	"aoc17/problems/p08"
	"aoc17/problems/p09"
	"aoc17/problems/p10"
	"aoc17/problems/p11"
	"aoc17/problems/p12"
	"aoc17/problems/p13"
	"aoc17/problems/p14"
	"aoc17/problems/p15"
	"aoc17/problems/p16"
	"aoc17/problems/p17"
	"aoc17/problems/p18"
	"aoc17/problems/p19"
	"aoc17/problems/p20"
	"runner"
)

// Run all the AOC 2017 puzzles
func Run(dataDir string) {
	// Note: Add new puzzles here.
	puzzles := []runner.Puzzle{
		{"AOC 2017.01", "aoc/2017/day1.txt", p01.Solve, "995", "1130"},
		{"AOC 2017.02", "aoc/2017/day2.txt", p02.Solve, "48357", "351"},
		{"AOC 2017.02.hs", "aoc/2017/day2.txt", p02.SolveHs, "48357", "351"},
		{"AOC 2017.03", "aoc/2017/day3.txt", p03.Solve, "371", "369601"},
		{"AOC 2017.03.big", "aoc/2017/day3.txt", p03.SolveBig, "371", "369601"},
		{"AOC 2017.04", "aoc/2017/day4.txt", p04.Solve, "451", "223"},
		{"AOC 2017.05", "aoc/2017/day5.txt", p05.Solve, "387096", "28040648"},
		{"AOC 2017.06", "aoc/2017/day6.txt", p06.Solve, "6681", "2392"},
		{"AOC 2017.07", "aoc/2017/day7.txt", p07.Solve, "dgoocsw", "1275"},
		{"AOC 2017.08", "aoc/2017/day8.txt", p08.Solve, "6343", "7184"},
		{"AOC 2017.09", "aoc/2017/day9.txt", p09.Solve, "21037", "9495"},
		{"AOC 2017.10", "aoc/2017/day10.txt", p10.Solve, "7888", "decdf7d377879877173b7f2fb131cf1b"},
		{"AOC 2017.11", "aoc/2017/day11.txt", p11.Solve, "722", "1551"},
		{"AOC 2017.12", "aoc/2017/day12.txt", p12.Solve, "175", "213"},
		{"AOC 2017.13", "aoc/2017/day13.txt", p13.Solve, "3184", "3878062"},
		{"AOC 2017.14", "aoc/2017/day14.txt", p14.Solve, "8140", "1182"},
		{"AOC 2017.15", "aoc/2017/day15.txt", p15.Solve, "600", "313"},
		{"AOC 2017.16", "aoc/2017/day16.txt", p16.Solve, "nlciboghjmfdapek", "nlciboghmkedpfja"},
		{"AOC 2017.17", "aoc/2017/day17.txt", p17.Solve, "1506", "39479736"},
		{"AOC 2017.18", "aoc/2017/day18.txt", p18.Solve, "7071", "8001"},
		{"AOC 2017.19", "aoc/2017/day19.txt", p19.Solve, "RYLONKEWB", "16016"},
		{"AOC 2017.20", "aoc/2017/day20.txt", p20.Solve, "300", "502"},
		//{"AOC 2017.21", "aoc/2017/day21.txt", p21.Solve, "", ""},
		//{"AOC 2017.22", "aoc/2017/day22.txt", p22.Solve, "", ""},
		//{"AOC 2017.23", "aoc/2017/day23.txt", p23.Solve, "", ""},
		//{"AOC 2017.24", "aoc/2017/day24.txt", p24.Solve, "", ""},
		//{"AOC 2017.25", "aoc/2017/day25.txt", p25.Solve, "", ""},
	}
	runner.Run(dataDir, puzzles)
}
<commit_msg>Add all current problems to 2017 runner (including 22).<commit_after>package aoc17

import (
	"aoc17/problems/p01"
	"aoc17/problems/p02"
	"aoc17/problems/p03"
	"aoc17/problems/p04"
	"aoc17/problems/p05"
	"aoc17/problems/p06"
	"aoc17/problems/p07"
	"aoc17/problems/p08"
	"aoc17/problems/p09"
	"aoc17/problems/p10"
	"aoc17/problems/p11"
	"aoc17/problems/p12"
	"aoc17/problems/p13"
	"aoc17/problems/p14"
	"aoc17/problems/p15"
	"aoc17/problems/p16"
	"aoc17/problems/p17"
	"aoc17/problems/p18"
	"aoc17/problems/p19"
	"aoc17/problems/p20"
	"aoc17/problems/p21"
	"aoc17/problems/p22"
	"runner"
)

// Run all the AOC 2017 puzzles
func Run(dataDir string) {
	// Note: Add new puzzles here.
	puzzles := []runner.Puzzle{
		{"AOC 2017.01", "aoc/2017/day1.txt", p01.Solve, "995", "1130"},
		{"AOC 2017.02", "aoc/2017/day2.txt", p02.Solve, "48357", "351"},
		{"AOC 2017.02.hs", "aoc/2017/day2.txt", p02.SolveHs, "48357", "351"},
		{"AOC 2017.03", "aoc/2017/day3.txt", p03.Solve, "371", "369601"},
		{"AOC 2017.03.big", "aoc/2017/day3.txt", p03.SolveBig, "371", "369601"},
		{"AOC 2017.04", "aoc/2017/day4.txt", p04.Solve, "451", "223"},
		{"AOC 2017.05", "aoc/2017/day5.txt", p05.Solve, "387096", "28040648"},
		{"AOC 2017.06", "aoc/2017/day6.txt", p06.Solve, "6681", "2392"},
		{"AOC 2017.07", "aoc/2017/day7.txt", p07.Solve, "dgoocsw", "1275"},
		{"AOC 2017.08", "aoc/2017/day8.txt", p08.Solve, "6343", "7184"},
		{"AOC 2017.09", "aoc/2017/day9.txt", p09.Solve, "21037", "9495"},
		{"AOC 2017.10", "aoc/2017/day10.txt", p10.Solve, "7888", "decdf7d377879877173b7f2fb131cf1b"},
		{"AOC 2017.11", "aoc/2017/day11.txt", p11.Solve, "722", "1551"},
		{"AOC 2017.12", "aoc/2017/day12.txt", p12.Solve, "175", "213"},
		{"AOC 2017.13", "aoc/2017/day13.txt", p13.Solve, "3184", "3878062"},
		{"AOC 2017.14", "aoc/2017/day14.txt", p14.Solve, "8140", "1182"},
		{"AOC 2017.15", "aoc/2017/day15.txt", p15.Solve, "600", "313"},
		{"AOC 2017.16", "aoc/2017/day16.txt", p16.Solve, "nlciboghjmfdapek", "nlciboghmkedpfja"},
		{"AOC 2017.17", "aoc/2017/day17.txt", p17.Solve, "1506", "39479736"},
		{"AOC 2017.18", "aoc/2017/day18.txt", p18.Solve, "7071", "8001"},
		{"AOC 2017.19", "aoc/2017/day19.txt", p19.Solve, "RYLONKEWB", "16016"},
		{"AOC 2017.20", "aoc/2017/day20.txt", p20.Solve, "300", "502"},
		{"AOC 2017.21", "aoc/2017/day21.txt", p21.Solve, "152", "1956174"},
		{"AOC 2017.22", "aoc/2017/day22.txt", p22.Solve, "5575", "2511991"},
		//{"AOC 2017.23", "aoc/2017/day23.txt", p23.Solve, "3969", ""},
		//{"AOC 2017.24", "aoc/2017/day24.txt", p24.Solve, "", ""},
		//{"AOC 2017.25", "aoc/2017/day25.txt", p25.Solve, "", ""},
	}
	runner.Run(dataDir, puzzles)
}
<|endoftext|>


<commit_before>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package barnacle

import (
	"fmt"
	"time"

	mproto "github.com/youtube/vitess/go/mysql/proto"
	"github.com/youtube/vitess/go/rpcplus"
	"github.com/youtube/vitess/go/vt/topo"
)

type ShardConn struct {
	address    string
	keyspace   string
	shard      string
	tabletType topo.TabletType
	retryCount int
	balancer   *Balancer
	conn       *TabletConn
}

func NewShardConn(bctopo *bcTopo, keyspace, shard string, tabletType topo.TabletType, retryDelay time.Duration, retryCount int) *ShardConn {
	return &ShardConn{
		keyspace:   keyspace,
		shard:      shard,
		tabletType: tabletType,
		retryCount: retryCount,
		balancer:   bctopo.Balancer(keyspace, shard, tabletType, retryDelay),
	}
}

func (sdc *ShardConn) connect() error {
	var lastError error
	for i := 0; i < sdc.retryCount; i++ {
		addr, err := sdc.balancer.Get()
		if err != nil {
			return err
		}
		conn, err := DialTablet(sdc.address, sdc.keyspace, sdc.shard, "", "", false)
		if err != nil {
			lastError = err
			sdc.balancer.MarkDown(addr)
			continue
		}
		sdc.address = addr
		sdc.conn = conn
		return nil
	}
	return fmt.Errorf("could not obtain connection to %s.%s.%s, last error: %v", sdc.keyspace, sdc.shard, sdc.tabletType, lastError)
}

func (sdc *ShardConn) Close() error {
	if sdc.conn == nil {
		return nil
	}
	err := sdc.conn.Close()
	sdc.address = ""
	sdc.conn = nil
	return err
}

func (sdc *ShardConn) mustReturn(err error) bool {
	if err == nil {
		return true
	}
	if _, ok := err.(rpcplus.ServerError); ok {
		return true
	}
	inTransaction := sdc.inTransaction()
	sdc.balancer.MarkDown(sdc.address)
	sdc.Close()
	return inTransaction
}

func (sdc *ShardConn) ExecDirect(query string, bindVars map[string]interface{}) (qr *mproto.QueryResult, err error) {
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return nil, err
			}
		}
		qr, err = sdc.conn.ExecDirect(query, bindVars)
		if sdc.mustReturn(err) {
			return qr, err
		}
	}
	return qr, err
}

func (sdc *ShardConn) ExecStream(query string, bindVars map[string]interface{}) (sr *StreamResult, err error) {
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return nil, err
			}
		}
		sr, err = sdc.conn.ExecStream(query, bindVars)
		if sdc.mustReturn(err) {
			return sr, err
		}
	}
	return sr, err
}

func (sdc *ShardConn) Begin() (err error) {
	if sdc.inTransaction() {
		return fmt.Errorf("cannot begin: already in transaction")
	}
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return err
			}
		}
		err = sdc.conn.Begin()
		if sdc.mustReturn(err) {
			return err
		}
	}
	return err
}

func (sdc *ShardConn) Commit() (err error) {
	if !sdc.inTransaction() {
		return fmt.Errorf("cannot commit: not in transaction")
	}
	return sdc.conn.Commit()
}

func (sdc *ShardConn) Rollback() (err error) {
	if !sdc.inTransaction() {
		return fmt.Errorf("cannot rollback: not in transaction")
	}
	return sdc.conn.Rollback()
}

func (sdc *ShardConn) inTransaction() bool {
	return sdc.conn != nil && sdc.conn.TransactionId != 0
}
<commit_msg>Load balanced connection for a shard.<commit_after>// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package barnacle

import (
	"fmt"
	"time"

	mproto "github.com/youtube/vitess/go/mysql/proto"
	"github.com/youtube/vitess/go/rpcplus"
	"github.com/youtube/vitess/go/vt/topo"
)

type ShardConn struct {
	address    string
	keyspace   string
	shard      string
	tabletType topo.TabletType
	retryCount int
	balancer   *Balancer
	conn       *TabletConn
}

func NewShardConn(bctopo *bcTopo, keyspace, shard string, tabletType topo.TabletType, retryDelay time.Duration, retryCount int) *ShardConn {
	return &ShardConn{
		keyspace:   keyspace,
		shard:      shard,
		tabletType: tabletType,
		retryCount: retryCount,
		balancer:   bctopo.Balancer(keyspace, shard, tabletType, retryDelay),
	}
}

func (sdc *ShardConn) connect() error {
	var lastError error
	for i := 0; i < sdc.retryCount; i++ {
		addr, err := sdc.balancer.Get()
		if err != nil {
			return err
		}
		conn, err := DialTablet(addr, sdc.keyspace, sdc.shard, "", "", false)
		if err != nil {
			lastError = err
			sdc.balancer.MarkDown(addr)
			continue
		}
		sdc.address = addr
		sdc.conn = conn
		return nil
	}
	return fmt.Errorf("could not obtain connection to %s.%s.%s, last error: %v", sdc.keyspace, sdc.shard, sdc.tabletType, lastError)
}

func (sdc *ShardConn) Close() error {
	if sdc.conn == nil {
		return nil
	}
	err := sdc.conn.Close()
	sdc.address = ""
	sdc.conn = nil
	return err
}

func (sdc *ShardConn) mustReturn(err error) bool {
	if err == nil {
		return true
	}
	if _, ok := err.(rpcplus.ServerError); ok {
		return true
	}
	inTransaction := sdc.inTransaction()
	sdc.balancer.MarkDown(sdc.address)
	sdc.Close()
	return inTransaction
}

func (sdc *ShardConn) ExecDirect(query string, bindVars map[string]interface{}) (qr *mproto.QueryResult, err error) {
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return nil, err
			}
		}
		qr, err = sdc.conn.ExecDirect(query, bindVars)
		if sdc.mustReturn(err) {
			return qr, err
		}
	}
	return qr, err
}

func (sdc *ShardConn) ExecStream(query string, bindVars map[string]interface{}) (sr *StreamResult, err error) {
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return nil, err
			}
		}
		sr, err = sdc.conn.ExecStream(query, bindVars)
		if sdc.mustReturn(err) {
			return sr, err
		}
	}
	return sr, err
}

func (sdc *ShardConn) Begin() (err error) {
	if sdc.inTransaction() {
		return fmt.Errorf("cannot begin: already in transaction")
	}
	for i := 0; i < 2; i++ {
		if sdc.conn == nil {
			if err = sdc.connect(); err != nil {
				return err
			}
		}
		err = sdc.conn.Begin()
		if sdc.mustReturn(err) {
			return err
		}
	}
	return err
}

func (sdc *ShardConn) Commit() (err error) {
	if !sdc.inTransaction() {
		return fmt.Errorf("cannot commit: not in transaction")
	}
	return sdc.conn.Commit()
}

func (sdc *ShardConn) Rollback() (err error) {
	if !sdc.inTransaction() {
		return fmt.Errorf("cannot rollback: not in transaction")
	}
	return sdc.conn.Rollback()
}

func (sdc *ShardConn) inTransaction() bool {
	return sdc.conn != nil && sdc.conn.TransactionId != 0
}
<|endoftext|>


<commit_before>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"tcpcall/proto"
	"time"
)

type RRegistry map[proto.SeqNum]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Locker
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

// Connect to server side.
func Dial(dst string, conf ClientConf) (c *Client, err error) {
	c = &Client{
		peer:       dst,
		config:     conf,
		registry:   RRegistry{},
		registryMu: &sync.Mutex{},
		closeChan:  make(chan bool, 50),
	}
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) (rep []byte, err error) {
	return c.ReqChunks([][]byte{payload}, timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) (rep []byte, err error) {
	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		return nil, OverloadError
	}
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     make(chan RRReply, 1),
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		c.popRegistry(req.SeqNum)
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	// wait for the response
	select {
	case reply := <-entry.Chan:
		if reply.Error == nil {
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		return nil, RemoteCrashedError
	case <-time.After(entry.Deadline.Sub(time.Now())):
		c.popRegistry(req.SeqNum)
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		return err
	}
	c.log("cast sent")
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-time.After(time.Second / 5):
		}
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		p := payload.(*proto.PacketReply)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{p.Reply, nil}
		}
	case proto.ERROR:
		p := payload.(*proto.PacketError)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum proto.SeqNum) *RREntry {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	res := c.registry[seqnum]
	if res != nil {
		delete(c.registry, seqnum)
	}
	return res
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<commit_msg>golang: optimize access to requests registry<commit_after>/*
Client connection.

Allow to make simultaneous requests through the one TCP connection.
Reconnects to the server on network failures.

Author: Aleksey Morarash <aleksey.morarash@gmail.com>
Since: 4 Sep 2016
Copyright: 2016, Aleksey Morarash <aleksey.morarash@gmail.com>
*/

package tcpcall

import (
	"bytes"
	"fmt"
	"log"
	"net"
	"sync"
	"tcpcall/proto"
	"time"
)

type RRegistry map[proto.SeqNum]*RREntry

type RREntry struct {
	Deadline time.Time
	Chan     chan RRReply
}

type RRReply struct {
	Reply [][]byte
	Error [][]byte
}

// Connection state.
type Client struct {
	// address of the remote server to connect to
	peer string
	// client configuration
	config ClientConf
	// list of issued pending requests
	registry   RRegistry
	registryMu sync.Locker
	// message oriented network socket
	socket *MsgConn
	// channel for disconnection events
	closeChan chan bool
	// set to truth on client termination
	closed bool
}

// Connection configuration.
type ClientConf struct {
	// Maximum parallel requests for the connection.
	Concurrency int
	// Sleep duration before reconnect after connection failure.
	ReconnectPeriod time.Duration
	// Max reply packet size, in bytes. 0 means no limit.
	MaxReplySize int
	// Minimum flush period for socket writer
	MinFlushPeriod time.Duration
	// Socket write buffer size
	WriteBufferSize int
	// Channel to send state events (connected/disconnected).
	StateListener chan StateEvent
	// Channel to send 'suspend' events.
	SuspendListener chan SuspendEvent
	// Channel to send 'resume' events.
	ResumeListener chan ResumeEvent
	// Channel to send Uplink Cast data.
	UplinkCastListener chan UplinkCastEvent
	// If true, Dial() function will attempt to connect to the
	// server before returning. Default is true.
	SyncConnect bool
	// Enable default logging or not.
	Trace bool
}

// Connection state event.
type StateEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// If true - client just have been connected to the server.
	// If false - disconnected.
	Online bool
}

// Sent when 'suspend' signal from server received.
type SuspendEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	// Requested suspend duration
	Duration time.Duration
}

// Sent when 'resume' signal from server received.
type ResumeEvent struct {
	// Pointer to the client connection state.
	Sender *Client
}

// Sent when uplink cast data received from server.
type UplinkCastEvent struct {
	// Pointer to the client connection state.
	Sender *Client
	Data   []byte
}

// Connect to server side.
func Dial(dst string, conf ClientConf) (c *Client, err error) {
	c = &Client{
		peer:       dst,
		config:     conf,
		registry:   RRegistry{},
		registryMu: &sync.Mutex{},
		closeChan:  make(chan bool, 50),
	}
	if conf.SyncConnect {
		err = c.connect()
	}
	go c.connectLoop()
	return c, err
}

// Create default client configuration
func NewClientConf() ClientConf {
	return ClientConf{
		Concurrency:     defConcurrency,
		ReconnectPeriod: time.Millisecond * 100,
		MinFlushPeriod:  defMinFlush,
		WriteBufferSize: defWBufSize,
		SyncConnect:     true,
		Trace:           traceClient,
	}
}

// Make synchronous request to the server.
func (c *Client) Req(payload []byte, timeout time.Duration) (rep []byte, err error) {
	return c.ReqChunks([][]byte{payload}, timeout)
}

// Make synchronous request to the server.
func (c *Client) ReqChunks(payload [][]byte, timeout time.Duration) (rep []byte, err error) {
	entry := &RREntry{
		Deadline: time.Now().Add(timeout),
		Chan:     make(chan RRReply, 1),
	}
	req := proto.NewRequest(payload, entry.Deadline)
	encoded := req.Encode()
	// queue
	c.registryMu.Lock()
	if c.config.Concurrency <= len(c.registry) {
		c.registryMu.Unlock()
		return nil, OverloadError
	}
	c.registry[req.SeqNum] = entry
	c.registryMu.Unlock()
	// send through the network
	if err := c.socket.Send(encoded); err != nil {
		c.popRegistry(req.SeqNum)
		if err == MsgConnNotConnectedError {
			return nil, NotConnectedError
		}
		return nil, DisconnectedError
	}
	c.log("req sent")
	// wait for the response
	select {
	case reply := <-entry.Chan:
		if reply.Error == nil {
			return bytes.Join(reply.Reply, []byte{}), nil
		}
		return nil, RemoteCrashedError
	case <-time.After(entry.Deadline.Sub(time.Now())):
		c.popRegistry(req.SeqNum)
		return nil, TimeoutError
	}
}

// Make asynchronous request to the server.
func (c *Client) Cast(data []byte) error {
	return c.CastChunks([][]byte{data})
}

// Make asynchronous request to the server.
func (c *Client) CastChunks(data [][]byte) error {
	encoded := proto.NewCast(data).Encode()
	if err := c.socket.Send(encoded); err != nil {
		return err
	}
	c.log("cast sent")
	return nil
}

// GetQueuedRequests function return total count of requests being
// processed right now.
func (c *Client) GetQueuedRequests() int {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	return len(c.registry)
}

// Connect (or reconnect) to the server.
func (c *Client) connect() error {
	c.disconnect()
	conn, err := net.Dial("tcp", c.peer)
	if err == nil {
		c.log("connected")
		msgConn, err := NewMsgConn(conn, c.config.MinFlushPeriod,
			c.config.WriteBufferSize,
			c.handlePacket, c.notifyClose)
		if err != nil {
			return err
		}
		msgConn.MaxPacketLen = c.config.MaxReplySize
		c.socket = msgConn
		c.notifyPool(true)
	} else {
		c.log("failed to connect: %s", err)
	}
	return err
}

// Terminate the client.
func (c *Client) Close() {
	c.log("closing...")
	c.closed = true
	c.disconnect()
	c.log("closed")
}

// Close connection to server.
func (c *Client) disconnect() {
	if c.socket == nil || c.socket.Closed() {
		return
	}
	c.socket.Close()
	c.notifyClose()
	// discard all pending requests
	c.registryMu.Lock()
	for _, entry := range c.registry {
		select {
		case entry.Chan <- RRReply{nil, [][]byte{[]byte("disconnected")}}:
		default:
		}
	}
	c.registry = RRegistry{}
	c.registryMu.Unlock()
	c.log("disconnected")
}

// Goroutine.
// Reconnects on network errors.
func (c *Client) connectLoop() {
	c.log("daemon started")
	defer c.log("daemon terminated")
	for !c.closed {
		if c.socket == nil || c.socket.Closed() {
			if err := c.connect(); err != nil {
				time.Sleep(c.config.ReconnectPeriod)
				continue
			}
		}
		<-c.closeChan
	}
}

// Send 'connection closed' notification to the client daemon.
func (c *Client) notifyClose() {
	c.notifyPool(false)
	c.closeChan <- true
}

// Send connection state change notification to Client owner
func (c *Client) notifyPool(connected bool) {
	if c.config.StateListener != nil && !c.closed {
		select {
		case c.config.StateListener <- StateEvent{c, connected}:
		case <-time.After(time.Second / 5):
		}
	}
}

// Callback for message-oriented socket.
// Handle message received from the remote peer.
func (c *Client) handlePacket(packet []byte) {
	ptype, payload, err := proto.Decode(packet)
	c.log("decoded packet_type=%d; data=%v; err=%s", ptype, payload, err)
	if err != nil {
		// close connection on bad packet receive
		c.log("decode failed: %s", err)
		c.disconnect()
		return
	}
	switch ptype {
	case proto.REPLY:
		p := payload.(*proto.PacketReply)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{p.Reply, nil}
		}
	case proto.ERROR:
		p := payload.(*proto.PacketError)
		if entry := c.popRegistry(p.SeqNum); entry != nil {
			entry.Chan <- RRReply{nil, p.Reason}
		}
	case proto.FLOW_CONTROL_SUSPEND:
		if c.config.SuspendListener != nil {
			p := payload.(*proto.PacketFlowControlSuspend)
			c.config.SuspendListener <- SuspendEvent{c, p.Duration}
		}
	case proto.FLOW_CONTROL_RESUME:
		if c.config.ResumeListener != nil {
			c.config.ResumeListener <- ResumeEvent{c}
		}
	case proto.UPLINK_CAST:
		if c.config.UplinkCastListener != nil {
			p := payload.(*proto.PacketUplinkCast)
			flat := bytes.Join(p.Data, []byte{})
			c.config.UplinkCastListener <- UplinkCastEvent{c, flat}
		}
	}
}

// Lookup request in the registry and remove it.
func (c *Client) popRegistry(seqnum proto.SeqNum) *RREntry {
	c.registryMu.Lock()
	defer c.registryMu.Unlock()
	res := c.registry[seqnum]
	if res != nil {
		delete(c.registry, seqnum)
	}
	return res
}

// Print message to the stdout if verbose mode is enabled.
func (c *Client) log(format string, args ...interface{}) {
	if c.config.Trace {
		prefix := fmt.Sprintf("tcpcall conn %s> ", c.peer)
		log.Printf(prefix+format, args...)
	}
}
<|endoftext|>


<commit_before>
package sre2

import (
  "fmt"
  "os"
  "unicode"
  "utf8"
)

/**
 * Regexp definition. Simple, just a list of states.
 */
type sregexp struct {
  prog []*instr         // list of states
  alts int              // number of marked alts [()'s] in this regexp
}

/**
 * Instruction type definitions, for `instr.mode`.
 */
const (
  kSplit = iota         // proceed down out & out1
  kAltBegin             // begin of alt section, i.e. '('
  kAltEnd               // end of alt section, i.e. ')'
  kRuneClass            // if match rune, proceed down out
  kMatch                // success state!
)

/**
 * Single instruction in regexp.
 */
type instr struct {
  idx int               // index of this instr
  mode byte             // mode (as above)
  out *instr            // next instr to process
  out1 *instr           // alt next instr (for kSplit)
  rune runeclass        // rune class
  alt int               // identifier of alt branch (for kAlt{Begin,End})
  alt_id *string        // string identifier of alt branch
}

/**
 * String-representation of an individual instruction.
 */
func (i *instr) str() string {
  str := fmt.Sprintf("{%d", i.idx)
  out := ""
  if i.out != nil {
    out += fmt.Sprintf(" out=%d", i.out.idx)
  }
  switch i.mode {
  case kSplit:
    str += " kSplit"
    if i.out1 != nil {
      out += fmt.Sprintf(" out1=%d", i.out1.idx)
    }
  case kAltBegin, kAltEnd:
    if i.mode == kAltBegin {
      str += " kAltBegin"
    } else {
      str += " kAltEnd"
    }
    str += fmt.Sprintf(" alt=%d", i.alt)
    if i.alt_id != nil {
      str += fmt.Sprintf(" alt_id=%s", *i.alt_id)
    }
  case kRuneClass:
    str += fmt.Sprint(" kRuneClass ", i.rune)
  case kMatch:
    str += " kMatch"
  }
  return str + out + "}"
}

/**
 * DebugOut writes the given regexp to Stderr, for debugging.
 */
func (r *sregexp) DebugOut() {
    for i := 0; i < len(r.prog); i++ {
      fmt.Fprintln(os.Stderr, i, r.prog[i].str())
    }
}

/*
 * Generic matcher for consuming instr instances (i.e. kRune/kCall). Does not
 * match anything else.
 */
func (s *instr) match(rune int) bool {
  return s.mode == kRuneClass && s.rune.MatchRune(rune)
}

/** transient parser state */
type parser struct {
  re *sregexp
  src string
  ch int
  pos int
}

/**
 * Generate a new pre-indexed instr.
 */
func (p *parser) instr() *instr {
  pos := len(p.re.prog)
  if pos == cap(p.re.prog) {
    local := p.re.prog
    p.re.prog = make([]*instr, pos, pos * 2)
    copy(p.re.prog, local)
  }
  p.re.prog = p.re.prog[0:pos+1]
  i := &instr{pos, kSplit, nil, nil, nil, -1, nil}
  p.re.prog[pos] = i
  return i
}

/**
 * Store/return the next character in parser. -1 indicates EOF.
 */
func (p *parser) nextc() int {
  if p.pos >= len(p.src) {
    p.ch = -1
  } else {
    c, w := utf8.DecodeRuneInString(p.src[p.pos:])
    p.ch = c
    p.pos += w
  }
  return p.ch
}

/**
 * Return the literal string from->to some expected characters. Assumes that the
 * cursor is resting on the from character. Will return the parser at the first
 * char past the result.
 */
func (p *parser) literal(start int, end int) (result string, err bool) {
  if p.ch != start {
    return "", true
  }

  result = ""
  for p.nextc() != end {
    if p.ch == -1 {
      return result, true
    }
    result += fmt.Sprintf("%c", p.ch)
  }
  return result, false
}

/**
 * Connect from -> to.
 */
func (p *parser) out(from *instr, to *instr) {
  if from.out == nil {
    from.out = to
  } else if from.mode == kSplit && from.out1 == nil {
    from.out1 = to
  } else {
    panic("can't out")
  }
}

/**
 * Consume some bracketed expression.
 */
func (p *parser) alt() (start *instr, end *instr) {
  use_alts := true
  var alt_id *string
  altpos := p.re.alts
  p.re.alts += 1

  if p.ch != '(' {
    panic("alt must start with '('")
  }

  end = p.instr() // shared end state for alt
  end.mode = kAltEnd
  end.alt = altpos

  p.nextc()
  if p.ch == '?' {
    // TODO: it might be appropriate to move this whole logic outside of alt().
    p.nextc()
    if p.ch == 'P' {
      p.nextc()
      s, err := p.literal('<', '>')
      if err {
        panic("couldn't consume name in < >")
      }
      alt_id = &s
      p.nextc() // move past '<'
    } else {
      // anything but 'P' means flags (unmatched).
      use_alts = false
      outer: for {
        switch p.ch {
        case ':':
          p.nextc() // move past ':'
          break outer // no more flags, process re
        case ')':
          panic("can't yet apply flags to outer")
          break outer // no more flags, ignore re, apply flags to outer
        default:
          panic(fmt.Sprint("flag unsupported:", p.ch))
        }
        p.nextc()
      }
    }
  }

  b_start, b_end := p.regexp()
  start = b_start
  p.out(b_end, end)

  for p.ch == '|' {
    start = p.instr()
    p.out(start, b_start)

    p.nextc()
    b_start, b_end = p.regexp()
    p.out(start, b_start)
    p.out(b_end, end)
    b_start = start
  }

  if p.ch != ')' {
    panic("alt must end with ')'")
  }

  alt_begin := p.instr()
  alt_begin.mode = kAltBegin
  alt_begin.alt = altpos
  p.out(alt_begin, start)

  if !use_alts {
    // clear alts, this is an unmatched group
    alt_begin.mode = kSplit
    end.mode = kSplit
  } else if alt_id != nil {
    // set alt string id
    alt_begin.alt_id = alt_id
    end.alt_id = alt_id
  }

  return alt_begin, end
}

/**
 * Consume a character class, and return a single instr representing this class.
 */
func (p *parser) charclass() runeclass {
  if p.ch != '[' {
    panic("expect charclass to start with [")
  }
  p.nextc() // walk over '['

  class := NewComplexRuneClass()
  negate := false
  if p.ch == '^' {
    negate = !negate
    p.nextc()
  }

  outer: for {
    switch p.ch {
    case '[':
      if p.nextc() != ':' {
        panic("expected ascii class [:")
      }
      _, err := p.literal(':', ':')
      if err {
        panic("could not consume ascii class")
      }
      if p.nextc() != ']' {
        panic("unclosed ascii class")
      }
    case ']':
      // NOTE: caller expects us not to walk over last bracket.
      break outer
    case -1:
      panic("unclosed character class")
    }

    rune := p.ch
    r := make([]unicode.Range, 1)
    if p.nextc() == '-' {
      rune_end := p.nextc()
      if rune >= rune_end {
        panic(fmt.Sprintf("unexpected range: %c >= %c", rune, rune_end))
      }
      r[0] = unicode.Range{rune, rune_end, 1}
      p.nextc() // walk past end of range
    } else {
      r[0] = unicode.Range{rune, rune, 1}
    }
    if negate {
      class.Exclude(r)
    } else {
      class.Include(r)
    }
  }

  return class
}

/**
 * Consume a single term (note that term may include a bracketed expression).
 */
func (p *parser) term() (start *instr, end *instr) {
  start = p.instr()
  end = start

  switch p.ch {
  case -1:
    panic("EOF in term")
  case '*', '+', '{', '?':
    panic("unexpected expansion char")
  case ')', '}', ']':
    panic("unexpected close element")
  case '(':
    start, end = p.alt()
  case '[':
    start.mode = kRuneClass
    start.rune = p.charclass()
  case '$':
    panic("not yet supported: end of string")
  case '^':
    panic("not yet supported: start of string")
  case '.':
    start.mode = kRuneClass
    start.rune = NewAnyRuneClass()
  default:
    ch := p.ch
    if ch == '\\' {
      switch p.nextc() {
      case 'n':
        ch = '\n'
      case 't':
        ch = '\t'
      default:
      panic("only expected \\n or \\t")
      }
    }

    start.mode = kRuneClass
    start.rune = NewSingleRuneClass(ch)
  }
  p.nextc()
  return start, end
}

/**
 * Consume a closure: i.e. ( term + [ repitition ] )
 */
func (p *parser) closure() (start *instr, end *instr) {
  start, end = p.term()

  var req int
  var opt int
  greedy := true
  switch p.ch {
  case '?':
    req, opt = 0, 1
  case '*':
    req, opt = 0, -1
  case '+':
    req, opt = 1, -1
  case '{':
    panic("unsupported")
  default:
    return start, end // nothing to see here
  }

  if p.nextc() == '?' {
    greedy = false
    p.nextc()
  }

  if req == 0 {
    p_start := start
    start = p.instr()
    if greedy {
      start.out = p_start
    } else {
      start.out1 = p_start
    }
    if opt == -1 {
      p.out(end, start)
      end = start
    } else if opt == 1 {
      p_end := end
      end = p.instr()
      p.out(p_end, end)
      p.out(start, end)
    } else {
      panic("unsupported opt size")
    }
  } else if req == 1 {
    p_end := end
    end = p.instr()
    p.out(p_end, end)
    // assumes opt is non-0
    if greedy {
      end.out = start
    } else {
      end.out1 = start
    }
  } else {
    panic("unsupported")
  }

/*
  case '{':
    count_str := ""
    p.nextc()
    for unicode.IsDigit(p.ch) {
      count_str += fmt.Sprintf("%c", p.ch)
      p.nextc()
    }
    if len(count_str) == 0 {
      panic("{ must be followed by digit")
    }
    if p.ch == '}' {
      // fixed expansion
      count, _ := strconv.Atoi(count_str)
      panic(fmt.Sprintf("can't yet expand to: %d", count))

      for i := 1; i < count; i++ {
        // TODO: clone (start,end) n times!
      }
    } else if p.ch == ',' {
      panic("can't handle anything but {n}")
    } else {
      panic("unexpected char in {}")
    }
  }*/
  return start, end
}

/**
 * Match a regexp (defined as [closure]*) from parser, until either: EOF, |, or
 * ) is encountered.
 */
func (p *parser) regexp() (start *instr, end *instr) {
  start = p.instr()
  curr := start

  for {
    if p.ch == -1 || p.ch == '|' || p.ch == ')' {
      break
    }
    s, e := p.closure()
    p.out(curr, s)
    curr = e
  }

  end = p.instr()
  p.out(curr, end)
  return start, end
}

/**
 * Cleanup the given program. Assumes the given input is a flat slice containing
 * no nil instructions. Will not clean up the first instruction, as it is always
 * the canonical entry point for the regexp.
 *
 * Returns a similarly flat slice containing no nil instructions, however the
 * slice may potentially be smaller.
 */
func cleanup(prog []*instr) []*instr {
  // Detect kSplit recursion. We can remove this and convert it to a single path.
  states := NewStateSet(len(prog), len(prog))
  for i := 1; i < len(prog); i++ {
    states.Clear()
    pi := prog[i]
    var fn func(ci *instr) bool
    fn = func(ci *instr) bool {
      if ci != nil && ci.mode == kSplit {
        if states.Put(ci.idx) {
          // NOTE: I'm not sure if this will ever happen. Panic for now. If we're
          // confident this won't happen, we could move the panic to runtime.
          panic("regexp should never loop")
          return true
        }
        if fn(ci.out) {
          ci.out = nil
        }
        if fn(ci.out1) {
          ci.out1 = nil
        }
        return false
      }
      return false
    }
    fn(pi)
  }

  // Iterate through the program, and remove single-instr kSplits.
  // NB: Don't parse the first instr, it will always be single.
  for i := 1; i < len(prog); i++ {
    pi := prog[i]
    if pi.mode == kSplit && (pi.out1 == nil || pi.out == pi.out1) {
      for j := 0; j < len(prog); j++ {
        if prog[j] == nil {
          continue
        }
        pj := prog[j]
        if pj.out == pi {
          pj.out = pi.out
        }
        if pj.out1 == pi {
          pj.out1 = pi.out
        }
      }
      prog[i] = nil
    }
  }

  // We may now have nil gaps: shift everything up.
  last := 0
  for i := 0; i < len(prog); i++ {
    if prog[i] != nil {
      last = i
    } else {
      // find next non-nil, move here
      var found int
      for found = i; found < len(prog); found++ {
        if prog[found] != nil {
          break
        }
      }
      if found == len(prog) {
        break // no more entries
      }

      // move found to i
      prog[i] = prog[found]
      prog[i].idx = i
      prog[found] = nil
      last = i
    }
  }

  return prog[0:last+1]
}

/**
 * Generates a simple straight-forward NFA.
 */
func Parse(src string) (r *sregexp) {
  // possibly expand this RE all the way to the left
  if src[0] == '^' {
    src = "(" + src[1:len(src)]
  } else {
    src = ".*?(" + src
  }

  // possibly expand this RE to the right
  if src[len(src)-1] == '$' {
    src = src[0:len(src)-1] + ")"
  } else {
    src = src + ").*?"
  }

  re := &sregexp{make([]*instr, 0, 1), -1}
  p := parser{re, src, 0, 0}
  begin := p.instr()
  match := p.instr()
  match.mode = kMatch

  p.nextc()
  start, end := p.regexp()

  if p.ch != -1 {
    panic("could not consume all of regexp!")
  }

  p.out(begin, start)
  p.out(end, match)

  re.prog = cleanup(re.prog)
  return re
}
<commit_msg>re-retypo<commit_after>
package sre2

import (
  "fmt"
  "os"
  "unicode"
  "utf8"
)

/**
 * Regexp definition. Simple, just a list of states.
 */
type sregexp struct {
  prog []*instr         // list of states
  alts int              // number of marked alts [()'s] in this regexp
}

/**
 * Instruction type definitions, for `instr.mode`.
 */
const (
  kSplit = iota         // proceed down out & out1
  kAltBegin             // begin of alt section, i.e. '('
  kAltEnd               // end of alt section, i.e. ')'
  kRuneClass            // if match rune, proceed down out
  kMatch                // success state!
)

/**
 * Single instruction in regexp.
 */
type instr struct {
  idx int               // index of this instr
  mode byte             // mode (as above)
  out *instr            // next instr to process
  out1 *instr           // alt next instr (for kSplit)
  rune runeclass        // rune class
  alt int               // identifier of alt branch (for kAlt{Begin,End})
  alt_id *string        // string identifier of alt branch
}

/**
 * String-representation of an individual instruction.
 */
func (i *instr) str() string {
  str := fmt.Sprintf("{%d", i.idx)
  out := ""
  if i.out != nil {
    out += fmt.Sprintf(" out=%d", i.out.idx)
  }
  switch i.mode {
  case kSplit:
    str += " kSplit"
    if i.out1 != nil {
      out += fmt.Sprintf(" out1=%d", i.out1.idx)
    }
  case kAltBegin, kAltEnd:
    if i.mode == kAltBegin {
      str += " kAltBegin"
    } else {
      str += " kAltEnd"
    }
    str += fmt.Sprintf(" alt=%d", i.alt)
    if i.alt_id != nil {
      str += fmt.Sprintf(" alt_id=%s", *i.alt_id)
    }
  case kRuneClass:
    str += fmt.Sprint(" kRuneClass ", i.rune)
  case kMatch:
    str += " kMatch"
  }
  return str + out + "}"
}

/**
 * DebugOut writes the given regexp to Stderr, for debugging.
 */
func (r *sregexp) DebugOut() {
    for i := 0; i < len(r.prog); i++ {
      fmt.Fprintln(os.Stderr, i, r.prog[i].str())
    }
}

/*
 * Generic matcher for consuming instr instances (i.e. kRune/kCall). Does not
 * match anything else.
 */
func (s *instr) match(rune int) bool {
  return s.mode == kRuneClass && s.rune.MatchRune(rune)
}

/** transient parser state */
type parser struct {
  re *sregexp
  src string
  ch int
  pos int
}

/**
 * Generate a new pre-indexed instr.
 */
func (p *parser) instr() *instr {
  pos := len(p.re.prog)
  if pos == cap(p.re.prog) {
    local := p.re.prog
    p.re.prog = make([]*instr, pos, pos * 2)
    copy(p.re.prog, local)
  }
  p.re.prog = p.re.prog[0:pos+1]
  i := &instr{pos, kSplit, nil, nil, nil, -1, nil}
  p.re.prog[pos] = i
  return i
}

/**
 * Store/return the next character in parser. -1 indicates EOF.
 */
func (p *parser) nextc() int {
  if p.pos >= len(p.src) {
    p.ch = -1
  } else {
    c, w := utf8.DecodeRuneInString(p.src[p.pos:])
    p.ch = c
    p.pos += w
  }
  return p.ch
}

/**
 * Return the literal string from->to some expected characters. Assumes that the
 * cursor is resting on the from character. Will return the parser at the first
 * char past the result.
 */
func (p *parser) literal(start int, end int) (result string, err bool) {
  if p.ch != start {
    return "", true
  }

  result = ""
  for p.nextc() != end {
    if p.ch == -1 {
      return result, true
    }
    result += fmt.Sprintf("%c", p.ch)
  }
  return result, false
}

/**
 * Connect from -> to.
 */
func (p *parser) out(from *instr, to *instr) {
  if from.out == nil {
    from.out = to
  } else if from.mode == kSplit && from.out1 == nil {
    from.out1 = to
  } else {
    panic("can't out")
  }
}

/**
 * Consume some bracketed expression.
 */
func (p *parser) alt() (start *instr, end *instr) {
  use_alts := true
  var alt_id *string
  altpos := p.re.alts
  p.re.alts += 1

  if p.ch != '(' {
    panic("alt must start with '('")
  }

  end = p.instr() // shared end state for alt
  end.mode = kAltEnd
  end.alt = altpos

  p.nextc()
  if p.ch == '?' {
    // TODO: it might be appropriate to move this whole logic outside of alt().
    p.nextc()
    if p.ch == 'P' {
      p.nextc()
      s, err := p.literal('<', '>')
      if err {
        panic("couldn't consume name in < >")
      }
      alt_id = &s
      p.nextc() // move past '<'
    } else {
      // anything but 'P' means flags (unmatched).
      use_alts = false
      outer: for {
        switch p.ch {
        case ':':
          p.nextc() // move past ':'
          break outer // no more flags, process re
        case ')':
          panic("can't yet apply flags to outer")
          break outer // no more flags, ignore re, apply flags to outer
        default:
          panic(fmt.Sprint("flag unsupported:", p.ch))
        }
        p.nextc()
      }
    }
  }

  b_start, b_end := p.regexp()
  start = b_start
  p.out(b_end, end)

  for p.ch == '|' {
    start = p.instr()
    p.out(start, b_start)

    p.nextc()
    b_start, b_end = p.regexp()
    p.out(start, b_start)
    p.out(b_end, end)
    b_start = start
  }

  if p.ch != ')' {
    panic("alt must end with ')'")
  }

  alt_begin := p.instr()
  alt_begin.mode = kAltBegin
  alt_begin.alt = altpos
  p.out(alt_begin, start)

  if !use_alts {
    // clear alts, this is an unmatched group
    alt_begin.mode = kSplit
    end.mode = kSplit
  } else if alt_id != nil {
    // set alt string id
    alt_begin.alt_id = alt_id
    end.alt_id = alt_id
  }

  return alt_begin, end
}

/**
 * Consume a character class, and return a single instr representing this class.
 */
func (p *parser) charclass() runeclass {
  if p.ch != '[' {
    panic("expect charclass to start with [")
  }
  p.nextc() // walk over '['

  class := NewComplexRuneClass()
  negate := false
  if p.ch == '^' {
    negate = !negate
    p.nextc()
  }

  outer: for {
    switch p.ch {
    case '[':
      if p.nextc() != ':' {
        panic("expected ascii class [:")
      }
      _, err := p.literal(':', ':')
      if err {
        panic("could not consume ascii class")
      }
      if p.nextc() != ']' {
        panic("unclosed ascii class")
      }
    case ']':
      // NOTE: caller expects us not to walk over last bracket.
      break outer
    case -1:
      panic("unclosed character class")
    }

    rune := p.ch
    r := make([]unicode.Range, 1)
    if p.nextc() == '-' {
      rune_end := p.nextc()
      if rune >= rune_end {
        panic(fmt.Sprintf("unexpected range: %c >= %c", rune, rune_end))
      }
      r[0] = unicode.Range{rune, rune_end, 1}
      p.nextc() // walk past end of range
    } else {
      r[0] = unicode.Range{rune, rune, 1}
    }
    if negate {
      class.Exclude(r)
    } else {
      class.Include(r)
    }
  }

  return class
}

/**
 * Consume a single term (note that term may include a bracketed expression).
 */
func (p *parser) term() (start *instr, end *instr) {
  start = p.instr()
  end = start

  switch p.ch {
  case -1:
    panic("EOF in term")
  case '*', '+', '{', '?':
    panic("unexpected expansion char")
  case ')', '}', ']':
    panic("unexpected close element")
  case '(':
    start, end = p.alt()
  case '[':
    start.mode = kRuneClass
    start.rune = p.charclass()
  case '$':
    panic("not yet supported: end of string")
  case '^':
    panic("not yet supported: start of string")
  case '.':
    start.mode = kRuneClass
    start.rune = NewAnyRuneClass()
  default:
    ch := p.ch
    if ch == '\\' {
      switch p.nextc() {
      case 'n':
        ch = '\n'
      case 't':
        ch = '\t'
      default:
      panic("only expected \\n or \\t")
      }
    }

    start.mode = kRuneClass
    start.rune = NewSingleRuneClass(ch)
  }
  p.nextc()
  return start, end
}

/**
 * Consume a closure: i.e. ( term + [ repitition ] )
 */
func (p *parser) closure() (start *instr, end *instr) {
  start, end = p.term()

  var req int
  var opt int
  greedy := true
  switch p.ch {
  case '?':
    req, opt = 0, 1
  case '*':
    req, opt = 0, -1
  case '+':
    req, opt = 1, -1
  case '{':
    panic("unsupported")
  default:
    return start, end // nothing to see here
  }

  if p.nextc() == '?' {
    greedy = false
    p.nextc()
  }

  if req == 0 {
    p_start := start
    start = p.instr()
    if greedy {
      start.out = p_start
    } else {
      start.out1 = p_start
    }
    if opt == -1 {
      p.out(end, start)
      end = start
    } else if opt == 1 {
      p_end := end
      end = p.instr()
      p.out(p_end, end)
      p.out(start, end)
    } else {
      panic("unsupported opt size")
    }
  } else if req == 1 {
    p_end := end
    end = p.instr()
    p.out(p_end, end)
    // assumes opt is non-0
    if greedy {
      end.out = start
    } else {
      end.out1 = start
    }
  } else {
    panic("unsupported")
  }

/*
  case '{':
    count_str := ""
    p.nextc()
    for unicode.IsDigit(p.ch) {
      count_str += fmt.Sprintf("%c", p.ch)
      p.nextc()
    }
    if len(count_str) == 0 {
      panic("{ must be followed by digit")
    }
    if p.ch == '}' {
      // fixed expansion
      count, _ := strconv.Atoi(count_str)
      panic(fmt.Sprintf("can't yet expand to: %d", count))

      for i := 1; i < count; i++ {
        // TODO: clone (start,end) n times!
      }
    } else if p.ch == ',' {
      panic("can't handle anything but {n}")
    } else {
      panic("unexpected char in {}")
    }
  }*/
  return start, end
}

/**
 * Match a regexp (defined as [closure]*) from parser, until either: EOF, |, or
 * ) is encountered.
 */
func (p *parser) regexp() (start *instr, end *instr) {
  start = p.instr()
  curr := start

  for {
    if p.ch == -1 || p.ch == '|' || p.ch == ')' {
      break
    }
    s, e := p.closure()
    p.out(curr, s)
    curr = e
  }

  end = p.instr()
  p.out(curr, end)
  return start, end
}

/**
 * Cleanup the given program. Assumes the given input is a flat slice containing
 * no nil instructions. Will not clean up the first instruction, as it is always
 * the canonical entry point for the regexp.
 *
 * Returns a similarly flat slice containing no nil instructions, however the
 * slice may potentially be smaller.
 */
func cleanup(prog []*instr) []*instr {
  // Detect kSplit recursion. We can remove this and convert it to a single path.
  states := NewStateSet(len(prog), len(prog))
  for i := 1; i < len(prog); i++ {
    states.Clear()
    pi := prog[i]
    var fn func(ci *instr) bool
    fn = func(ci *instr) bool {
      if ci != nil && ci.mode == kSplit {
        if states.Put(ci.idx) {
          // NOTE: I'm not sure if this will ever happen. Panic for now. If we're
          // confident this won't happen, we could move the panic to runtime.
          panic("regexp should never loop")
          return true
        }
        if fn(ci.out) {
          ci.out = nil
        }
        if fn(ci.out1) {
          ci.out1 = nil
        }
        return false
      }
      return false
    }
    fn(pi)
  }

  // Iterate through the program, and remove single-instr kSplits.
  // NB: Don't parse the first instr, it will always be single.
  for i := 1; i < len(prog); i++ {
    pi := prog[i]
    if pi.mode == kSplit && (pi.out1 == nil || pi.out == pi.out1) {
      for j := 0; j < len(prog); j++ {
        if prog[j] == nil {
          continue
        }
        pj := prog[j]
        if pj.out == pi {
          pj.out = pi.out
        }
        if pj.out1 == pi {
          pj.out1 = pi.out
        }
      }
      prog[i] = nil
    }
  }

  // We may now have nil gaps: shift everything up.
  last := 0
  for i := 0; i < len(prog); i++ {
    if prog[i] != nil {
      last = i
    } else {
      // find next non-nil, move here
      var found int
      for found = i; found < len(prog); found++ {
        if prog[found] != nil {
          break
        }
      }
      if found == len(prog) {
        break // no more entries
      }

      // move found to i
      prog[i] = prog[found]
      prog[i].idx = i
      prog[found] = nil
      last = i
    }
  }

  return prog[0:last+1]
}

/**
 * Generates a simple straight-forward NFA.
 */
func Parse(src string) (r *sregexp) {
  // possibly expand this RE all the way to the left
  if src[0] == '^' {
    src = "(" + src[1:len(src)]
  } else {
    src = ".*?(" + src
  }

  // possibly expand this RE to the right
  if src[len(src)-1] == '$' {
    src = src[0:len(src)-1] + ")"
  } else {
    src = src + ").*?"
  }

  re := &sregexp{make([]*instr, 0, 1), 0}
  p := parser{re, src, -1, 0}
  begin := p.instr()
  match := p.instr()
  match.mode = kMatch

  p.nextc()
  start, end := p.regexp()

  if p.ch != -1 {
    panic("could not consume all of regexp!")
  }

  p.out(begin, start)
  p.out(end, match)

  re.prog = cleanup(re.prog)
  return re
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"io/ioutil"
	"log"
	"github.com/cloudfoundry/sshark"
	"github.com/cloudfoundry/go_cfmessagebus"
)

func main() {
	agent := sshark.NewAgent("/tmp/warden.sock")

  pubkeyPath := fmt.Sprintf("%s/.ssh/id_rsa.pub", os.Getenv("HOME"))

  pubkey, err := ioutil.ReadFile(pubkeyPath)
  if err != nil {
    log.Fatal(err.Error())
    return
  }

  sess, err := agent.StartSession("foo")
  if err != nil {
    log.Fatal(err.Error())
    return
  }

  log.Println(sess.Port)

  err = sess.LoadPublicKey(string(pubkey))
  if err != nil {
    log.Fatal(err.Error())
    return
  }

  err = sess.StartSSHServer()
  if err != nil {
    log.Fatal(err.Error())
    return
  }
}
<commit_msg>executable now does something useful<commit_after>package main

import (
	"fmt"
	"github.com/cloudfoundry/go_cfmessagebus"
	"github.com/cloudfoundry/sshark"
	"io/ioutil"
	"log"
	"os"
)

func main() {
	agent := sshark.NewAgent("/tmp/warden.sock")

	pubkeyPath := fmt.Sprintf("%s/.ssh/id_rsa.pub", os.Getenv("HOME"))

	pubkey, err := ioutil.ReadFile(pubkeyPath)
	if err != nil {
		log.Fatal(err.Error())
		return
	}

	sess, err := agent.StartSession("foo")
	if err != nil {
		log.Fatal(err.Error())
		return
	}

	log.Println(sess.Port)

	err = sess.LoadPublicKey(string(pubkey))
	if err != nil {
		log.Fatal(err.Error())
		return
	}

	err = sess.StartSSHServer()
	if err != nil {
		log.Fatal(err.Error())
		return
	}
}
<|endoftext|>


<commit_before>package statc

import (
	"math"
	"math/rand"
	"sort"
	"sync"
	"time"
)

// A Timer is used to time how long things take to run
type Timer struct {
	mtx sync.Mutex
	timerSnap

	sampPercent int // Percent of samples to save
	samples     int64Slice

	// Cached names
	nStddev, nMean, nMin, nMax, nCount, nP50, nP75, nP90, nP95 Name
}

type int64Slice []int64

type timerSnap struct {
	sum, sumOfSq       int64 // For stddev + mean
	stddev             int64
	mean               int64
	min, max           int64
	count              int64
	p50, p75, p90, p95 int64 // 50th, 75th, 90th, and 95th percentiles
}

var (
	timerRand  = rand.New(rand.NewSource(time.Now().Unix()))
	timerReset = timerSnap{
		min: math.MaxInt64,
	}
)

// NewTimer creates a new timer that outputs stats prefixed with the given
// name. The names are cached internally to limit allocations.
//
// The timer also reports percentiles of data by sampling. The given
// `sampPercent` controls what percent of samples to save for percentile
// calculations (0 - 100).
func NewTimer(name Name, sampPercent int) *Timer {
	if sampPercent < 0 {
		sampPercent = 0
	}

	if sampPercent > 100 {
		sampPercent = 100
	}

	return &Timer{
		timerSnap:   timerReset,
		sampPercent: sampPercent,
		nStddev:     name.Join("stddev"),
		nMean:       name.Join("mean"),
		nMin:        name.Join("min"),
		nMax:        name.Join("max"),
		nCount:      name.Join("count"),
		nP50:        name.Join("p50"),
		nP75:        name.Join("p75"),
		nP90:        name.Join("p90"),
		nP95:        name.Join("p95"),
	}
}

// TimeFunc times how long it takes the given function to run
func (t *Timer) TimeFunc(cb func()) {
	start := time.Now()
	cb()
	t.Add(time.Now().Sub(start))
}

// Add adds timing information
func (t *Timer) Add(dd time.Duration) {
	d := int64(dd)
	sq := d * d

	keep := t.sampPercent > int(timerRand.Int31n(100))

	t.mtx.Lock()

	t.count++
	t.sumOfSq += sq
	t.sum += d

	if d > t.max {
		t.max = d
	}

	if d < t.min {
		t.min = d
	}

	if keep {
		t.samples = append(t.samples, d)
	}

	t.mtx.Unlock()
}

// Snapshot implements Snapshotter
func (t *Timer) Snapshot(a Adder) {
	t.snapshot(a, false)
}

func (t *Timer) snapshot(a Adder, ignoreIfEmpty bool) {
	nsamps := make(int64Slice, 0, t.count)

	t.mtx.Lock()

	ts := t.timerSnap
	t.timerSnap = timerReset

	samps := t.samples
	t.samples = nsamps

	t.mtx.Unlock()

	sort.Sort(samps)

	if ts.min == timerReset.min {
		ts.min = 0
	}

	if ts.count == 0 && ignoreIfEmpty {
		return
	}

	if ts.count > 0 {
		ss := ts.sumOfSq - ((ts.sum * ts.sum) / ts.count)
		ts.stddev = int64(math.Sqrt(float64(ss / ts.count)))
		ts.mean = ts.sum / ts.count
	}

	if len(samps) > 0 {
		l := float64(len(samps))

		ts.p50 = samps[int(math.Ceil(l*.50))-1]
		ts.p75 = samps[int(math.Ceil(l*.75))-1]
		ts.p90 = samps[int(math.Ceil(l*.90))-1]
		ts.p95 = samps[int(math.Ceil(l*.95))-1]
	}

	a.AddInt(t.nStddev, ts.stddev)
	a.AddInt(t.nMean, ts.mean)
	a.AddInt(t.nMin, ts.min)
	a.AddInt(t.nMax, ts.max)
	a.AddInt(t.nCount, ts.count)
	a.AddInt(t.nP50, ts.p50)
	a.AddInt(t.nP75, ts.p75)
	a.AddInt(t.nP90, ts.p90)
	a.AddInt(t.nP95, ts.p95)
}

func (p int64Slice) Len() int           { return len(p) }
func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
<commit_msg>statc/timer: Fix rand<commit_after>package statc

import (
	"math"
	"math/rand"
	"sort"
	"sync"
	"time"
)

// A Timer is used to time how long things take to run
type Timer struct {
	mtx sync.Mutex
	timerSnap

	sampPercent int // Percent of samples to save
	samples     int64Slice

	// Cached names
	nStddev, nMean, nMin, nMax, nCount, nP50, nP75, nP90, nP95 Name
}

type int64Slice []int64

type timerSnap struct {
	sum, sumOfSq       int64 // For stddev + mean
	stddev             int64
	mean               int64
	min, max           int64
	count              int64
	p50, p75, p90, p95 int64 // 50th, 75th, 90th, and 95th percentiles
}

var (
	timerRand  = rand.New(rand.NewSource(time.Now().Unix()))
	timerReset = timerSnap{
		min: math.MaxInt64,
	}

	// Rand is not safe to use concurrently, and the global rand functions all
	// use a mutex. Another pool to the rescue!
	randPool = sync.Pool{
		New: func() interface{} {
			return rand.New(rand.NewSource(time.Now().UnixNano()))
		},
	}
)

// NewTimer creates a new timer that outputs stats prefixed with the given
// name. The names are cached internally to limit allocations.
//
// The timer also reports percentiles of data by sampling. The given
// `sampPercent` controls what percent of samples to save for percentile
// calculations (0 - 100).
func NewTimer(name Name, sampPercent int) *Timer {
	if sampPercent < 0 {
		sampPercent = 0
	}

	if sampPercent > 100 {
		sampPercent = 100
	}

	return &Timer{
		timerSnap:   timerReset,
		sampPercent: sampPercent,
		nStddev:     name.Join("stddev"),
		nMean:       name.Join("mean"),
		nMin:        name.Join("min"),
		nMax:        name.Join("max"),
		nCount:      name.Join("count"),
		nP50:        name.Join("p50"),
		nP75:        name.Join("p75"),
		nP90:        name.Join("p90"),
		nP95:        name.Join("p95"),
	}
}

// TimeFunc times how long it takes the given function to run
func (t *Timer) TimeFunc(cb func()) {
	start := time.Now()
	cb()
	t.Add(time.Now().Sub(start))
}

// Add adds timing information
func (t *Timer) Add(dd time.Duration) {
	d := int64(dd)
	sq := d * d

	rand := randPool.Get().(*rand.Rand)
	keep := t.sampPercent > int(rand.Int31n(100))
	randPool.Put(rand)

	t.mtx.Lock()

	t.count++
	t.sumOfSq += sq
	t.sum += d

	if d > t.max {
		t.max = d
	}

	if d < t.min {
		t.min = d
	}

	if keep {
		t.samples = append(t.samples, d)
	}

	t.mtx.Unlock()
}

// Snapshot implements Snapshotter
func (t *Timer) Snapshot(a Adder) {
	t.snapshot(a, false)
}

func (t *Timer) snapshot(a Adder, ignoreIfEmpty bool) {
	nsamps := make(int64Slice, 0, t.count)

	t.mtx.Lock()

	ts := t.timerSnap
	t.timerSnap = timerReset

	samps := t.samples
	t.samples = nsamps

	t.mtx.Unlock()

	sort.Sort(samps)

	if ts.min == timerReset.min {
		ts.min = 0
	}

	if ts.count == 0 && ignoreIfEmpty {
		return
	}

	if ts.count > 0 {
		ss := ts.sumOfSq - ((ts.sum * ts.sum) / ts.count)
		ts.stddev = int64(math.Sqrt(float64(ss / ts.count)))
		ts.mean = ts.sum / ts.count
	}

	if len(samps) > 0 {
		l := float64(len(samps))

		ts.p50 = samps[int(math.Ceil(l*.50))-1]
		ts.p75 = samps[int(math.Ceil(l*.75))-1]
		ts.p90 = samps[int(math.Ceil(l*.90))-1]
		ts.p95 = samps[int(math.Ceil(l*.95))-1]
	}

	a.AddInt(t.nStddev, ts.stddev)
	a.AddInt(t.nMean, ts.mean)
	a.AddInt(t.nMin, ts.min)
	a.AddInt(t.nMax, ts.max)
	a.AddInt(t.nCount, ts.count)
	a.AddInt(t.nP50, ts.p50)
	a.AddInt(t.nP75, ts.p75)
	a.AddInt(t.nP90, ts.p90)
	a.AddInt(t.nP95, ts.p95)
}

func (p int64Slice) Len() int           { return len(p) }
func (p int64Slice) Less(i, j int) bool { return p[i] < p[j] }
func (p int64Slice) Swap(i, j int)      { p[i], p[j] = p[j], p[i] }
<|endoftext|>


<commit_before>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/dpapathanasiou/go-recaptcha"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username    string
	Password    string
	EmailServer string
	Port        int
}

type SmtpTemplateData struct {
	From    string
	To      string
	Subject string
	Body    string
}

type Configuration struct {
	Smtp                EmailUser
	RecaptchaPrivateKey string
}

type ReCaptcha struct {
	Response  string
	Challenge string
}

type SendEmailData struct {
	YourEmail string
	YourName  string
	Feedback  string
	Captcha   ReCaptcha
}

var conf Configuration

func sendMail(emailUser EmailUser, auth smtp.Auth, from string, to string, subject string, body string) error {
	const emailTemplate = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}

{{.Body}}

Sincerely,

{{.From}}
`
	var err error
	var doc bytes.Buffer
	context := &SmtpTemplateData{from, to, subject, body}
	t := template.New("emailTemplate")
	if t, err = t.Parse(emailTemplate); err != nil {
		log.Print("error trying to parse mail template ", err)
	}
	if err = t.Execute(&doc, context); err != nil {
		log.Print("error trying to execute mail template ", err)
	}
	err = smtp.SendMail(emailUser.EmailServer+":"+strconv.Itoa(emailUser.Port),
		auth,
		emailUser.Username,
		[]string{"nathanleclaire@gmail.com"},
		doc.Bytes())
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}

	return nil
}

func readConfigurationFile(filepath string) Configuration {
	var conf Configuration
	rawConfigurationJson, err := ioutil.ReadFile(filepath)
	if err != nil {
		log.Print("error reading smtp config file ", err)
	}
	err = json.Unmarshal(rawConfigurationJson, &conf)
	if err != nil {
		log.Print("error unmarshalling config ", err)
	}
	return conf
}

func connectToSmtpServer(emailUser EmailUser) smtp.Auth {
	auth := smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
	return auth
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	failResponseJSON, err := json.Marshal(failResponse)
	if err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	urlToScrape := strings.ToLower(r.URL.Query().Get("urlToScrape"))

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(urlToScrape); e == nil {
		if crossDomainRegex, err := regexp.Compile(`^http`); err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}
		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			if href, exists := s.Attr("href"); exists == true {
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				} else {
					if href != "" {
						links = append(links, urlToScrape+href)
					} else {
						// TODO: set error on blank link in client side code,
						// also change over to including content of link text
						// to show in table
						links = append(links, "")
					}
				}
			} else {
				log.Print("href does not exist for: ", s)
			}
		})
		parsedResponse := &ParsedResponse{true, links}
		if parsedResponseJSON, err = json.Marshal(parsedResponse); err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}
	} else {
		log.Print("error querying for document: ", urlToScrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	urlToCheck := r.URL.Query().Get("urlToCheck")
	externalServerResponse, err := http.Get(urlToCheck)
	if err != nil {
		log.Print("error getting in checkHandler ", urlToCheck)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	responseJSON, err := json.Marshal(response)
	if err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandlerClosure(auth smtp.Auth, recaptchaPrivateKey string, emailUser EmailUser) http.HandlerFunc {
	// Use a closure so we can pass auth to the handler
	return (func(w http.ResponseWriter, r *http.Request) {

		var jsonResponse []byte
		var err error
		response := map[string]interface{}{
			"success": true,
		}
		dec := json.NewDecoder(r.Body)
		contactData := SendEmailData{}
		err = dec.Decode(&contactData)
		if err != nil {
			log.Print(err)
			response["success"] = false
		}

		// call the recaptcha server
		recaptcha.Init(recaptchaPrivateKey)
		captchaIsValid := recaptcha.Confirm(r.RemoteAddr, contactData.Captcha.Challenge, contactData.Captcha.Response)

		if captchaIsValid {
			go sendMail(emailUser,
				auth,
				contactData.YourName+fmt.Sprintf(" <%s>", contactData.YourEmail),
				"Nathan LeClaire <nathan.leclaire@gmail.com>",
				"CFBL Feedback from "+contactData.YourName,
				contactData.Feedback)
		} else {
			response["success"] = false
		}
		jsonResponse, err = json.Marshal(response)
		if err != nil {
			log.Print("marshalling r ", err)
		}
		w.Write(jsonResponse)
	})
}

func main() {
	conf = readConfigurationFile("../conf/conf.json")
	auth := connectToSmtpServer(conf.Smtp)
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandlerClosure(auth, conf.RecaptchaPrivateKey, conf.Smtp))
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	err := http.ListenAndServe(":8000", nil)
	if err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<commit_msg>move to save-line-err style filewide...<commit_after>package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"github.com/dpapathanasiou/go-recaptcha"
	"io/ioutil"
	"log"
	"net/http"
	"net/smtp"
	"regexp"
	"strconv"
	"strings"
	"text/template"
)

type ParsedResponse struct {
	Success bool     `json:"success"`
	Links   []string `json:"links"`
}

type EmailUser struct {
	Username    string
	Password    string
	EmailServer string
	Port        int
}

type SmtpTemplateData struct {
	From    string
	To      string
	Subject string
	Body    string
}

type Configuration struct {
	Smtp                EmailUser
	RecaptchaPrivateKey string
}

type ReCaptcha struct {
	Response  string
	Challenge string
}

type SendEmailData struct {
	YourEmail string
	YourName  string
	Feedback  string
	Captcha   ReCaptcha
}

var conf Configuration

func sendMail(emailUser EmailUser, auth smtp.Auth, from string, to string, subject string, body string) error {
	const emailTemplate = `From: {{.From}}
To: {{.To}}
Subject: {{.Subject}}

{{.Body}}

Sincerely,

{{.From}}
`
	var err error
	var doc bytes.Buffer
	context := &SmtpTemplateData{from, to, subject, body}
	t := template.New("emailTemplate")
	if t, err = t.Parse(emailTemplate); err != nil {
		log.Print("error trying to parse mail template ", err)
	}
	if err = t.Execute(&doc, context); err != nil {
		log.Print("error trying to execute mail template ", err)
	}
	err = smtp.SendMail(emailUser.EmailServer+":"+strconv.Itoa(emailUser.Port),
		auth,
		emailUser.Username,
		[]string{"nathanleclaire@gmail.com"},
		doc.Bytes())
	if err != nil {
		log.Print("ERROR: attempting to send a mail ", err)
	}

	return nil
}

func readConfigurationFile(filepath string) Configuration {
	var conf Configuration
	if rawConfigurationJson, err := ioutil.ReadFile(filepath); err != nil {
		log.Print("error reading smtp config file ", err)
	}
	if err = json.Unmarshal(rawConfigurationJson, &conf); err != nil {
		log.Print("error unmarshalling config ", err)
	}
	return conf
}

func connectToSmtpServer(emailUser EmailUser) smtp.Auth {
	auth := smtp.PlainAuth("", emailUser.Username, emailUser.Password, emailUser.EmailServer)
	return auth
}

func getFailedSlurpResponse() []byte {
	failResponse := &ParsedResponse{false, nil}
	if failResponseJSON, err := json.Marshal(failResponse); err != nil {
		log.Print("something went really weird in attempt to marshal a fail json ", err)
		failResponseJSON, _ = json.Marshal(nil)
	}
	return failResponseJSON
}

func slurpHandler(w http.ResponseWriter, r *http.Request) {
	urlToScrape := strings.ToLower(r.URL.Query().Get("urlToScrape"))

	var doc *goquery.Document
	var e error
	var parsedResponseJSON []byte

	links := []string{}

	if doc, e = goquery.NewDocument(urlToScrape); e == nil {
		if crossDomainRegex, err := regexp.Compile(`^http`); err != nil {
			log.Printf("issue compiling regular expression to validate cross domain URLs")
		}
		doc.Find("a").Each(func(i int, s *goquery.Selection) {
			if href, exists := s.Attr("href"); exists == true {
				if crossDomainRegex.Match([]byte(href)) {
					links = append(links, href)
				} else {
					if href != "" {
						links = append(links, urlToScrape+href)
					} else {
						// TODO: set error on blank link in client side code,
						// also change over to including content of link text
						// to show in table
						links = append(links, "")
					}
				}
			} else {
				log.Print("href does not exist for: ", s)
			}
		})
		parsedResponse := &ParsedResponse{true, links}
		if parsedResponseJSON, err = json.Marshal(parsedResponse); err != nil {
			parsedResponseJSON = getFailedSlurpResponse()
		}
	} else {
		log.Print("error querying for document: ", urlToScrape, "err : ", e)
		parsedResponseJSON = getFailedSlurpResponse()
	}

	w.Write(parsedResponseJSON)

}

func checkHandler(w http.ResponseWriter, r *http.Request) {
	urlToCheck := r.URL.Query().Get("urlToCheck")
	if externalServerResponse, err := http.Get(urlToCheck); err != nil {
		log.Print("error getting in checkHandler ", urlToCheck)
	}

	response := map[string]interface{}{
		"status":     externalServerResponse.Status,
		"statusCode": externalServerResponse.StatusCode,
	}

	if responseJSON, err := json.Marshal(response); err != nil {
		log.Print("error Marshalling check response json: ", err)
	}
	w.Write(responseJSON)
}

func emailHandlerClosure(auth smtp.Auth, recaptchaPrivateKey string, emailUser EmailUser) http.HandlerFunc {
	// Use a closure so we can pass auth to the handler
	return (func(w http.ResponseWriter, r *http.Request) {

		var jsonResponse []byte
		var err error
		response := map[string]interface{}{
			"success": true,
		}
		dec := json.NewDecoder(r.Body)
		contactData := SendEmailData{}
		if dec.Decode(&contactData) != nil {
			log.Print(err)
			response["success"] = false
		}

		// call the recaptcha server
		recaptcha.Init(recaptchaPrivateKey)
		captchaIsValid := recaptcha.Confirm(r.RemoteAddr, contactData.Captcha.Challenge, contactData.Captcha.Response)

		if captchaIsValid {
			go sendMail(emailUser,
				auth,
				contactData.YourName+fmt.Sprintf(" <%s>", contactData.YourEmail),
				"Nathan LeClaire <nathan.leclaire@gmail.com>",
				"CFBL Feedback from "+contactData.YourName,
				contactData.Feedback)
		} else {
			response["success"] = false
		}
		if jsonResponse, err = json.Marshal(response); err != nil {
			log.Print("marshalling r ", err)
		}
		w.Write(jsonResponse)
	})
}

func main() {
	conf = readConfigurationFile("../conf/conf.json")
	auth := connectToSmtpServer(conf.Smtp)
	http.HandleFunc("/slurp", slurpHandler)
	http.HandleFunc("/check", checkHandler)
	http.HandleFunc("/email", emailHandlerClosure(auth, conf.RecaptchaPrivateKey, conf.Smtp))
	http.Handle("/", http.FileServer(http.Dir("..")))
	http.Handle("/css/", http.FileServer(http.Dir("..")))
	http.Handle("/img/", http.FileServer(http.Dir("..")))
	http.Handle("/lib/", http.FileServer(http.Dir("..")))
	http.Handle("/partials/", http.FileServer(http.Dir("..")))
	http.Handle("/js/", http.FileServer(http.Dir("..")))
	if http.ListenAndServe(":8000", nil) != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
<|endoftext|>