<commit_before>package yiigo

import (
	"fmt"
	"strings"
	"sync"

	"gopkg.in/ini.v1"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var (
	DB    *sqlx.DB
	dbmap map[string]*sqlx.DB
	dbmux sync.RWMutex
)

// SQL expression
type expr struct {
	expr string
	args []interface{}
}

// initMySQL init mysql connection
func initMySQL() error {
	sections := childSections("mysql")

	if len(sections) > 0 {
		return initMultiDB(sections)
	}

	return initSingleDB()
}

// initSingleDB init single db connection
func initSingleDB() error {
	var err error

	host := EnvString("mysql", "host", "localhost")
	port := EnvInt("mysql", "port", 3306)
	username := EnvString("mysql", "username", "root")
	password := EnvString("mysql", "password", "")
	database := EnvString("mysql", "database", "test")
	charset := EnvString("mysql", "charset", "utf8mb4")
	collection := EnvString("mysql", "collection", "utf8mb4_general_ci")

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

	DB, err = sqlx.Open("mysql", dsn)

	if err != nil {
		DB.Close()
		return err
	}

	DB.SetMaxOpenConns(EnvInt("mysql", "maxOpenConns", 20))
	DB.SetMaxIdleConns(EnvInt("mysql", "maxIdleConns", 10))

	err = DB.Ping()

	if err != nil {
		DB.Close()
		return err
	}

	return nil
}

// initMultiDB init multi db connections
func initMultiDB(sections []*ini.Section) error {
	dbmap = make(map[string]*sqlx.DB)

	for _, v := range sections {
		host := v.Key("host").MustString("localhost")
		port := v.Key("port").MustInt(3306)
		username := v.Key("username").MustString("root")
		password := v.Key("password").MustString("")
		database := v.Key("database").MustString("test")
		charset := v.Key("charset").MustString("utf8mb4")
		collection := v.Key("collection").MustString("utf8mb4_general_ci")

		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

		db, err := sqlx.Open("mysql", dsn)

		if err != nil {
			db.Close()
			return err
		}

		db.SetMaxOpenConns(v.Key("maxOpenConns").MustInt(20))
		db.SetMaxIdleConns(v.Key("maxIdleConns").MustInt(10))

		err = db.Ping()

		if err != nil {
			db.Close()
			return err
		}

		dbmap[v.Name()] = db
	}

	if db, ok := dbmap["mysql.default"]; ok {
		DB = db
	}

	return nil
}

// DBConn get db
func DBConn(conn ...string) (*sqlx.DB, error) {
	dbmux.RLock()
	defer dbmux.RUnlock()

	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("mysql.%s", c)

	db, ok := dbmap[schema]

	if !ok {
		return nil, fmt.Errorf("database %s is not connected", schema)
	}

	return db, nil
}

// InsertSQL build insert sql
func InsertSQL(table string, data X) (string, []interface{}) {
	columns := []string{}
	placeholders := []string{}
	binds := []interface{}{}

	for k, v := range data {
		columns = append(columns, k)
		placeholders = append(placeholders, "?")
		binds = append(binds, v)
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// BatchInsertSQL build batch insert sql
func BatchInsertSQL(table string, columns []string, data []X) (string, []interface{}) {
	placeholders := []string{}
	binds := []interface{}{}

	for _, v := range data {
		bindvars := []string{}

		for _, c := range columns {
			binds = append(binds, v[c])
			bindvars = append(bindvars, "?")
		}

		placeholders = append(placeholders, fmt.Sprintf("(%s)", strings.Join(bindvars, ",")))
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// UpdateSQL build update sql
func UpdateSQL(sql string, args ...interface{}) (string, []interface{}) {
	sets := []string{}
	binds := []interface{}{}

	for k, v := range args[0].(X) {
		if expr, ok := v.(*expr); ok {
			sets = append(sets, fmt.Sprintf("%s = %s", k, expr.expr))
			binds = append(binds, expr.args...)
		} else {
			sets = append(sets, fmt.Sprintf("%s = ?", k))
			binds = append(binds, v)
		}
	}

	sql = strings.Replace(sql, "?", strings.Join(sets, ", "), 1)
	binds = append(binds, args[1:]...)

	return sql, binds
}

// Expr expression, eg: yiigo.Expr("price * ? + ?", 2, 100)
func Expr(expression string, args ...interface{}) *expr {
	return &expr{expr: expression, args: args}
}
<commit_msg>change mysql Open to Connect<commit_after>package yiigo

import (
	"fmt"
	"strings"
	"sync"

	"gopkg.in/ini.v1"

	_ "github.com/go-sql-driver/mysql"
	"github.com/jmoiron/sqlx"
)

var (
	DB    *sqlx.DB
	dbmap map[string]*sqlx.DB
	dbmux sync.RWMutex
)

// SQL expression
type expr struct {
	expr string
	args []interface{}
}

// initMySQL init mysql connection
func initMySQL() error {
	sections := childSections("mysql")

	if len(sections) > 0 {
		return initMultiDB(sections)
	}

	return initSingleDB()
}

// initSingleDB init single db connection
func initSingleDB() error {
	var err error

	host := EnvString("mysql", "host", "localhost")
	port := EnvInt("mysql", "port", 3306)
	username := EnvString("mysql", "username", "root")
	password := EnvString("mysql", "password", "")
	database := EnvString("mysql", "database", "test")
	charset := EnvString("mysql", "charset", "utf8mb4")
	collection := EnvString("mysql", "collection", "utf8mb4_general_ci")

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

	DB, err = sqlx.Connect("mysql", dsn)

	if err != nil {
		DB.Close()
		return err
	}

	DB.SetMaxOpenConns(EnvInt("mysql", "maxOpenConns", 20))
	DB.SetMaxIdleConns(EnvInt("mysql", "maxIdleConns", 10))

	return nil
}

// initMultiDB init multi db connections
func initMultiDB(sections []*ini.Section) error {
	dbmap = make(map[string]*sqlx.DB)

	for _, v := range sections {
		host := v.Key("host").MustString("localhost")
		port := v.Key("port").MustInt(3306)
		username := v.Key("username").MustString("root")
		password := v.Key("password").MustString("")
		database := v.Key("database").MustString("test")
		charset := v.Key("charset").MustString("utf8mb4")
		collection := v.Key("collection").MustString("utf8mb4_general_ci")

		dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=%s&collation=%s&parseTime=True&loc=Local", username, password, host, port, database, charset, collection)

		db, err := sqlx.Connect("mysql", dsn)

		if err != nil {
			db.Close()
			return err
		}

		db.SetMaxOpenConns(v.Key("maxOpenConns").MustInt(20))
		db.SetMaxIdleConns(v.Key("maxIdleConns").MustInt(10))

		dbmap[v.Name()] = db
	}

	if db, ok := dbmap["mysql.default"]; ok {
		DB = db
	}

	return nil
}

// DBConn get db
func DBConn(conn ...string) (*sqlx.DB, error) {
	dbmux.RLock()
	defer dbmux.RUnlock()

	c := "default"

	if len(conn) > 0 {
		c = conn[0]
	}

	schema := fmt.Sprintf("mysql.%s", c)

	db, ok := dbmap[schema]

	if !ok {
		return nil, fmt.Errorf("database %s is not connected", schema)
	}

	return db, nil
}

// InsertSQL build insert sql
func InsertSQL(table string, data X) (string, []interface{}) {
	columns := []string{}
	placeholders := []string{}
	binds := []interface{}{}

	for k, v := range data {
		columns = append(columns, k)
		placeholders = append(placeholders, "?")
		binds = append(binds, v)
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// BatchInsertSQL build batch insert sql
func BatchInsertSQL(table string, columns []string, data []X) (string, []interface{}) {
	placeholders := []string{}
	binds := []interface{}{}

	for _, v := range data {
		bindvars := []string{}

		for _, c := range columns {
			binds = append(binds, v[c])
			bindvars = append(bindvars, "?")
		}

		placeholders = append(placeholders, fmt.Sprintf("(%s)", strings.Join(bindvars, ",")))
	}

	sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", table, strings.Join(columns, ","), strings.Join(placeholders, ","))

	return sql, binds
}

// UpdateSQL build update sql
func UpdateSQL(sql string, args ...interface{}) (string, []interface{}) {
	sets := []string{}
	binds := []interface{}{}

	for k, v := range args[0].(X) {
		if expr, ok := v.(*expr); ok {
			sets = append(sets, fmt.Sprintf("%s = %s", k, expr.expr))
			binds = append(binds, expr.args...)
		} else {
			sets = append(sets, fmt.Sprintf("%s = ?", k))
			binds = append(binds, v)
		}
	}

	sql = strings.Replace(sql, "?", strings.Join(sets, ", "), 1)
	binds = append(binds, args[1:]...)

	return sql, binds
}

// Expr expression, eg: yiigo.Expr("price * ? + ?", 2, 100)
func Expr(expression string, args ...interface{}) *expr {
	return &expr{expr: expression, args: args}
}
<|endoftext|>


<commit_before>package ui

import (
	"fmt"
	"regexp"
	"strconv"
	"unicode"

	"github.com/atotto/clipboard"
	"github.com/tcolar/goed/core"
)

func (v *View) ClearSelections() {
	v.selections = []core.Selection{}
}

// Text returns the text contained in the selection of the given view
// Note: **NOT** a rectangle but from pt1 to pt2
func (v *View) SelectionText(s *core.Selection) [][]rune {
	cf := s.ColFrom
	ct := s.ColTo
	lt := s.LineTo
	lf := s.LineFrom
	if lf == lt {
		return *v.backend.Slice(lf, cf, lt, ct).Text()
	}
	// first line
	text := *v.backend.Slice(lf, cf, lf, -1).Text()
	for l := lf + 1; l < lt; l++ {
		// middle
		text = append(text, *v.backend.Slice(l, 0, l, -1).Text()...)
	}
	// last line
	text = append(text, *v.backend.Slice(lt, 0, lt, ct).Text()...)
	return text
}

// Selected returns whether the text at line, col is current selected
// also returns the matching selection, if any.
func (v *View) Selected(col, line int) (bool, *core.Selection) {
	for _, s := range v.selections {
		if line < s.LineFrom || line > s.LineTo {
			continue
		} else if line > s.LineFrom && line < s.LineTo {
			return true, &s
		} else if s.LineFrom == s.LineTo {
			return col >= s.ColFrom && col <= s.ColTo, &s
		} else if line == s.LineFrom && col >= s.ColFrom {
			return true, &s
		} else if line == s.LineTo && col <= s.ColTo {
			return true, &s
		}
	}
	return false, nil
}

func (v *View) SelectionCopy(s *core.Selection) {
	t := v.SelectionText(s)
	core.Ed.SetStatus(fmt.Sprintf("Copied %d lines to clipboard.", len(t)))
	clipboard.WriteAll(core.RunesToString(t))
}

func (v *View) SelectionDelete(s *core.Selection) {
	y, x := s.LineFrom-v.CurLine(), s.ColFrom-v.CurCol()
	v.Delete(s.LineFrom, s.ColFrom, s.LineTo, s.ColTo)
	v.MoveCursor(y, x)
}

func (v *View) Paste() {
	text, err := clipboard.ReadAll()
	if err != nil {
		core.Ed.SetStatusErr(err.Error())
		return
	}
	if len(v.selections) > 0 {
		v.DeleteCur()
	}
	_, y, x := v.CurChar()
	v.Insert(y, x, text)
}

var locationRegexp = regexp.MustCompile(`([^"\s(){}[\]<>,?|+=&^%#@!;':]+)(:\d+)?(:\d+)?`)

// Try to select a "location" from the given position
// a location is a path with possibly a line number and maybe a column number as well
func (v *View) ExpandSelectionPath(line, col int) *core.Selection {
	l := v.Line(v.slice, line)
	ln := string(l)
	slice := core.NewSlice(0, 0, 0, len(l), [][]rune{l})
	c := v.LineRunesTo(slice, 0, col)
	matches := locationRegexp.FindAllStringIndex(ln, -1)
	var best []int
	// Find the "narrowest" match around the cursor
	for _, s := range matches {
		if s[0] <= c && s[1] >= c {
			if best == nil || s[1]-s[0] < best[1]-best[0] {
				best = s
			}
		}
	}
	if best == nil {
		return nil
	}
	return core.NewSelection(line, best[0], line, best[1]-1)
}

// Try to select the longest "word" from current position.
func (v *View) ExpandSelectionWord(line, col int) *core.Selection {
	l := v.Line(v.slice, line)
	c := v.LineRunesTo(v.slice, line, col)
	if c < 0 || c >= len(l) {
		return nil
	}
	c1, c2 := c, c
	for ; c1 >= 0 && isWordRune(l[c1]); c1-- {
	}
	c1++
	for ; c2 < len(l) && isWordRune(l[c2]); c2++ {
	}
	c2--
	if c1 >= c2 {
		return nil
	}
	return core.NewSelection(line, c1, line, c2)
}

func isWordRune(r rune) bool {
	return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_'
}

// Select the whole given line
func (v *View) SelectLine(line int) {
	s := core.NewSelection(line, 0, line, v.LineLen(v.slice, line))
	v.selections = []core.Selection{
		*s,
	}
}

// Select a word at the given location (if any)
func (v *View) SelectWord(line, col int) {
	s := v.ExpandSelectionWord(line, col)
	if s != nil {
		v.selections = []core.Selection{
			*s,
		}
	}
}

// Parses a selection into a location (file, line, col)
func (v *View) SelectionToLoc(sel *core.Selection) (loc string, line, col int) {
	sub := locationRegexp.FindAllStringSubmatch(core.RunesToString(v.SelectionText(sel)), 1)
	if len(sub) == 0 {
		return
	}
	s := sub[0]
	if len(s) >= 1 {
		loc = s[1]
	}
	if len(s[2]) > 0 {
		line, _ = strconv.Atoi(s[2][1:])
	}
	if len(s[3]) > 0 {
		col, _ = strconv.Atoi(s[3][1:])
	}
	return loc, line, col
}

// Stretch a selection toward a new position
func (v *View) StretchSelection(prevl, prevc, l, c int) {
	if len(v.selections) == 0 {
		s := *core.NewSelection(prevl, prevc, l, c)
		v.selections = []core.Selection{
			s,
		}
	} else {
		s := v.selections[0]
		if s.LineTo == prevl && s.ColTo == prevc {
			s.LineTo, s.ColTo = l, c
		} else {
			s.LineFrom, s.ColFrom = l, c
		}
		s.Normalize()
		v.selections[0] = s
	}
}

// Open what's selected or under the cursor
// if newView is true then open in a new view, otherwise
// replace content of v
func (v *View) OpenSelection(newView bool) {
	ed := core.Ed.(*Editor)
	newView = newView || v.Dirty()
	if len(v.selections) == 0 {
		selection := v.ExpandSelectionPath(v.CurLine(), v.CurCol())
		if selection == nil {
			ed.SetStatusErr("Could not expand location from cursor location.")
			return
		}
		v.selections = []core.Selection{*selection}
	}
	loc, line, col := v.SelectionToLoc(&v.selections[0])
	line-- // we use 0 indexes in views
	col--
	isDir := false
	loc, isDir = core.LookupLocation(v.WorkDir(), loc)
	vv := ed.ViewByLoc(loc)
	if vv != nil {
		// Already open
		ed.ActivateView(vv.(*View), line, col)
		return
	}
	v2 := ed.NewView(loc)
	if _, err := ed.Open(loc, v2, v.WorkDir()); err != nil {
		ed.SetStatusErr(err.Error())
		return
	}
	if newView {
		if isDir {
			ed.InsertView(v2, v, 0.5)
		} else {
			ed.InsertViewSmart(v2)
		}
	} else {
		ed.ReplaceView(v, v2)
	}
	ed.ActivateView(v2, line, col)
}
<commit_msg>Fixed selection overwritting bug<commit_after>package ui

import (
	"fmt"
	"regexp"
	"strconv"
	"unicode"

	"github.com/atotto/clipboard"
	"github.com/tcolar/goed/core"
)

func (v *View) ClearSelections() {
	v.selections = []core.Selection{}
}

// Text returns the text contained in the selection of the given view
// Note: **NOT** a rectangle but from pt1 to pt2
func (v *View) SelectionText(s *core.Selection) [][]rune {
	cf := s.ColFrom
	ct := s.ColTo
	lt := s.LineTo
	lf := s.LineFrom
	if lf == lt {
		return *v.backend.Slice(lf, cf, lt, ct).Text()
	}
	// first line
	text := *v.backend.Slice(lf, cf, lf, -1).Text()
	for l := lf + 1; l < lt; l++ {
		// middle
		text = append(text, *v.backend.Slice(l, 0, l, -1).Text()...)
	}
	// last line
	text = append(text, *v.backend.Slice(lt, 0, lt, ct).Text()...)
	return text
}

// Selected returns whether the text at line, col is current selected
// also returns the matching selection, if any.
func (v *View) Selected(col, line int) (bool, *core.Selection) {
	for _, s := range v.selections {
		if line < s.LineFrom || line > s.LineTo {
			continue
		} else if line > s.LineFrom && line < s.LineTo {
			return true, &s
		} else if s.LineFrom == s.LineTo {
			return col >= s.ColFrom && col <= s.ColTo, &s
		} else if line == s.LineFrom && col >= s.ColFrom {
			return true, &s
		} else if line == s.LineTo && col <= s.ColTo {
			return true, &s
		}
	}
	return false, nil
}

func (v *View) SelectionCopy(s *core.Selection) {
	t := v.SelectionText(s)
	core.Ed.SetStatus(fmt.Sprintf("Copied %d lines to clipboard.", len(t)))
	clipboard.WriteAll(core.RunesToString(t))
}

func (v *View) SelectionDelete(s *core.Selection) {
	v.Delete(s.LineFrom, s.ColFrom, s.LineTo, s.ColTo)
}

func (v *View) Paste() {
	text, err := clipboard.ReadAll()
	if err != nil {
		core.Ed.SetStatusErr(err.Error())
		return
	}
	if len(v.selections) > 0 {
		v.DeleteCur()
	}
	_, y, x := v.CurChar()
	v.Insert(y, x, text)
}

var locationRegexp = regexp.MustCompile(`([^"\s(){}[\]<>,?|+=&^%#@!;':]+)(:\d+)?(:\d+)?`)

// Try to select a "location" from the given position
// a location is a path with possibly a line number and maybe a column number as well
func (v *View) ExpandSelectionPath(line, col int) *core.Selection {
	l := v.Line(v.slice, line)
	ln := string(l)
	slice := core.NewSlice(0, 0, 0, len(l), [][]rune{l})
	c := v.LineRunesTo(slice, 0, col)
	matches := locationRegexp.FindAllStringIndex(ln, -1)
	var best []int
	// Find the "narrowest" match around the cursor
	for _, s := range matches {
		if s[0] <= c && s[1] >= c {
			if best == nil || s[1]-s[0] < best[1]-best[0] {
				best = s
			}
		}
	}
	if best == nil {
		return nil
	}
	return core.NewSelection(line, best[0], line, best[1]-1)
}

// Try to select the longest "word" from current position.
func (v *View) ExpandSelectionWord(line, col int) *core.Selection {
	l := v.Line(v.slice, line)
	c := v.LineRunesTo(v.slice, line, col)
	if c < 0 || c >= len(l) {
		return nil
	}
	c1, c2 := c, c
	for ; c1 >= 0 && isWordRune(l[c1]); c1-- {
	}
	c1++
	for ; c2 < len(l) && isWordRune(l[c2]); c2++ {
	}
	c2--
	if c1 >= c2 {
		return nil
	}
	return core.NewSelection(line, c1, line, c2)
}

func isWordRune(r rune) bool {
	return unicode.IsLetter(r) || unicode.IsDigit(r) || r == '_'
}

// Select the whole given line
func (v *View) SelectLine(line int) {
	s := core.NewSelection(line, 0, line, v.LineLen(v.slice, line))
	v.selections = []core.Selection{
		*s,
	}
}

// Select a word at the given location (if any)
func (v *View) SelectWord(line, col int) {
	s := v.ExpandSelectionWord(line, col)
	if s != nil {
		v.selections = []core.Selection{
			*s,
		}
	}
}

// Parses a selection into a location (file, line, col)
func (v *View) SelectionToLoc(sel *core.Selection) (loc string, line, col int) {
	sub := locationRegexp.FindAllStringSubmatch(core.RunesToString(v.SelectionText(sel)), 1)
	if len(sub) == 0 {
		return
	}
	s := sub[0]
	if len(s) >= 1 {
		loc = s[1]
	}
	if len(s[2]) > 0 {
		line, _ = strconv.Atoi(s[2][1:])
	}
	if len(s[3]) > 0 {
		col, _ = strconv.Atoi(s[3][1:])
	}
	return loc, line, col
}

// Stretch a selection toward a new position
func (v *View) StretchSelection(prevl, prevc, l, c int) {
	if len(v.selections) == 0 {
		s := *core.NewSelection(prevl, prevc, l, c)
		v.selections = []core.Selection{
			s,
		}
	} else {
		s := v.selections[0]
		if s.LineTo == prevl && s.ColTo == prevc {
			s.LineTo, s.ColTo = l, c
		} else {
			s.LineFrom, s.ColFrom = l, c
		}
		s.Normalize()
		v.selections[0] = s
	}
}

// Open what's selected or under the cursor
// if newView is true then open in a new view, otherwise
// replace content of v
func (v *View) OpenSelection(newView bool) {
	ed := core.Ed.(*Editor)
	newView = newView || v.Dirty()
	if len(v.selections) == 0 {
		selection := v.ExpandSelectionPath(v.CurLine(), v.CurCol())
		if selection == nil {
			ed.SetStatusErr("Could not expand location from cursor location.")
			return
		}
		v.selections = []core.Selection{*selection}
	}
	loc, line, col := v.SelectionToLoc(&v.selections[0])
	line-- // we use 0 indexes in views
	col--
	isDir := false
	loc, isDir = core.LookupLocation(v.WorkDir(), loc)
	vv := ed.ViewByLoc(loc)
	if vv != nil {
		// Already open
		ed.ActivateView(vv.(*View), line, col)
		return
	}
	v2 := ed.NewView(loc)
	if _, err := ed.Open(loc, v2, v.WorkDir()); err != nil {
		ed.SetStatusErr(err.Error())
		return
	}
	if newView {
		if isDir {
			ed.InsertView(v2, v, 0.5)
		} else {
			ed.InsertViewSmart(v2)
		}
	} else {
		ed.ReplaceView(v, v2)
	}
	ed.ActivateView(v2, line, col)
}
<|endoftext|>


<commit_before>// Copyright 2018 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package driver

import (
	"fmt"
	"io"
	"strconv"

	"github.com/pingcap/errors"
	"github.com/pingcap/parser/ast"
	"github.com/pingcap/parser/format"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/tidb/types"
	"github.com/pingcap/tidb/util/hack"
)

// The purpose of driver package is to decompose the dependency of the parser and
// types package.
// It provides the NewValueExpr function for the ast package, so the ast package
// do not depends on the concrete definition of `types.Datum`, thus get rid of
// the dependency of the types package.
// The parser package depends on the ast package, but not the types package.
// The whole relationship:
// ast imports []
// tidb/types imports [parser/types]
// parser imports [ast, parser/types]
// driver imports [ast, tidb/types]
// tidb imports [parser, driver]

func init() {
	ast.NewValueExpr = newValueExpr
	ast.NewParamMarkerExpr = newParamMarkerExpr
	ast.NewDecimal = func(str string) (interface{}, error) {
		dec := new(types.MyDecimal)
		err := dec.FromString(hack.Slice(str))
		return dec, err
	}
	ast.NewHexLiteral = func(str string) (interface{}, error) {
		h, err := types.NewHexLiteral(str)
		return h, err
	}
	ast.NewBitLiteral = func(str string) (interface{}, error) {
		b, err := types.NewBitLiteral(str)
		return b, err
	}
}

var (
	_ ast.ParamMarkerExpr = &ParamMarkerExpr{}
	_ ast.ValueExpr       = &ValueExpr{}
)

// ValueExpr is the simple value expression.
type ValueExpr struct {
	ast.TexprNode
	types.Datum
	projectionOffset int
}

// Restore implements Node interface.
func (n *ValueExpr) Restore(ctx *format.RestoreCtx) error {
	switch n.Kind() {
	case types.KindNull:
		ctx.WriteKeyWord("NULL")
	case types.KindInt64:
		if n.Type.Flag&mysql.IsBooleanFlag != 0 {
			if n.GetInt64() > 0 {
				ctx.WriteKeyWord("TRUE")
			} else {
				ctx.WriteKeyWord("FALSE")
			}
		} else {
			ctx.WritePlain(strconv.FormatInt(n.GetInt64(), 10))
		}
	case types.KindUint64:
		ctx.WritePlain(strconv.FormatUint(n.GetUint64(), 10))
	case types.KindFloat32:
		ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32))
	case types.KindFloat64:
		ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64))
	case types.KindString, types.KindBytes:
		ctx.WriteString(n.GetString())
	case types.KindMysqlDecimal:
		ctx.WritePlain(n.GetMysqlDecimal().String())
	case types.KindBinaryLiteral:
		if n.Type.Flag&mysql.UnsignedFlag != 0 {
			ctx.WritePlainf("x'%x'", n.GetBytes())
		} else {
			ctx.WritePlain(n.GetBinaryLiteral().ToBitLiteralString(true))
		}
	case types.KindMysqlDuration, types.KindMysqlEnum,
		types.KindMysqlBit, types.KindMysqlSet, types.KindMysqlTime,
		types.KindInterface, types.KindMinNotNull, types.KindMaxValue,
		types.KindRaw, types.KindMysqlJSON:
		// TODO implement Restore function
		return errors.New("Not implemented")
	default:
		return errors.New("can't format to string")
	}
	return nil
}

// GetDatumString implements the ast.ValueExpr interface.
func (n *ValueExpr) GetDatumString() string {
	return n.GetString()
}

// Format the ExprNode into a Writer.
func (n *ValueExpr) Format(w io.Writer) {
	var s string
	switch n.Kind() {
	case types.KindNull:
		s = "NULL"
	case types.KindInt64:
		if n.Type.Flag&mysql.IsBooleanFlag != 0 {
			if n.GetInt64() > 0 {
				s = "TRUE"
			} else {
				s = "FALSE"
			}
		} else {
			s = strconv.FormatInt(n.GetInt64(), 10)
		}
	case types.KindUint64:
		s = strconv.FormatUint(n.GetUint64(), 10)
	case types.KindFloat32:
		s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32)
	case types.KindFloat64:
		s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64)
	case types.KindString, types.KindBytes:
		s = strconv.Quote(n.GetString())
	case types.KindMysqlDecimal:
		s = n.GetMysqlDecimal().String()
	case types.KindBinaryLiteral:
		if n.Type.Flag&mysql.UnsignedFlag != 0 {
			s = fmt.Sprintf("x'%x'", n.GetBytes())
		} else {
			s = n.GetBinaryLiteral().ToBitLiteralString(true)
		}
	default:
		panic("Can't format to string")
	}
	fmt.Fprint(w, s)
}

// newValueExpr creates a ValueExpr with value, and sets default field type.
func newValueExpr(value interface{}) ast.ValueExpr {
	if ve, ok := value.(*ValueExpr); ok {
		return ve
	}
	ve := &ValueExpr{}
	ve.SetValue(value)
	types.DefaultTypeForValue(value, &ve.Type)
	ve.projectionOffset = -1
	return ve
}

// SetProjectionOffset sets ValueExpr.projectionOffset for logical plan builder.
func (n *ValueExpr) SetProjectionOffset(offset int) {
	n.projectionOffset = offset
}

// GetProjectionOffset returns ValueExpr.projectionOffset.
func (n *ValueExpr) GetProjectionOffset() int {
	return n.projectionOffset
}

// Accept implements Node interface.
func (n *ValueExpr) Accept(v ast.Visitor) (ast.Node, bool) {
	newNode, skipChildren := v.Enter(n)
	if skipChildren {
		return v.Leave(newNode)
	}
	n = newNode.(*ValueExpr)
	return v.Leave(n)
}

// ParamMarkerExpr expression holds a place for another expression.
// Used in parsing prepare statement.
type ParamMarkerExpr struct {
	ValueExpr
	Offset int
	Order  int
}

// Restore implements Node interface.
func (n *ParamMarkerExpr) Restore(ctx *format.RestoreCtx) error {
	ctx.WritePlain("?")
	return nil
}

func newParamMarkerExpr(offset int) ast.ParamMarkerExpr {
	return &ParamMarkerExpr{
		Offset: offset,
	}
}

// Format the ExprNode into a Writer.
func (n *ParamMarkerExpr) Format(w io.Writer) {
	panic("Not implemented")
}

// Accept implements Node Accept interface.
func (n *ParamMarkerExpr) Accept(v ast.Visitor) (ast.Node, bool) {
	newNode, skipChildren := v.Enter(n)
	if skipChildren {
		return v.Leave(newNode)
	}
	n = newNode.(*ParamMarkerExpr)
	return v.Leave(n)
}

// SetOrder implements the ast.ParamMarkerExpr interface.
func (n *ParamMarkerExpr) SetOrder(order int) {
	n.Order = order
}
<commit_msg>value_expr: add charset value for string expr (#9302)<commit_after>// Copyright 2018 PingCAP, Inc.
//
// 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,
// See the License for the specific language governing permissions and
// limitations under the License.

package driver

import (
	"fmt"
	"io"
	"strconv"

	"github.com/pingcap/errors"
	"github.com/pingcap/parser/ast"
	"github.com/pingcap/parser/format"
	"github.com/pingcap/parser/mysql"
	"github.com/pingcap/tidb/types"
	"github.com/pingcap/tidb/util/hack"
)

// The purpose of driver package is to decompose the dependency of the parser and
// types package.
// It provides the NewValueExpr function for the ast package, so the ast package
// do not depends on the concrete definition of `types.Datum`, thus get rid of
// the dependency of the types package.
// The parser package depends on the ast package, but not the types package.
// The whole relationship:
// ast imports []
// tidb/types imports [parser/types]
// parser imports [ast, parser/types]
// driver imports [ast, tidb/types]
// tidb imports [parser, driver]

func init() {
	ast.NewValueExpr = newValueExpr
	ast.NewParamMarkerExpr = newParamMarkerExpr
	ast.NewDecimal = func(str string) (interface{}, error) {
		dec := new(types.MyDecimal)
		err := dec.FromString(hack.Slice(str))
		return dec, err
	}
	ast.NewHexLiteral = func(str string) (interface{}, error) {
		h, err := types.NewHexLiteral(str)
		return h, err
	}
	ast.NewBitLiteral = func(str string) (interface{}, error) {
		b, err := types.NewBitLiteral(str)
		return b, err
	}
}

var (
	_ ast.ParamMarkerExpr = &ParamMarkerExpr{}
	_ ast.ValueExpr       = &ValueExpr{}
)

// ValueExpr is the simple value expression.
type ValueExpr struct {
	ast.TexprNode
	types.Datum
	projectionOffset int
}

// Restore implements Node interface.
func (n *ValueExpr) Restore(ctx *format.RestoreCtx) error {
	switch n.Kind() {
	case types.KindNull:
		ctx.WriteKeyWord("NULL")
	case types.KindInt64:
		if n.Type.Flag&mysql.IsBooleanFlag != 0 {
			if n.GetInt64() > 0 {
				ctx.WriteKeyWord("TRUE")
			} else {
				ctx.WriteKeyWord("FALSE")
			}
		} else {
			ctx.WritePlain(strconv.FormatInt(n.GetInt64(), 10))
		}
	case types.KindUint64:
		ctx.WritePlain(strconv.FormatUint(n.GetUint64(), 10))
	case types.KindFloat32:
		ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32))
	case types.KindFloat64:
		ctx.WritePlain(strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64))
	case types.KindString:
		if n.Type.Charset != "" && n.Type.Charset != mysql.DefaultCharset {
			ctx.WritePlain("_")
			ctx.WriteKeyWord(n.Type.Charset)
		}
		ctx.WriteString(n.GetString())
	case types.KindBytes:
		ctx.WriteString(n.GetString())
	case types.KindMysqlDecimal:
		ctx.WritePlain(n.GetMysqlDecimal().String())
	case types.KindBinaryLiteral:
		if n.Type.Flag&mysql.UnsignedFlag != 0 {
			ctx.WritePlainf("x'%x'", n.GetBytes())
		} else {
			ctx.WritePlain(n.GetBinaryLiteral().ToBitLiteralString(true))
		}
	case types.KindMysqlDuration, types.KindMysqlEnum,
		types.KindMysqlBit, types.KindMysqlSet, types.KindMysqlTime,
		types.KindInterface, types.KindMinNotNull, types.KindMaxValue,
		types.KindRaw, types.KindMysqlJSON:
		// TODO implement Restore function
		return errors.New("Not implemented")
	default:
		return errors.New("can't format to string")
	}
	return nil
}

// GetDatumString implements the ast.ValueExpr interface.
func (n *ValueExpr) GetDatumString() string {
	return n.GetString()
}

// Format the ExprNode into a Writer.
func (n *ValueExpr) Format(w io.Writer) {
	var s string
	switch n.Kind() {
	case types.KindNull:
		s = "NULL"
	case types.KindInt64:
		if n.Type.Flag&mysql.IsBooleanFlag != 0 {
			if n.GetInt64() > 0 {
				s = "TRUE"
			} else {
				s = "FALSE"
			}
		} else {
			s = strconv.FormatInt(n.GetInt64(), 10)
		}
	case types.KindUint64:
		s = strconv.FormatUint(n.GetUint64(), 10)
	case types.KindFloat32:
		s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 32)
	case types.KindFloat64:
		s = strconv.FormatFloat(n.GetFloat64(), 'e', -1, 64)
	case types.KindString, types.KindBytes:
		s = strconv.Quote(n.GetString())
	case types.KindMysqlDecimal:
		s = n.GetMysqlDecimal().String()
	case types.KindBinaryLiteral:
		if n.Type.Flag&mysql.UnsignedFlag != 0 {
			s = fmt.Sprintf("x'%x'", n.GetBytes())
		} else {
			s = n.GetBinaryLiteral().ToBitLiteralString(true)
		}
	default:
		panic("Can't format to string")
	}
	fmt.Fprint(w, s)
}

// newValueExpr creates a ValueExpr with value, and sets default field type.
func newValueExpr(value interface{}) ast.ValueExpr {
	if ve, ok := value.(*ValueExpr); ok {
		return ve
	}
	ve := &ValueExpr{}
	ve.SetValue(value)
	types.DefaultTypeForValue(value, &ve.Type)
	ve.projectionOffset = -1
	return ve
}

// SetProjectionOffset sets ValueExpr.projectionOffset for logical plan builder.
func (n *ValueExpr) SetProjectionOffset(offset int) {
	n.projectionOffset = offset
}

// GetProjectionOffset returns ValueExpr.projectionOffset.
func (n *ValueExpr) GetProjectionOffset() int {
	return n.projectionOffset
}

// Accept implements Node interface.
func (n *ValueExpr) Accept(v ast.Visitor) (ast.Node, bool) {
	newNode, skipChildren := v.Enter(n)
	if skipChildren {
		return v.Leave(newNode)
	}
	n = newNode.(*ValueExpr)
	return v.Leave(n)
}

// ParamMarkerExpr expression holds a place for another expression.
// Used in parsing prepare statement.
type ParamMarkerExpr struct {
	ValueExpr
	Offset int
	Order  int
}

// Restore implements Node interface.
func (n *ParamMarkerExpr) Restore(ctx *format.RestoreCtx) error {
	ctx.WritePlain("?")
	return nil
}

func newParamMarkerExpr(offset int) ast.ParamMarkerExpr {
	return &ParamMarkerExpr{
		Offset: offset,
	}
}

// Format the ExprNode into a Writer.
func (n *ParamMarkerExpr) Format(w io.Writer) {
	panic("Not implemented")
}

// Accept implements Node Accept interface.
func (n *ParamMarkerExpr) Accept(v ast.Visitor) (ast.Node, bool) {
	newNode, skipChildren := v.Enter(n)
	if skipChildren {
		return v.Leave(newNode)
	}
	n = newNode.(*ParamMarkerExpr)
	return v.Leave(n)
}

// SetOrder implements the ast.ParamMarkerExpr interface.
func (n *ParamMarkerExpr) SetOrder(order int) {
	n.Order = order
}
<|endoftext|>


<commit_before>package wx

import (
	"fmt"
	"github.com/hillbig/fixvec"
	"github.com/hillbig/rsdic"
	"github.com/hillbig/vecstring"
	"sort"
)

type builderImpl struct {
	keys map[string]struct{}
}

func (wxb *builderImpl) Add(key string) {
	wxb.keys[key] = struct{}{}
}

type strs struct {
	str2id map[string]uint64
	ids    []uint64
}

func newStrs() *strs {
	return &strs{
		str2id: make(map[string]uint64),
		ids:    make([]uint64, 0),
	}
}

func (s *strs) add(str string) {
	id, ok := s.str2id[str]
	if !ok {
		id = uint64(len(s.str2id))
		s.str2id[str] = id
	}
	s.ids = append(s.ids, id)
}

func (wxb builderImpl) Build() WX {
	return wxb.build(false)
}

func (wxb builderImpl) Num() uint64 {
	return uint64(len(wxb.keys))
}

func (wxb builderImpl) TotalByteNum() uint64 {
	totalByteNum := uint64(0)
	for key, _ := range wxb.keys {
		totalByteNum += uint64(len(key))
	}
	return totalByteNum
}

func (wxb *builderImpl) build(isRawLead bool) WX {
	keys := make([]string, 0)
	for key, _ := range wxb.keys {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	branches := vecstring.NewForWX()
	terminals := rsdic.New()
	leadingIsZeroOrOnes := rsdic.New()
	leadingIsOnes := rsdic.New()
	leadingOnes := make([]byte, 0)
	leadingStrs := newStrs()

	q := newNodeQueue(0)
	if len(keys) > 0 {
		q.push(&node{0, len(keys), 0})
	}
	for q.num > 0 {
		n := q.pop()
		beg, end, depth := n.beg, n.end, n.depth
		bdepth := branchDepth(keys[beg], keys[end-1], depth)
		leading := keys[beg][depth:bdepth]
		if len(leading) <= 1 {
			leadingIsZeroOrOnes.PushBack(true)
			if len(leading) == 0 {
				leadingIsOnes.PushBack(false)
			} else {
				// len(leading) == 1
				leadingIsOnes.PushBack(true)
				leadingOnes = append(leadingOnes, leading[0])
			}
		} else {
			leadingIsZeroOrOnes.PushBack(false)
			leadingStrs.add(leading)
		}
		if len(keys[beg]) == bdepth {
			// keys[beg] is internal node
			terminals.PushBack(true)
			beg++
			if beg == end {
				branches.PushBack("")
				continue
			}
		} else {
			terminals.PushBack(false)
		}

		nextBeg := beg
		c := keys[nextBeg][bdepth]
		branch := make([]byte, 0)
		// QUEUEUEU
		for i := beg + 1; i <= end; i++ {
			if i == end || c != keys[i][bdepth] {
				branch = append(branch, c)
				q.push(&node{nextBeg, i, bdepth + 1})
				if i == end {
					break
				}
				nextBeg = i
				c = keys[i][bdepth]
			}
		}
		branches.PushBack(string(branch))
	}

	// build trie for leadings recursively
	/*
		if !isRawLead {
			leadBuilder := builderImpl{make(map[string]struct{})}
			for key, _ := range wxtmp.leadingStrs.str2id {
				leadBuilder.Add(key)
			}
			return &wxImpl{
				branches:  wxtmp.branches.Build(),
				terminals: wxtmp.terminals.Build(),
				leadings:  leadBuilder.Build(),
				num:       uint64(len(keys)),
			}
		} else {
	*/
	id2key := make([]string, len(leadingStrs.str2id))
	for key, id := range leadingStrs.str2id {
		id2key[id] = key
	}
	leadings := vecstring.New()
	for _, key := range id2key {
		leadings.PushBack(key)
	}
	return &wxImpl{
		branches:            branches,
		terminals:           terminals,
		leadingIDs:          fixvec.NewFromArray(leadingStrs.ids),
		leadings:            leadings,
		leadingIsZeroOrOnes: leadingIsZeroOrOnes,
		leadingIsOnes:       leadingIsOnes,
		leadingOnes:         leadingOnes,
		num:                 uint64(len(keys)),
	}
}

func printString(s string) {
	for i := 0; i < len(s); i++ {
		fmt.Printf("%x ", s[i])
	}
	fmt.Printf("\n")
}

func branchDepth(s string, u string, depth int) int {
	for i := depth; ; i++ {
		if len(s) == i || len(u) == i { // since keys are sorted, only len(s) == i should be valid. But added len(u) in case.
			return i
		}
		if s[i] != u[i] {
			return i
		}
	}
}
<commit_msg>remove comments<commit_after>package wx

import (
	"fmt"
	"github.com/hillbig/fixvec"
	"github.com/hillbig/rsdic"
	"github.com/hillbig/vecstring"
	"sort"
)

type builderImpl struct {
	keys map[string]struct{}
}

func (wxb *builderImpl) Add(key string) {
	wxb.keys[key] = struct{}{}
}

type strs struct {
	str2id map[string]uint64
	ids    []uint64
}

func newStrs() *strs {
	return &strs{
		str2id: make(map[string]uint64),
		ids:    make([]uint64, 0),
	}
}

func (s *strs) add(str string) {
	id, ok := s.str2id[str]
	if !ok {
		id = uint64(len(s.str2id))
		s.str2id[str] = id
	}
	s.ids = append(s.ids, id)
}

func (wxb builderImpl) Build() WX {
	return wxb.build(false)
}

func (wxb builderImpl) Num() uint64 {
	return uint64(len(wxb.keys))
}

func (wxb builderImpl) TotalByteNum() uint64 {
	totalByteNum := uint64(0)
	for key, _ := range wxb.keys {
		totalByteNum += uint64(len(key))
	}
	return totalByteNum
}

func (wxb *builderImpl) build(isRawLead bool) WX {
	keys := make([]string, 0)
	for key, _ := range wxb.keys {
		keys = append(keys, key)
	}
	sort.Strings(keys)
	branches := vecstring.NewForWX()
	terminals := rsdic.New()
	leadingIsZeroOrOnes := rsdic.New()
	leadingIsOnes := rsdic.New()
	leadingOnes := make([]byte, 0)
	leadingStrs := newStrs()

	q := newNodeQueue(0)
	if len(keys) > 0 {
		q.push(&node{0, len(keys), 0})
	}
	for q.num > 0 {
		n := q.pop()
		beg, end, depth := n.beg, n.end, n.depth
		bdepth := branchDepth(keys[beg], keys[end-1], depth)
		leading := keys[beg][depth:bdepth]
		if len(leading) <= 1 {
			leadingIsZeroOrOnes.PushBack(true)
			if len(leading) == 0 {
				leadingIsOnes.PushBack(false)
			} else {
				// len(leading) == 1
				leadingIsOnes.PushBack(true)
				leadingOnes = append(leadingOnes, leading[0])
			}
		} else {
			leadingIsZeroOrOnes.PushBack(false)
			leadingStrs.add(leading)
		}
		if len(keys[beg]) == bdepth {
			// keys[beg] is internal node
			terminals.PushBack(true)
			beg++
			if beg == end {
				branches.PushBack("")
				continue
			}
		} else {
			terminals.PushBack(false)
		}

		nextBeg := beg
		c := keys[nextBeg][bdepth]
		branch := make([]byte, 0)
		for i := beg + 1; i <= end; i++ {
			if i == end || c != keys[i][bdepth] {
				branch = append(branch, c)
				q.push(&node{nextBeg, i, bdepth + 1})
				if i == end {
					break
				}
				nextBeg = i
				c = keys[i][bdepth]
			}
		}
		branches.PushBack(string(branch))
	}
	id2key := make([]string, len(leadingStrs.str2id))
	for key, id := range leadingStrs.str2id {
		id2key[id] = key
	}
	leadings := vecstring.New()
	for _, key := range id2key {
		leadings.PushBack(key)
	}
	return &wxImpl{
		branches:            branches,
		terminals:           terminals,
		leadingIDs:          fixvec.NewFromArray(leadingStrs.ids),
		leadings:            leadings,
		leadingIsZeroOrOnes: leadingIsZeroOrOnes,
		leadingIsOnes:       leadingIsOnes,
		leadingOnes:         leadingOnes,
		num:                 uint64(len(keys)),
	}
}

func printString(s string) {
	for i := 0; i < len(s); i++ {
		fmt.Printf("%x ", s[i])
	}
	fmt.Printf("\n")
}

func branchDepth(s string, u string, depth int) int {
	for i := depth; ; i++ {
		if len(s) == i || len(u) == i { // since keys are sorted, only len(s) == i should be valid. But added len(u) in case.
			return i
		}
		if s[i] != u[i] {
			return i
		}
	}
}
<|endoftext|>


<commit_before>// Package accesslog logs HTTP requests.
package accesslog

import (
	"log"
	"net/http"
	"strings"
	"time"
)

// Handler wraps an existing http.Handler and logs any requests
// routed along to the handler, in the following format:
//
// 	127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
//
// Output is logged to the dest parameter. If dest is nil, the default
// logger of the log package is used.
func Handler(existing http.Handler, dest Logger) http.Handler {
	return handler{handler: existing, dest: dest}
}

// Types implementing the Logger interface can be used as destinations
// for access log messages. The Printf method must be safe for concurrent
// use among multiple goroutines.
type Logger interface {
	Printf(format string, v ...interface{})
}

type handler struct {
	handler http.Handler
	dest    Logger
}

func (h handler) logf(format string, v ...interface{}) {
	if h.dest != nil {
		h.dest.Printf(format, v...)
	} else {
		log.Printf(format, v...)
	}
}

type responseWriter struct {
	http.ResponseWriter
	status, n int
}

func (w *responseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *responseWriter) Write(b []byte) (int, error) {
	n, err := w.ResponseWriter.Write(b)
	w.n += n
	return n, err
}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// From https://en.wikipedia.org/wiki/Common_Log_Format
	//
	// 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
	const format = "%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\""
	const layout = "2/Jan/2006:15:04:05 -0700"

	userAgent := "-"
	if agent := r.UserAgent(); agent != "" {
		userAgent = agent
	}
	referer := "-"
	if ref := r.Referer(); ref != "" {
		referer = ref
	}

	shim := responseWriter{ResponseWriter: w}

	//start := time.Now()
	h.handler.ServeHTTP(&shim, r)
	end := time.Now()

	h.logf(format,
		strings.Split(r.RemoteAddr, ":")[0],
		end.Format(layout),
		r.Method,
		r.URL.RequestURI(),
		r.Proto,
		shim.status,
		shim.n,
		referer,
		userAgent)
}
<commit_msg>Log request URI before we modify it.<commit_after>// Package accesslog logs HTTP requests.
package accesslog

import (
	"log"
	"net/http"
	"strings"
	"time"
)

// Handler wraps an existing http.Handler and logs any requests
// routed along to the handler, in the following format:
//
// 	127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
//
// Output is logged to the dest parameter. If dest is nil, the default
// logger of the log package is used.
func Handler(existing http.Handler, dest Logger) http.Handler {
	return handler{handler: existing, dest: dest}
}

// Types implementing the Logger interface can be used as destinations
// for access log messages. The Printf method must be safe for concurrent
// use among multiple goroutines.
type Logger interface {
	Printf(format string, v ...interface{})
}

type handler struct {
	handler http.Handler
	dest    Logger
}

func (h handler) logf(format string, v ...interface{}) {
	if h.dest != nil {
		h.dest.Printf(format, v...)
	} else {
		log.Printf(format, v...)
	}
}

type responseWriter struct {
	http.ResponseWriter
	status, n int
}

func (w *responseWriter) WriteHeader(status int) {
	w.status = status
	w.ResponseWriter.WriteHeader(status)
}

func (w *responseWriter) Write(b []byte) (int, error) {
	n, err := w.ResponseWriter.Write(b)
	w.n += n
	return n, err
}

func (h handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// From https://en.wikipedia.org/wiki/Common_Log_Format
	//
	// 127.0.0.1 user-identifier frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326
	const format = "%s - - [%s] \"%s %s %s\" %d %d \"%s\" \"%s\""
	const layout = "2/Jan/2006:15:04:05 -0700"

	uri := r.URL.RequestURI()
	userAgent := "-"
	if agent := r.UserAgent(); agent != "" {
		userAgent = agent
	}
	referer := "-"
	if ref := r.Referer(); ref != "" {
		referer = ref
	}

	shim := responseWriter{ResponseWriter: w}

	//start := time.Now()
	h.handler.ServeHTTP(&shim, r)
	end := time.Now()

	h.logf(format,
		strings.Split(r.RemoteAddr, ":")[0],
		end.Format(layout),
		r.Method,
		uri,
		r.Proto,
		shim.status,
		shim.n,
		referer,
		userAgent)
}
<|endoftext|>


<commit_before>package saf

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

const (
	lineURL    = "http://www.safaricom.com/bundles/js/get.jsp"
	bundlesURL = "http://www.safaricom.com/bundles/GetSubDetails"
)

type Bundles struct {
	Line    string
	AccType string
	Bundles string
	Airtime float64
}

func GetBundles() (*Bundles, error) {
	l, err := line()
	if err != nil {
		return nil, fmt.Errorf("Unable to get line: %v", err)
	}
	resp, err := http.Get(bundlesURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	dat, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	b, err := ParseBundles(string(dat))
	if err != nil {
		return nil, err
	}
	b.Line = l
	return b, nil
}

/*
ParseBundles parses raw bundles html to Bundles value
Example raw bundles html:

Account Types	Prepaid

Data Bundle	8056.47 MBs

Data Bundle Expiry Date 	31-Dec-2036 19:00

Airtime Balances	0.03

Airtime Expiry Date 	01-Jan-2037 00:00

Refresh

*/
func ParseBundles(rawBundles string) (*Bundles, error) {
	rows := strings.Split(rawBundles, "
")

	res := map[string]string{"Account Types": "", "Data Bundle": "", "Airtime Balances": ""}

	for _, val := range rows {
		if !strings.Contains(val, "
") {
			continue
		}
		var title string
		for key := range res {
			if strings.Contains(val, key) {
				title = key
			}
		}
		if title == "" {
			continue
		}

		if strings.Count(val, "") < 2 {
			continue
		}
		val2 := strings.Split(val, "")[2]
		val2 = strings.Replace(val2, "", "", 1)
		val2 = strings.Replace(val2, "
", "", 1)
		res[title] = val2
	}
	for _, val := range res {
		if val == "" {
			return nil, errors.New("failed to parse bundles")
		}
	}
	airtime, err := strconv.ParseFloat(res["Airtime Balances"], 64)
	if err != nil {
		return nil, errors.New("failed to parse bundles: unable to get airtime")
	}
	return &Bundles{
		AccType: res["Account Types"],
		Bundles: res["Data Bundle"],
		Airtime: airtime,
	}, nil

}

func line() (string, error) {
	resp, err := http.Get(lineURL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	dat, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(dat)), nil
}
<commit_msg>Document package code<commit_after>package saf

import (
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"strconv"
	"strings"
)

// Public http endpoints for getting required data
const (
	lineURL    = "http://www.safaricom.com/bundles/js/get.jsp"
	bundlesURL = "http://www.safaricom.com/bundles/GetSubDetails"
)

// Bundles defines the structure for bundles values returned
type Bundles struct {
	Line    string
	AccType string
	Bundles string
	Airtime float64
}

// GetBundles returns the bundles for the line in use
func GetBundles() (*Bundles, error) {
	l, err := line()
	if err != nil {
		return nil, fmt.Errorf("Unable to get line: %v", err)
	}
	resp, err := http.Get(bundlesURL)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	dat, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	b, err := ParseBundles(string(dat))
	if err != nil {
		return nil, err
	}
	b.Line = l
	return b, nil
}

/*
ParseBundles parses raw bundles html to Bundles value, especially useful in processing data sent from clients (e.g. xhr)

Example raw bundles html:

Account Types	Prepaid

Data Bundle	8056.47 MBs

Data Bundle Expiry Date 	31-Dec-2036 19:00

Airtime Balances	0.03

Airtime Expiry Date 	01-Jan-2037 00:00

Refresh

*/
func ParseBundles(rawBundles string) (*Bundles, error) {
	rows := strings.Split(rawBundles, "
")

	res := map[string]string{"Account Types": "", "Data Bundle": "", "Airtime Balances": ""}

	for _, val := range rows {
		if !strings.Contains(val, "
") {
			continue
		}
		var title string
		for key := range res {
			if strings.Contains(val, key) {
				title = key
			}
		}
		if title == "" {
			continue
		}

		if strings.Count(val, "") < 2 {
			continue
		}
		val2 := strings.Split(val, "")[2]
		val2 = strings.Replace(val2, "", "", 1)
		val2 = strings.Replace(val2, "
", "", 1)
		res[title] = val2
	}
	for _, val := range res {
		if val == "" {
			return nil, errors.New("failed to parse bundles")
		}
	}
	airtime, err := strconv.ParseFloat(res["Airtime Balances"], 64)
	if err != nil {
		return nil, errors.New("failed to parse bundles: unable to get airtime")
	}
	return &Bundles{
		AccType: res["Account Types"],
		Bundles: res["Data Bundle"],
		Airtime: airtime,
	}, nil

}

// line simply returns the line, and an error if any
func line() (string, error) {
	resp, err := http.Get(lineURL)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	dat, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return strings.TrimSpace(string(dat)), nil
}
<|endoftext|>


<commit_before>package actions

import (
	log "github.com/Sirupsen/logrus"
	"github.com/gaia-docker/tugbot/container"
	"github.com/gaia-docker/tugbot/container/mockclient"
	"github.com/samalba/dockerclient"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"k8s.io/kubernetes/staging/src/k8s.io/client-go/1.4/_vendor/golang.org/x/net/context"

	"errors"
	"sync"
	"testing"
	"time"
)

func TestRunTickerTestContainers_FailedToGetListContainers(t *testing.T) {
	touch := false
	var locker sync.Mutex
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	client := mockclient.NewMockClient()
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Run(func(args mock.Arguments) {
			locker.Lock()
			if !touch {
				touch = true
				wg1.Done()
			}
			locker.Unlock()
		}).Return([]container.Container{}, errors.New("Expected :)"))
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Second*10)
		wg2.Done()
	}()
	wg1.Wait()
	cancel()
	wg2.Wait()

	assert.True(t, touch)
	client.AssertExpectations(t)

}

func TestRunTickerTestContainers(t *testing.T) {
	touch := false
	var locker sync.Mutex
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{
			container.TugbotTest:       "true",
			container.TugbotEventTimer: "10s",
		},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "02131b95b737",
			Name:   "My Test Container",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)
	client := mockclient.NewMockClient()
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.ID(), args.Get(0).(string))
		}).Return(&c, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
			locker.Lock()
			if !touch {
				touch = true
				wg1.Done()
			}
			locker.Unlock()
		}).Return(nil)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Second*10)
		wg2.Done()
	}()
	wg1.Wait()
	cancel()
	wg2.Wait()

	assert.True(t, touch)
	client.AssertExpectations(t)
}

func TestRunTickerTestContainers_Iteration2ContainsDifferentListContainers(t *testing.T) {
	touchListContainers, touchStartContainerFrom := false, false
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{
			container.TugbotTest:       "true",
			container.TugbotEventTimer: "10s",
		},
	}
	c1 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "c1id",
			Name:   "c1",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)
	c2 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "c2id",
			Name:   "c2",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()

	// Iteration 1 - c1
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Return([]container.Container{c1}, nil).Once()
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c1.ID(), args.Get(0).(string))
		}).Return(&c1, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			name := args.Get(0).(container.Container).Name()
			log.Info("Running container ", name)
			assert.Equal(t, c1.Name(), name)
		}).Return(nil).Once()

	// Iteration 2 - c2
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Run(func(args mock.Arguments) {
			touchListContainers = true
		}).Return([]container.Container{c2}, nil)
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c2.ID(), args.Get(0).(string))
		}).Return(&c2, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			name := args.Get(0).(container.Container).Name()
			log.Info("Running container ", name)
			touchStartContainerFrom = true
			assert.Equal(t, c2.Name(), name)
			wg1.Done()
		}).Return(nil)

	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Nanosecond*1)
		wg2.Done()
	}()
	log.Info("Wating for finish running container ", c2.Name())
	wg1.Wait()
	cancel()
	log.Info("Wating for quiting ticker")
	wg2.Wait()

	assert.True(t, touchListContainers)
	assert.True(t, touchStartContainerFrom)
	client.AssertExpectations(t)
}
<commit_msg>testing added for failed to find basic container to start a new container from it;<commit_after>package actions

import (
	log "github.com/Sirupsen/logrus"
	"github.com/gaia-docker/tugbot/container"
	"github.com/gaia-docker/tugbot/container/mockclient"
	"github.com/samalba/dockerclient"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/mock"
	"k8s.io/kubernetes/staging/src/k8s.io/client-go/1.4/_vendor/golang.org/x/net/context"

	"errors"
	"sync"
	"testing"
	"time"
)

func TestRunTickerTestContainers_FailedToGetListContainers(t *testing.T) {
	touch := false
	var locker sync.Mutex
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	client := mockclient.NewMockClient()
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Run(func(args mock.Arguments) {
			locker.Lock()
			if !touch {
				touch = true
				wg1.Done()
			}
			locker.Unlock()
		}).Return([]container.Container{}, errors.New("Expected :)"))
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Second*10)
		wg2.Done()
	}()
	wg1.Wait()
	cancel()
	wg2.Wait()

	assert.True(t, touch)
	client.AssertExpectations(t)

}

func TestRunTickerTestContainers(t *testing.T) {
	touch := false
	var locker sync.Mutex
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{
			container.TugbotTest:       "true",
			container.TugbotEventTimer: "10s",
		},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "02131b95b737",
			Name:   "My Test Container",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)
	client := mockclient.NewMockClient()
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).Return([]container.Container{c}, nil)
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.ID(), args.Get(0).(string))
		}).Return(&c, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.Name(), args.Get(0).(container.Container).Name())
			locker.Lock()
			if !touch {
				touch = true
				wg1.Done()
			}
			locker.Unlock()
		}).Return(nil)
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Second*10)
		wg2.Done()
	}()
	wg1.Wait()
	cancel()
	wg2.Wait()

	assert.True(t, touch)
	client.AssertExpectations(t)
}

func TestRunTickerTestContainers_Iteration2ContainsDifferentListContainers(t *testing.T) {
	touchListContainers, touchStartContainerFrom := false, false
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{
			container.TugbotTest:       "true",
			container.TugbotEventTimer: "10s",
		},
	}
	c1 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "c1id",
			Name:   "c1",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)
	c2 := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "c2id",
			Name:   "c2",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()

	// Iteration 1 - c1
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Return([]container.Container{c1}, nil).Once()
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c1.ID(), args.Get(0).(string))
		}).Return(&c1, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			name := args.Get(0).(container.Container).Name()
			log.Info("Running container ", name)
			assert.Equal(t, c1.Name(), name)
		}).Return(nil).Once()

	// Iteration 2 - c2
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Run(func(args mock.Arguments) {
			touchListContainers = true
		}).Return([]container.Container{c2}, nil).Once()
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c2.ID(), args.Get(0).(string))
		}).Return(&c2, nil).Once()
	client.On("StartContainerFrom", mock.AnythingOfType("container.Container")).
		Run(func(args mock.Arguments) {
			name := args.Get(0).(container.Container).Name()
			log.Info("Running container ", name)
			touchStartContainerFrom = true
			assert.Equal(t, c2.Name(), name)
			wg1.Done()
		}).Return(nil)

	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Nanosecond*1)
		wg2.Done()
	}()
	log.Info("Wating for finish running container ", c2.Name())
	wg1.Wait()
	cancel()
	log.Info("Wating for quiting ticker")
	wg2.Wait()

	assert.True(t, touchListContainers)
	assert.True(t, touchStartContainerFrom)
	client.AssertExpectations(t)
}

func TestRunTickerTestContainers_FailedToFindBasicContainer(t *testing.T) {
	var wg1, wg2 sync.WaitGroup
	wg1.Add(1)
	wg2.Add(1)
	cc := &dockerclient.ContainerConfig{
		Labels: map[string]string{
			container.TugbotTest:       "true",
			container.TugbotEventTimer: "1ms",
		},
	}
	c := *container.NewContainer(
		&dockerclient.ContainerInfo{
			Id:     "cid",
			Name:   "API tests",
			Config: cc,
			State:  stateExited,
		},
		nil,
	)

	client := mockclient.NewMockClient()
	client.On("ListContainers", mock.AnythingOfType("container.Filter")).
		Return([]container.Container{c}, nil).Once()
	// failed to find basic container (to start from it a new container)
	client.On("Inspect", mock.AnythingOfType("string")).
		Run(func(args mock.Arguments) {
			assert.Equal(t, c.ID(), args.Get(0).(string))
			wg1.Done()
		}).Return(&container.Container{}, errors.New("Expected :-)")).Once()
	ctx, cancel := context.WithCancel(context.Background())
	go func() {
		RunTickerTestContainers(ctx, client, time.Second*10)
		wg2.Done()
	}()
	log.Info("Wating for inpect of ", c.Name())
	wg1.Wait()
	cancel()
	log.Info("Wating for quiting ticker")
	wg2.Wait()

	client.AssertExpectations(t)
}
<|endoftext|>


<commit_before>package networking

import (
	"../events"
	"../state"
	"encoding/json"
	"log"
	"net"
	"strconv"
)

type subscribtionsType map[string]chan bool

type Connection struct {
	conn          net.Conn
	sender        *SyncedSender
	subscribtions subscribtionsType
}

func NewConnection(conn net.Conn) *Connection {
	connection := new(Connection)
	connection.conn = conn
	connection.sender = NewSyncedSender(conn)
	connection.subscribtions = make(subscribtionsType)
	return connection
}

func (conn *Connection) sendStatusMessage(id int64, key, msg string) {
	packet := new(ApiMessage)
	packet.Id = id
	packet.Type = "status"
	packet.Data.Key = key
	packet.Data.Payload = msg
	conn.sender.Send(packet)
}

func (conn *Connection) subscribe(req *ApiMessage) {
	topic := req.Data.Key
	if _, ok := conn.subscribtions[topic]; !ok {
		eventChan, unsubscribeChan := events.Subscribe(topic)
		closeChan := make(chan bool)
		conn.subscribtions[topic] = closeChan
		go func() {
			defer func() {
				unsubscribeChan <- true
			}()
			for {
				select {
				case event := <-eventChan:
					{
						resp := new(ApiMessage)
						resp.Id = req.Id
						resp.Type = "event"
						resp.Data.Key = topic
						resp.Data.Payload = event
						err := conn.sender.Send(resp)
						if err != nil {
							log.Print(err)
							return
						}
					}
				case <-closeChan:
					{
						return
					}
				}
			}
		}()
		conn.sendStatusMessage(req.Id,"ok", "successfully subscribed to "+topic)
	} else {
		conn.sendStatusMessage(req.Id,"error", "you are allready subscribed to "+topic)
		log.Print("allready subscribed to topic ", topic)
	}
}

func (conn *Connection) unsubscribe(req *ApiMessage) {
	topic := req.Data.Key
	if ch, ok := conn.subscribtions[topic]; ok {
		ch <- true
		delete(conn.subscribtions, topic)
		conn.sendStatusMessage(req.Id,"ok", "successfully unsubscribed from "+topic)
	} else {
		conn.sendStatusMessage(req.Id,"error", "you are not subscribed to "+topic)
		log.Print("not subscribed to topic ", topic)
	}
}

type ApiMessage struct {
	Id   int64  `json:"id,omitempty"`
	Type string `json:"type"`
	Data struct {
		Key     string      `json:"key"`
		Payload interface{} `json:"payload"`
	} `json:"data"`
}

func HandleConnection(conn net.Conn) {
	connection := NewConnection(conn)
	defer func() {
		for _, ch := range connection.subscribtions {
			ch <- true
		}
		connection.sender.Close()
		conn.Close()
	}()
	decoder := json.NewDecoder(conn)
	for {
		req := ApiMessage{}
		err := decoder.Decode(&req)
		if err != nil {
			log.Print(err)
			return
		}
		switch req.Type {
		case "subscribe":
			{
				connection.subscribe(&req)
			}
		case "unsubscribe":
			{
				connection.unsubscribe(&req)
			}
		case "publish":
			{
				events.Publish(req.Data.Key, req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully published event to "+req.Data.Key)
			}
		case "set":
			{
				state.Set(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully saved data to "+req.Data.Key)
			}
		case "push":
			{
				state.Push(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully pushed data to "+req.Data.Key)
			}
		case "enqueue":
			{
				state.Enqueue(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully queued data to "+req.Data.Key)
			}
		case "get":
			{
				data := state.Get(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "pop":
			{
				data := state.Pop(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "dequeue":
			{
				data := state.Dequeue(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "unset":
			{
				state.Unset(req.Data.Key)
				connection.sendStatusMessage(req.Id,"ok", "successfully unset data from "+req.Data.Key)
			}
		default:
			{
				connection.sendStatusMessage(req.Id,"error", "no such request type: "+req.Type)
			}
		}
		// fmt.Println("Request: ",req)
	}
}

func StartTCPServer(port uint16) error {
	listener, err := net.Listen("tcp", ":"+strconv.FormatInt(int64(port), 10))
	if err != nil {
		return err
	}
	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Print(err)
				continue
			}
			go HandleConnection(conn)
		}
	}()
	return nil
}
<commit_msg>[event] unified return event structure from normal and glob events;<commit_after>package networking

import (
	"../events"
	"../state"
	"encoding/json"
	"log"
	"net"
	"strconv"
)

type subscribtionsType map[string]chan bool

type Connection struct {
	conn          net.Conn
	sender        *SyncedSender
	subscribtions subscribtionsType
}

func NewConnection(conn net.Conn) *Connection {
	connection := new(Connection)
	connection.conn = conn
	connection.sender = NewSyncedSender(conn)
	connection.subscribtions = make(subscribtionsType)
	return connection
}

func (conn *Connection) sendStatusMessage(id int64, key, msg string) {
	packet := new(ApiMessage)
	packet.Id = id
	packet.Type = "status"
	packet.Data.Key = key
	packet.Data.Payload = msg
	conn.sender.Send(packet)
}

func (conn *Connection) subscribe(req *ApiMessage) {
	topic := req.Data.Key
	if _, ok := conn.subscribtions[topic]; !ok {
		eventChan, unsubscribeChan := events.Subscribe(topic)
		closeChan := make(chan bool)
		conn.subscribtions[topic] = closeChan
		go func() {
			defer func() {
				unsubscribeChan <- true
			}()
			for {
				select {
				case event := <-eventChan:
					{
						resp := new(ApiMessage)
						resp.Id = req.Id
						resp.Type = "event"
						resp.Data.Key = topic
						resp.Data.Payload = event
						if evt,ok := event.(map[string]interface{}); ok {
							if topic,ok = evt["topic"].(string);ok {
								resp.Data.Key = topic
								if pay,ok := evt["payload"]; ok {
									resp.Data.Payload = pay
								}
							}
						}
						err := conn.sender.Send(resp)
						if err != nil {
							log.Print(err)
							return
						}
					}
				case <-closeChan:
					{
						return
					}
				}
			}
		}()
		conn.sendStatusMessage(req.Id,"ok", "successfully subscribed to "+topic)
	} else {
		conn.sendStatusMessage(req.Id,"error", "you are allready subscribed to "+topic)
		log.Print("allready subscribed to topic ", topic)
	}
}

func (conn *Connection) unsubscribe(req *ApiMessage) {
	topic := req.Data.Key
	if ch, ok := conn.subscribtions[topic]; ok {
		ch <- true
		delete(conn.subscribtions, topic)
		conn.sendStatusMessage(req.Id,"ok", "successfully unsubscribed from "+topic)
	} else {
		conn.sendStatusMessage(req.Id,"error", "you are not subscribed to "+topic)
		log.Print("not subscribed to topic ", topic)
	}
}

type ApiMessage struct {
	Id   int64  `json:"id,omitempty"`
	Type string `json:"type"`
	Data struct {
		Key     string      `json:"key"`
		Payload interface{} `json:"payload"`
	} `json:"data"`
}

func HandleConnection(conn net.Conn) {
	connection := NewConnection(conn)
	defer func() {
		for _, ch := range connection.subscribtions {
			ch <- true
		}
		connection.sender.Close()
		conn.Close()
	}()
	decoder := json.NewDecoder(conn)
	for {
		req := ApiMessage{}
		err := decoder.Decode(&req)
		if err != nil {
			log.Print(err)
			return
		}
		switch req.Type {
		case "subscribe":
			{
				connection.subscribe(&req)
			}
		case "unsubscribe":
			{
				connection.unsubscribe(&req)
			}
		case "publish":
			{
				events.Publish(req.Data.Key, req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully published event to "+req.Data.Key)
			}
		case "set":
			{
				state.Set(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully saved data to "+req.Data.Key)
			}
		case "push":
			{
				state.Push(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully pushed data to "+req.Data.Key)
			}
		case "enqueue":
			{
				state.Enqueue(req.Data.Key,req.Data.Payload)
				connection.sendStatusMessage(req.Id,"ok", "successfully queued data to "+req.Data.Key)
			}
		case "get":
			{
				data := state.Get(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "pop":
			{
				data := state.Pop(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "dequeue":
			{
				data := state.Dequeue(req.Data.Key)
				packet := new(ApiMessage)
				packet.Id = req.Id
				packet.Type = "response"
				packet.Data.Key = req.Data.Key
				packet.Data.Payload = data
				connection.sender.Send(packet)
			}
		case "unset":
			{
				state.Unset(req.Data.Key)
				connection.sendStatusMessage(req.Id,"ok", "successfully unset data from "+req.Data.Key)
			}
		default:
			{
				connection.sendStatusMessage(req.Id,"error", "no such request type: "+req.Type)
			}
		}
		// fmt.Println("Request: ",req)
	}
}

func StartTCPServer(port uint16) error {
	listener, err := net.Listen("tcp", ":"+strconv.FormatInt(int64(port), 10))
	if err != nil {
		return err
	}
	go func() {
		for {
			conn, err := listener.Accept()
			if err != nil {
				log.Print(err)
				continue
			}
			go HandleConnection(conn)
		}
	}()
	return nil
}
<|endoftext|>


<commit_before>/*
 *  uplink, a simple daemon to implement a simple chat protocol
 *  Copyright (C) Marco Cilloni <marco.cilloni@yahoo.com> 2016
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *  Exhibit B is not attached; this software is compatible with the
 *  licenses expressed under Section 1.12 of the MPL v2.
 *
 */

package uplink

import (
	"log"

	pd "github.com/mcilloni/uplink/protodef"
)

type sink struct {
	UID  int64
	Sink chan *pd.Notification
}

type broadcast struct {
	UIDs         []int64
	Notification *pd.Notification
}

type dispatcher struct {
	l *log.Logger

	pushChans []chan<- *broadcast
	bins      map[int64][]chan<- *pd.Notification
	started   bool

	addSinkChan    chan *sink
	notifyChan     chan *broadcast
	removeSinkChan chan *sink
}

func startDispatcher(l *log.Logger) *dispatcher {
	d := &dispatcher{
		l:              l,
		pushChans:      make([]chan<- *broadcast, 1),
		bins:           make(map[int64][]chan<- *pd.Notification),
		addSinkChan:    make(chan *sink, 100),
		notifyChan:     make(chan *broadcast, 1000),
		removeSinkChan: make(chan *sink, 100),
	}

	go d.start()

	return d
}

func (d *dispatcher) addPushChan(sink chan<- *broadcast) {
	d.pushChans = append(d.pushChans, sink)
}

func (d *dispatcher) addSinkInternal(uid int64, sink chan<- *pd.Notification) {
	bin, ok := d.bins[uid]
	if !ok {
		bin = []chan<- *pd.Notification{}
	}

	d.bins[uid] = append(bin, sink)

	sink <- &pd.Notification{Type: pd.Notification_HANDLER_READY}
}

func (d *dispatcher) notifyInternal(uids []int64, notif *pd.Notification) {
	for _, pushChan := range d.pushChans {
		go func(pushChan chan<- *broadcast) {
			pushChan <- &broadcast{UIDs: uids, Notification: notif}
		}(pushChan)
	}

	for _, uid := range uids {
		if bin, ok := d.bins[uid]; ok {
			for _, sink := range bin {
				go func(sink chan<- *pd.Notification) {
					sink <- notif
				}(sink)
			}
		}
	}
}

func (d *dispatcher) removeSinkInternal(uid int64, toRemove chan<- *pd.Notification) {
	defer close(toRemove)

	if bin, ok := d.bins[uid]; ok {
		for i, sink := range bin {
			if sink == toRemove {
				d.bins[uid] = append(bin[:i], bin[i+1:]...)

				return
			}
		}
	}
}

func (d *dispatcher) start() {
	if d.started {
		panic("dispatcher already started")
	}

	d.started = true

	for {
		select {
		case sink := <-d.addSinkChan:
			d.addSinkInternal(sink.UID, sink.Sink)

		case broadcast := <-d.notifyChan:
			d.notifyInternal(broadcast.UIDs, broadcast.Notification)

		case sink := <-d.removeSinkChan:
			d.removeSinkInternal(sink.UID, sink.Sink)
		}
	}
}

func (d *dispatcher) AddSink(uid int64) chan *pd.Notification {
	newSink := make(chan *pd.Notification)
	d.addSinkChan <- &sink{uid, newSink}

	return newSink
}

func (d *dispatcher) Notify(uids []int64, notification *pd.Notification) {
	d.notifyChan <- &broadcast{uids, notification}
}

func (d *dispatcher) RemoveSink(uid int64, oldSink chan *pd.Notification) {
	d.removeSinkChan <- &sink{uid, oldSink}
}
<commit_msg>Small change<commit_after>/*
 *  uplink, a simple daemon to implement a simple chat protocol
 *  Copyright (C) Marco Cilloni <marco.cilloni@yahoo.com> 2016
 *
 *  This Source Code Form is subject to the terms of the Mozilla Public
 *  License, v. 2.0. If a copy of the MPL was not distributed with this
 *  file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *  Exhibit B is not attached; this software is compatible with the
 *  licenses expressed under Section 1.12 of the MPL v2.
 *
 */

package uplink

import (
	"log"

	pd "github.com/mcilloni/uplink/protodef"
)

type sink struct {
	UID  int64
	Sink chan *pd.Notification
}

type broadcast struct {
	UIDs         []int64
	Notification *pd.Notification
}

type dispatcher struct {
	l *log.Logger

	pushChans []chan<- *broadcast
	bins      map[int64][]chan<- *pd.Notification
	started   bool

	addSinkChan    chan *sink
	notifyChan     chan *broadcast
	removeSinkChan chan *sink
}

func startDispatcher(l *log.Logger) *dispatcher {
	d := &dispatcher{
		l:              l,
		pushChans:      make([]chan<- *broadcast, 0),
		bins:           make(map[int64][]chan<- *pd.Notification),
		addSinkChan:    make(chan *sink, 100),
		notifyChan:     make(chan *broadcast, 1000),
		removeSinkChan: make(chan *sink, 100),
	}

	go d.start()

	return d
}

func (d *dispatcher) addPushChan(sink chan<- *broadcast) {
	d.pushChans = append(d.pushChans, sink)
}

func (d *dispatcher) addSinkInternal(uid int64, sink chan<- *pd.Notification) {
	bin, ok := d.bins[uid]
	if !ok {
		bin = []chan<- *pd.Notification{}
	}

	d.bins[uid] = append(bin, sink)

	sink <- &pd.Notification{Type: pd.Notification_HANDLER_READY}
}

func (d *dispatcher) notifyInternal(uids []int64, notif *pd.Notification) {
	for _, pushChan := range d.pushChans {
		go func(pushChan chan<- *broadcast) {
			pushChan <- &broadcast{UIDs: uids, Notification: notif}
		}(pushChan)
	}

	for _, uid := range uids {
		if bin, ok := d.bins[uid]; ok {
			for _, sink := range bin {
				go func(sink chan<- *pd.Notification) {
					sink <- notif
				}(sink)
			}
		}
	}
}

func (d *dispatcher) removeSinkInternal(uid int64, toRemove chan<- *pd.Notification) {
	defer close(toRemove)

	if bin, ok := d.bins[uid]; ok {
		for i, sink := range bin {
			if sink == toRemove {
				d.bins[uid] = append(bin[:i], bin[i+1:]...)

				return
			}
		}
	}
}

func (d *dispatcher) start() {
	if d.started {
		panic("dispatcher already started")
	}

	d.started = true

	for {
		select {
		case sink := <-d.addSinkChan:
			d.addSinkInternal(sink.UID, sink.Sink)

		case broadcast := <-d.notifyChan:
			d.notifyInternal(broadcast.UIDs, broadcast.Notification)

		case sink := <-d.removeSinkChan:
			d.removeSinkInternal(sink.UID, sink.Sink)
		}
	}
}

func (d *dispatcher) AddSink(uid int64) chan *pd.Notification {
	newSink := make(chan *pd.Notification)
	d.addSinkChan <- &sink{uid, newSink}

	return newSink
}

func (d *dispatcher) Notify(uids []int64, notification *pd.Notification) {
	d.notifyChan <- &broadcast{uids, notification}
}

func (d *dispatcher) RemoveSink(uid int64, oldSink chan *pd.Notification) {
	d.removeSinkChan <- &sink{uid, oldSink}
}
<|endoftext|>


<commit_before>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob_test

import (
	"errors"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestChecking(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type checkingStoreTest struct {
	wrapped mock_blob.MockStore
	store   blob.Store
}

func (t *checkingStoreTest) SetUp(i *TestInfo) {
	t.wrapped = mock_blob.NewMockStore(i.MockController, "wrapped")
	t.store = blob.NewCheckingStore(t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// Store
////////////////////////////////////////////////////////////////////////

type CheckingStore_StoreTest struct {
	checkingStoreTest
}

func init() { RegisterTestSuite(&CheckingStore_StoreTest{}) }

func (t *CheckingStore_StoreTest) CallsWrapped() {
	blob := []byte{0xde, 0xad}

	// Wrapped
	ExpectCall(t.wrapped, "Store")(DeepEquals(blob)).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.store.Store([]byte{})
}

func (t *CheckingStore_StoreTest) WrappedReturnsError() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_StoreTest) WrappedReturnsIncorrectScore() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_StoreTest) WrappedReturnsCorrectScore() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// Load
////////////////////////////////////////////////////////////////////////

type CheckingStore_LoadTest struct {
	checkingStoreTest
}

func init() { RegisterTestSuite(&CheckingStore_LoadTest{}) }

func (t *CheckingStore_LoadTest) CallsWrapped() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsError() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsCorrectData() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsIncorrectData() {
	ExpectEq("TODO", "")
}
<commit_msg>CheckingStore_StoreTest.WrappedReturnsError<commit_after>// Copyright 2012 Aaron Jacobs. All Rights Reserved.
// Author: aaronjjacobs@gmail.com (Aaron Jacobs)
//
// 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 blob_test

import (
	"errors"
	"github.com/jacobsa/comeback/blob"
	"github.com/jacobsa/comeback/blob/mock"
	. "github.com/jacobsa/oglematchers"
	"github.com/jacobsa/oglemock"
	. "github.com/jacobsa/ogletest"
	"testing"
)

func TestChecking(t *testing.T) { RunTests(t) }

////////////////////////////////////////////////////////////////////////
// Helpers
////////////////////////////////////////////////////////////////////////

type checkingStoreTest struct {
	wrapped mock_blob.MockStore
	store   blob.Store
}

func (t *checkingStoreTest) SetUp(i *TestInfo) {
	t.wrapped = mock_blob.NewMockStore(i.MockController, "wrapped")
	t.store = blob.NewCheckingStore(t.wrapped)
}

////////////////////////////////////////////////////////////////////////
// Store
////////////////////////////////////////////////////////////////////////

type CheckingStore_StoreTest struct {
	checkingStoreTest
}

func init() { RegisterTestSuite(&CheckingStore_StoreTest{}) }

func (t *CheckingStore_StoreTest) CallsWrapped() {
	blob := []byte{0xde, 0xad}

	// Wrapped
	ExpectCall(t.wrapped, "Store")(DeepEquals(blob)).
		WillOnce(oglemock.Return(nil, errors.New("")))

	// Call
	t.store.Store(blob)
}

func (t *CheckingStore_StoreTest) WrappedReturnsError() {
	// Wrapped
	ExpectCall(t.wrapped, "Store")(Any()).
		WillOnce(oglemock.Return(nil, errors.New("taco")))

	// Call
	_, err := t.store.Store([]byte{})

	ExpectThat(err, Error(Equals("taco")))
}

func (t *CheckingStore_StoreTest) WrappedReturnsIncorrectScore() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_StoreTest) WrappedReturnsCorrectScore() {
	ExpectEq("TODO", "")
}

////////////////////////////////////////////////////////////////////////
// Load
////////////////////////////////////////////////////////////////////////

type CheckingStore_LoadTest struct {
	checkingStoreTest
}

func init() { RegisterTestSuite(&CheckingStore_LoadTest{}) }

func (t *CheckingStore_LoadTest) CallsWrapped() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsError() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsCorrectData() {
	ExpectEq("TODO", "")
}

func (t *CheckingStore_LoadTest) WrappedReturnsIncorrectData() {
	ExpectEq("TODO", "")
}
<|endoftext|>


<commit_before>package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"github.com/satori/go.uuid"

)

func (s *supervisor) permission(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `category`}

	log.Printf(LogStrReq, q.Type, fmt.Sprintf("%s/%s", q.Action, q.Super.Action), q.User, q.RemoteAddr)

	if s.readonly && (q.Super.Action == `add` || q.Super.Action == `delete`) {
		result.Conflict(fmt.Errorf(`Readonly instance`))
		goto dispatch
	}

	switch q.Super.Action {
	case `list`:
		fallthrough
	case `show`:
		s.permission_read(q)
		return
	case `add`:
		fallthrough
	case `delete`:
		s.permission_write(q)
		return
	}

dispatch:
	q.Reply <- result
}

func (s *supervisor) permission_read(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `permission`}
	var (
		rows                     *sql.Rows
		err                      error
		id, name, category, user string
		ts                       time.Time
	)

	switch q.Super.Action {
	case `list`:
		result.Permission = []proto.Permission{}
		if rows, err = s.stmt_ListPermission.Query(); err != nil {
			result.ServerError(err)
			goto dispatch
		}
		defer rows.Close()

		for rows.Next() {
			if err = rows.Scan(
				&id,
				&name,
			); err != nil {
				result.ServerError(err)
				result.Clear(q.Action)
				goto dispatch
			}
			result.Permission = append(result.Permission,
				proto.Permission{Id: id, Name: name})
		}
		if err = rows.Err(); err != nil {
			result.ServerError(err)
			result.Clear(q.Action)
		}
	case `show`:
		if err = s.stmt_ShowPermission.QueryRow(q.Permission.Id).Scan(
			&id,
			&name,
			&category,
			&user,
			&ts,
		); err == sql.ErrNoRows {
			result.NotFound(err)
			goto dispatch
		} else if err != nil {
			result.ServerError(err)
			goto dispatch
		}
		result.Permission = []proto.Permission{proto.Permission{
			Id:       id,
			Name:     name,
			Category: category,
			Details: &proto.PermissionDetails{
				CreatedAt: ts.Format(rfc3339Milli),
				CreatedBy: user,
			},
		}}
	}

dispatch:
	q.Reply <- result
}

func (s *supervisor) permission_write(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `permission`}
	userUUID, ok := s.id_user_rev.get(q.User)
	if !ok {
		userUUID = `00000000-0000-0000-0000-000000000000`
	}

	var (
		res sql.Result
		err error
	)

	switch q.Super.Action {
	case `add`:
		q.Permission.Id = uuid.NewV4().String()
		res, err = s.stmt_AddPermission.Exec(
			q.Permission.Id,
			q.Permission.Name,
			q.Permission.Category,
			userUUID,
		)
	case `delete`:
		res, err = s.stmt_DelPermission.Exec(
			q.Permission.Id,
		)
	}
	if err != nil {
		result.ServerError(err)
		goto dispatch
	}

	if result.RowCnt(res.RowsAffected()) {
		result.Permission = []proto.Permission{q.Permission}
		// keep lookup maps in sync
		switch q.Super.Action {
		case `add`:
			s.id_permission.insert(q.Permission.Id, q.Permission.Name)
		case `delete`:
			s.id_permission.remove(q.Permission.Id)
		}
	}

dispatch:
	q.Reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<commit_msg>FIX: delete permissions<commit_after>package main

import (
	"database/sql"
	"fmt"
	"log"
	"time"

	"github.com/satori/go.uuid"

)

func (s *supervisor) permission(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `category`}

	log.Printf(LogStrReq, q.Type, fmt.Sprintf("%s/%s", q.Action, q.Super.Action), q.User, q.RemoteAddr)

	if s.readonly && (q.Super.Action == `add` || q.Super.Action == `delete`) {
		result.Conflict(fmt.Errorf(`Readonly instance`))
		goto dispatch
	}

	switch q.Super.Action {
	case `list`:
		fallthrough
	case `show`:
		s.permission_read(q)
		return
	case `add`:
		fallthrough
	case `delete`:
		s.permission_write(q)
		return
	}

dispatch:
	q.Reply <- result
}

func (s *supervisor) permission_read(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `permission`}
	var (
		rows                     *sql.Rows
		err                      error
		id, name, category, user string
		ts                       time.Time
	)

	switch q.Super.Action {
	case `list`:
		result.Permission = []proto.Permission{}
		if rows, err = s.stmt_ListPermission.Query(); err != nil {
			result.ServerError(err)
			goto dispatch
		}
		defer rows.Close()

		for rows.Next() {
			if err = rows.Scan(
				&id,
				&name,
			); err != nil {
				result.ServerError(err)
				result.Clear(q.Action)
				goto dispatch
			}
			result.Permission = append(result.Permission,
				proto.Permission{Id: id, Name: name})
		}
		if err = rows.Err(); err != nil {
			result.ServerError(err)
			result.Clear(q.Action)
		}
	case `show`:
		if err = s.stmt_ShowPermission.QueryRow(q.Permission.Id).Scan(
			&id,
			&name,
			&category,
			&user,
			&ts,
		); err == sql.ErrNoRows {
			result.NotFound(err)
			goto dispatch
		} else if err != nil {
			result.ServerError(err)
			goto dispatch
		}
		result.Permission = []proto.Permission{proto.Permission{
			Id:       id,
			Name:     name,
			Category: category,
			Details: &proto.PermissionDetails{
				CreatedAt: ts.Format(rfc3339Milli),
				CreatedBy: user,
			},
		}}
	}

dispatch:
	q.Reply <- result
}

func (s *supervisor) permission_write(q *msg.Request) {
	result := msg.Result{Type: `supervisor`, Action: `permission`}
	userUUID, ok := s.id_user_rev.get(q.User)
	if !ok {
		userUUID = `00000000-0000-0000-0000-000000000000`
	}

	var (
		res sql.Result
		err error
		id  string
	)

	switch q.Super.Action {
	case `add`:
		q.Permission.Id = uuid.NewV4().String()
		res, err = s.stmt_AddPermission.Exec(
			q.Permission.Id,
			q.Permission.Name,
			q.Permission.Category,
			userUUID,
		)
	case `delete`:
		if id, ok = s.id_permission.scan(q.Permission.Name); !ok {
			result.NotFound(fmt.Errorf(`Supervisor: unknown`))
			goto dispatch
		}
		res, err = s.stmt_DelPermission.Exec(
			id,
		)
	}
	if err != nil {
		result.ServerError(err)
		goto dispatch
	}

	if result.RowCnt(res.RowsAffected()) {
		result.Permission = []proto.Permission{q.Permission}
		// keep lookup maps in sync
		switch q.Super.Action {
		case `add`:
			s.id_permission.insert(q.Permission.Id, q.Permission.Name)
		case `delete`:
			s.id_permission.remove(id)
		}
	}

dispatch:
	q.Reply <- result
}

// vim: ts=4 sw=4 sts=4 noet fenc=utf-8 ffs=unix
<|endoftext|>


<commit_before>package btrfs

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os/exec"
	"path"
	"time"

	"github.com/aws/aws-sdk-go/service/s3"

	"github.com/pachyderm/pachyderm/src/s3utils"
	"github.com/pachyderm/pachyderm/src/util"
)

// localReplica implements the Replica interface using a btrfs repo.
type localReplica struct {
	repo string
}

func newLocalReplica(repo string) *localReplica {
	return &localReplica{repo}
}

func (r *localReplica) From() (string, error) {
	from := ""
	err := Commits(r.repo, "", Desc, func(name string) error {
		isCommit, err := IsCommit(path.Join(r.repo, name))
		if err != nil {
			return err
		}
		if isCommit {
			from = name
			return ErrComplete
		}
		return nil
	})
	if err != nil && err != ErrComplete {
		return "", err
	}

	return from, nil
}

func (r *localReplica) Push(diff io.Reader) error {
	return recv(r.repo, diff)
}

func (r *localReplica) Pull(from string, cb Pusher) error {
	return Pull(r.repo, from, cb)
}

// s3Replica implements the Replica interface using an s3 replica.
type s3Replica struct {
	uri   string
	count int // number of sent commits
}

func newS3Replica(uri string) *s3Replica {
	return &s3Replica{uri, 0}
}

func (r *s3Replica) Push(diff io.Reader) error {
	key := fmt.Sprintf("%.10d", r.count)
	r.count++

	p, err := s3utils.GetPath(r.uri)
	if err != nil {
		return err
	}

	return s3utils.PutMulti(r.uri, path.Join(p, key), diff, "application/octet-stream", s3utils.BucketOwnerFull)
}

func (r *s3Replica) Pull(from string, target Pusher) error {
	client := s3.New(nil)
	err := s3utils.ForEachFile(r.uri, from, func(path string, modtime time.Time) (retErr error) {
		response, err := client.GetObject(&s3.GetObjectInput{
			Bucket: &r.uri,
			Key:    &path,
		})

		f := response.Body

		if f == nil {
			return fmt.Errorf("Nil file returned.")
		}
		if err != nil {
			return err
		}
		defer func() {
			if err := f.Close(); err != nil && retErr == nil {
				retErr = err
			}
		}()

		err = target.Push(f)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}

func (r *s3Replica) From() (string, error) {
	result := ""
	err := s3utils.ForEachFile(r.uri, "", func(path string, modtime time.Time) error {
		result = path
		return nil
	})
	return result, err
}

// send produces a binary diff stream and passes it to cont
func send(repo, commit string, cont func(io.Reader) error) error {
	parent := GetMeta(path.Join(repo, commit), "parent")
	if parent == "" {
		return util.CallCont(exec.Command("btrfs", "send", FilePath(path.Join(repo, commit))), cont)
	} else {
		return util.CallCont(exec.Command("btrfs", "send", "-p",
			FilePath(path.Join(repo, parent)), FilePath(path.Join(repo, commit))), cont)
	}
}

// recv reads a binary stream from data and applies it to `repo`
func recv(repo string, data io.Reader) error {
	c := exec.Command("btrfs", "receive", FilePath(repo))
	stdin, err := c.StdinPipe()
	if err != nil {
		return err
	}
	stderr, err := c.StderrPipe()
	if err != nil {
		return err
	}
	err = c.Start()
	if err != nil {
		return err
	}
	_, err = io.Copy(stdin, data)
	if err != nil {
		return err
	}
	err = stdin.Close()
	if err != nil {
		return err
	}
	buf := new(bytes.Buffer)
	buf.ReadFrom(stderr)
	log.Print("Stderr:", buf)
	err = c.Wait()
	if err != nil {
		return err
	}
	createNewBranch(repo)
	return nil
}

// createNewBranch gets called after a new commit has been `Recv`ed it creates
// the branch that should be pointing to the newly made commit.
func createNewBranch(repo string) error {
	// TODO this is a kind of ugly way to get the most recent branch we should
	// make it better
	err := Commits(repo, "", Desc, func(name string) error {
		branch := GetMeta(path.Join(repo, name), "branch")
		err := subvolumeDeleteAll(path.Join(repo, branch))
		if err != nil {
			return err
		}
		err = Branch(repo, name, branch)
		if err != nil {
			return err
		}
		return ErrComplete
	})
	if err != nil && err != ErrComplete {
		return err
	}
	return nil
}
<commit_msg>Use s3utils.NewClient<commit_after>package btrfs

import (
	"bytes"
	"fmt"
	"io"
	"log"
	"os/exec"
	"path"
	"time"

	"github.com/aws/aws-sdk-go/service/s3"

	"github.com/pachyderm/pachyderm/src/s3utils"
	"github.com/pachyderm/pachyderm/src/util"
)

// localReplica implements the Replica interface using a btrfs repo.
type localReplica struct {
	repo string
}

func newLocalReplica(repo string) *localReplica {
	return &localReplica{repo}
}

func (r *localReplica) From() (string, error) {
	from := ""
	err := Commits(r.repo, "", Desc, func(name string) error {
		isCommit, err := IsCommit(path.Join(r.repo, name))
		if err != nil {
			return err
		}
		if isCommit {
			from = name
			return ErrComplete
		}
		return nil
	})
	if err != nil && err != ErrComplete {
		return "", err
	}

	return from, nil
}

func (r *localReplica) Push(diff io.Reader) error {
	return recv(r.repo, diff)
}

func (r *localReplica) Pull(from string, cb Pusher) error {
	return Pull(r.repo, from, cb)
}

// s3Replica implements the Replica interface using an s3 replica.
type s3Replica struct {
	uri   string
	count int // number of sent commits
}

func newS3Replica(uri string) *s3Replica {
	return &s3Replica{uri, 0}
}

func (r *s3Replica) Push(diff io.Reader) error {
	key := fmt.Sprintf("%.10d", r.count)
	r.count++

	p, err := s3utils.GetPath(r.uri)
	if err != nil {
		return err
	}

	return s3utils.PutMulti(r.uri, path.Join(p, key), diff, "application/octet-stream", s3utils.BucketOwnerFull)
}

func (r *s3Replica) Pull(from string, target Pusher) error {
	client := s3utils.NewClient()
	err := s3utils.ForEachFile(r.uri, from, func(path string, modtime time.Time) (retErr error) {
		response, err := client.GetObject(&s3.GetObjectInput{
			Bucket: &r.uri,
			Key:    &path,
		})

		f := response.Body

		if f == nil {
			return fmt.Errorf("Nil file returned.")
		}
		if err != nil {
			return err
		}
		defer func() {
			if err := f.Close(); err != nil && retErr == nil {
				retErr = err
			}
		}()

		err = target.Push(f)
		if err != nil {
			return err
		}
		return nil
	})
	if err != nil {
		return err
	}
	return nil
}

func (r *s3Replica) From() (string, error) {
	result := ""
	err := s3utils.ForEachFile(r.uri, "", func(path string, modtime time.Time) error {
		result = path
		return nil
	})
	return result, err
}

// send produces a binary diff stream and passes it to cont
func send(repo, commit string, cont func(io.Reader) error) error {
	parent := GetMeta(path.Join(repo, commit), "parent")
	if parent == "" {
		return util.CallCont(exec.Command("btrfs", "send", FilePath(path.Join(repo, commit))), cont)
	} else {
		return util.CallCont(exec.Command("btrfs", "send", "-p",
			FilePath(path.Join(repo, parent)), FilePath(path.Join(repo, commit))), cont)
	}
}

// recv reads a binary stream from data and applies it to `repo`
func recv(repo string, data io.Reader) error {
	c := exec.Command("btrfs", "receive", FilePath(repo))
	stdin, err := c.StdinPipe()
	if err != nil {
		return err
	}
	stderr, err := c.StderrPipe()
	if err != nil {
		return err
	}
	err = c.Start()
	if err != nil {
		return err
	}
	_, err = io.Copy(stdin, data)
	if err != nil {
		return err
	}
	err = stdin.Close()
	if err != nil {
		return err
	}
	buf := new(bytes.Buffer)
	buf.ReadFrom(stderr)
	log.Print("Stderr:", buf)
	err = c.Wait()
	if err != nil {
		return err
	}
	createNewBranch(repo)
	return nil
}

// createNewBranch gets called after a new commit has been `Recv`ed it creates
// the branch that should be pointing to the newly made commit.
func createNewBranch(repo string) error {
	// TODO this is a kind of ugly way to get the most recent branch we should
	// make it better
	err := Commits(repo, "", Desc, func(name string) error {
		branch := GetMeta(path.Join(repo, name), "branch")
		err := subvolumeDeleteAll(path.Join(repo, branch))
		if err != nil {
			return err
		}
		err = Branch(repo, name, branch)
		if err != nil {
			return err
		}
		return ErrComplete
	})
	if err != nil && err != ErrComplete {
		return err
	}
	return nil
}
<|endoftext|>