<commit_before>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int
var userList []string
var shareList map[string]int
var availableList map[string]int

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "draft"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}
		fmt.Printf("user is %v and amount is %v", args[0], args[1])
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	}
	return nil, nil
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	case "getUserList":
		fmt.Println("started logging in getUserList")
		var result string
		for i, value := range userList {
			result += fmt.Sprintf("userList[%v] is %v ****", strconv.Itoa(i), value)
		}
		return []byte(result), nil
	case "getShareList":
		fmt.Println("started logging in getShareList")
		return nil, nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	}
	return nil, nil
}
<commit_msg>demo7.go<commit_after>package main

import (
	"errors"
	"fmt"
	"strconv"

	"github.com/hyperledger/fabric/core/chaincode/shim"
)

type SimpleChaincode struct {
}

func main() {
	fmt.Println("started logging in main()")
	err := shim.Start(new(SimpleChaincode))
	if err != nil {
		fmt.Println("failed in function main()")
	}
}

var projectName string
var projectRate int
var projectPeriod int
var projectGoal int
var projectTimes int
var projectBenifary string
var projectState string
var currentPrice float64
var projectSummary int
var userList []string
var shareList map[string]int
var availableList map[string]int

//Init comment
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Init()")

	//started to initialize the projectState
	//step1: check whether args == 5
	if len(args) != 5 {
		return nil, errors.New("failed in args")
	}

	//step 2, intialize the project properties
	projectName = args[0]
	stub.PutState("projectName", []byte(projectName))

	projectRate, _ = strconv.Atoi(args[1])
	if projectRate <= 0 {
		return nil, errors.New("errors in args[1], it cannot be negative")
	}
	stub.PutState("projectRate", []byte(args[1]))

	projectPeriod, _ = strconv.Atoi(args[2])
	if projectPeriod <= 0 {
		return nil, errors.New("errors in args[2], it cannot be negative")
	}
	stub.PutState("projectPeriod", []byte(args[2]))

	projectGoal, _ = strconv.Atoi(args[3])
	if projectGoal <= 0 {
		return nil, errors.New("errors in args[3], it cannot be negative")
	}
	stub.PutState("projectGoal", []byte(args[3]))

	projectTimes = 1
	stub.PutState("projectTimes", []byte(strconv.Itoa(projectTimes)))

	projectBenifary = args[4]
	stub.PutState("projectBenifary", []byte(args[4]))

	projectState = "draft"
	stub.PutState("projectState", []byte(projectState))

	currentPrice = 1.0
	projectSummary = 0

	return nil, nil
} //end of Init()

// Invoke comment
func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Invoke()")
	switch function {
	case "goPublic":
		fmt.Println("started logging in goPublic")
		if len(args) != 0 {
			return nil, errors.New("failed in args")
		}
		projectState = "public"
		return nil, nil //end of goPublic
	case "pay":
		fmt.Println("started logging in pay()")

		if len(args) != 2 {
			return nil, errors.New("failed in args")
		}
		user := args[0]
		amount := args[1]
		fmt.Printf("user is %v and amount is %v", user, amount)

		amountInt, _ := strconv.Atoi(amount)
		projectSummary += amountInt
		return nil, nil
	case "checkGoalReached":
		fmt.Println("started logging in checkGoalReached()")
		// TODO: write code for checkGoalReached
		return nil, nil
	case "checkDaoqi":
		fmt.Println("started logging in checkDaoqi()")
		// TODO: write code for checkDaoqi
		return nil, nil
	case "calculatePrice":
		fmt.Println("started logging in calculatePrice")
		return nil, nil
	case "calculateResult":
		fmt.Println("started logging in calculateResult")
		return nil, nil
	}
	return nil, nil
}

// Query comment
func (t *SimpleChaincode) Query(stub shim.ChaincodeStubInterface, function string, args []string) ([]byte, error) {
	fmt.Println("started logging in Query()")
	switch function {
	case "getProjectName":
		result, err := stub.GetState("projectName")
		if err != nil {
			return nil, errors.New("error in getProjectName")
		}
		return result, nil
	case "getProjectGoal":
		result, err := stub.GetState("projectGoal")
		if err != nil {
			return nil, errors.New("error in getProjectGoal")
		}
		return result, nil
	case "getProjectSummary":
		result := strconv.Itoa(projectSummary)
		return []byte(result), nil
	case "getUserList":
		fmt.Println("started logging in getUserList")
		var result string
		for i, value := range userList {
			result += fmt.Sprintf("userList[%v] is %v ****", strconv.Itoa(i), value)
		}
		return []byte(result), nil
	case "getShareList":
		fmt.Println("started logging in getShareList")
		return nil, nil
	case "getAvailableList":
		fmt.Println("started logging in getAvailableList")
		return nil, nil
	}
	return nil, nil
}
<|endoftext|>


<commit_before>package main

import (
	"os"

	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	_ "github.com/mattn/go-sqlite3"
)

var orm *xorm.Engine

// InitDatabase sets up the database and xorm
func InitDatabase() error {
	var err error

	// connect to our database
	if os.Getenv("OPENSHIFT_MYSQL_DB_HOST") != "" {
		mysql := os.Getenv("OPENSHIFT_MYSQL_DB_USERNAME")
		mysql += ":" + os.Getenv("OPENSHIFT_MYSQL_DB_PASSWORD")
		mysql += "@tcp(" + os.Getenv("OPENSHIFT_MYSQL_DB_HOST")
		mysql += ":" + os.Getenv("OPENSHIFT_MYSQL_DB_PORT")
		mysql += ")/" + os.Getenv("OPENSHIFT_MYSQL_DB_NAME")
		orm, err = xorm.NewEngine("mysql", mysql)
	} else {
		orm, err = xorm.NewEngine("sqlite3", ":memory:")
	}

	if err != nil {
		return err
	}

	// Migrate our database if needed
	err = orm.Sync(new(ClientRequest))
	if err != nil {
		return err
	}

	return nil
}
<commit_msg>Made Database errors more clear<commit_after>package main

import (
	"fmt"
	"os"

	_ "github.com/go-sql-driver/mysql"
	"github.com/go-xorm/xorm"
	_ "github.com/mattn/go-sqlite3"
)

var orm *xorm.Engine

// InitDatabase sets up the database and xorm
func InitDatabase() error {
	var err error

	// connect to our database
	if os.Getenv("OPENSHIFT_MYSQL_DB_HOST") != "" {
		mysql := os.Getenv("OPENSHIFT_MYSQL_DB_USERNAME")
		mysql += ":" + os.Getenv("OPENSHIFT_MYSQL_DB_PASSWORD")
		mysql += "@tcp(" + os.Getenv("OPENSHIFT_MYSQL_DB_HOST")
		mysql += ":" + os.Getenv("OPENSHIFT_MYSQL_DB_PORT")
		mysql += ")/" + os.Getenv("OPENSHIFT_MYSQL_DB_NAME")
		orm, err = xorm.NewEngine("mysql", mysql)
	} else {
		orm, err = xorm.NewEngine("sqlite3", ":memory:")
	}

	if err != nil {
		return err
	}

	// Migrate our database if needed
	err = orm.Sync(new(ClientRequest))
	if err != nil {
		return fmt.Errorf("ClientRequest: %s", err)
	}
	err = orm.Sync(new(Domain))
	if err != nil {
		return fmt.Errorf("Domain: %s", err)
	}
	err = orm.Sync(new(Payment))
	if err != nil {
		return fmt.Errorf("Payment: %s", err)
	}

	return nil
}
<|endoftext|>


<commit_before>package tools

import (
	_ "github.com/golang/protobuf/protoc-gen-go"
	_ "github.com/matryer/moq"
	_ "github.com/pressly/goose/v3/cmd/goose"
	_ "github.com/twitchtv/twirp/protoc-gen-twirp"
	_ "github.com/volatiletech/sqlboiler/v4"
	_ "github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-mysql"
	_ "github.com/99designs/gqlgen"
)
<commit_msg>Add build tag<commit_after>//go:build tools
// +build tools

package tools

import (
	_ "github.com/99designs/gqlgen"
	_ "github.com/golang/protobuf/protoc-gen-go"
	_ "github.com/matryer/moq"
	_ "github.com/pressly/goose/v3/cmd/goose"
	_ "github.com/twitchtv/twirp/protoc-gen-twirp"
	_ "github.com/volatiletech/sqlboiler/v4"
	_ "github.com/volatiletech/sqlboiler/v4/drivers/sqlboiler-mysql"
)
<|endoftext|>


<commit_before>package elasticthought

import (
	"fmt"
	"net/http"
	"net/url"
	"path"

	"github.com/couchbaselabs/logg"
	"github.com/tleyden/cbfs/client"
	"github.com/tleyden/go-couch"
)

// A Datafile is a raw "bundle" of data, typically a zip or .tar.gz file.
// It cannot be used by a solver directly, instead it used to create
// dataset objects which can be used by the solver.
// A single datafile can be used to create any number of dataset objects.
type Datafile struct {
	ElasticThoughtDoc
	ProcessingState ProcessingState   `json:"processing-state"`
	ProcessingLog   string            `json:"processing-log"`
	UserID          string            `json:"user-id"`
	Url             string            `json:"url" binding:"required"`
	LayersType      string            `json:"layers_type" binding:"required"`
	LayersDataParam map[string]string `json:"layers_data_param"`

	// had to make exported, due to https://github.com/gin-gonic/gin/pull/123
	// waiting for this to get merged into master branch, since go get
	// pulls from master branch.
	Configuration Configuration
}

// Create a new datafile
func NewDatafile(c Configuration) *Datafile {
	return &Datafile{
		ElasticThoughtDoc: ElasticThoughtDoc{Type: DOC_TYPE_DATAFILE},
		Configuration:     c,
	}
}

// Find Datafile by Id from the db
func FindDatafile(db couch.Database, datafileId string) (*Datafile, error) {

	datafile := &Datafile{}
	if err := db.Retrieve(datafileId, datafile); err != nil {
		return nil, err
	}
	return datafile, nil

}

// Save a new version of Datafile to the db
func (d Datafile) Save(db couch.Database) (*Datafile, error) {

	idToRetrieve := ""

	switch d.HasValidId() {
	case true:
		logg.LogTo("MODEL", "calling db.Edit()")
		_, err := db.Edit(d)
		if err != nil {
			return nil, err
		}
		idToRetrieve = d.Id
	default:
		logg.LogTo("MODEL", "calling db.Insert()")
		id, _, err := db.Insert(d)
		if err != nil {
			return nil, err
		}
		idToRetrieve = id
	}

	// load latest version from db to get the _id and _rev fields
	datafile := &Datafile{}
	err := db.Retrieve(idToRetrieve, datafile)
	if err != nil {
		return nil, err
	}

	return datafile, nil

}

// Mark this datafile as having finished processing succesfully
func (d Datafile) FinishedSuccessfully(db couch.Database) error {

	_, err := d.UpdateProcessingState(FinishedSuccessfully)
	if err != nil {
		return err
	}

	return nil

}

// Update the dataset state to record that it failed
// Codereview: datafile.go has same method
func (d Datafile) Failed(db couch.Database, processingErr error) error {

	_, err := d.UpdateProcessingState(Failed)
	if err != nil {
		return err
	}

	return nil

}

// Update the processing state to new state.
func (d *Datafile) UpdateProcessingState(newState ProcessingState) (bool, error) {

	updater := func(datafile *Datafile) {
		datafile.ProcessingState = newState
	}

	doneMetric := func(datafile Datafile) bool {
		return datafile.ProcessingState == newState
	}

	return d.casUpdate(updater, doneMetric)

}

// Does this datafile have a valid Id?
func (d Datafile) HasValidId() bool {
	return len(d.Id) > 0
}

// Copy the contents of Datafile.Url to CBFS and return the cbfs dest path
func (d Datafile) CopyToCBFS(db couch.Database, cbfs *cbfsclient.Client) (string, error) {

	if !d.HasValidId() {
		errMsg := fmt.Errorf("Datafile: %+v must have an id", d)
		logg.LogError(errMsg)
		return "", errMsg
	}

	if len(d.Url) == 0 {
		errMsg := fmt.Errorf("Datafile: %+v must have a non empty url", d)
		logg.LogError(errMsg)
		return "", errMsg
	}

	logg.LogTo("MODEL", "datafile url: |%v|", d.Url)

	// figure out dest path to save to on cbfs
	u, err := url.Parse(d.Url)
	if err != nil {
		errMsg := fmt.Errorf("Error parsing: %v. Err %v", d.Url, err)
		logg.LogError(errMsg)
		return "", errMsg
	}
	urlPath := u.Path
	_, filename := path.Split(urlPath)
	destPath := fmt.Sprintf("%v/%v", d.Id, filename)

	// open input stream to url
	resp, err := http.Get(d.Url)
	if err != nil {
		errMsg := fmt.Errorf("Error opening: %v. Err %v", d.Url, err)
		logg.LogError(errMsg)
		return "", errMsg
	}
	defer resp.Body.Close()

	// write to cbfs
	options := cbfsclient.PutOptions{
		ContentType: resp.Header.Get("Content-Type"),
	}
	if err := cbfs.Put("", destPath, resp.Body, options); err != nil {
		errMsg := fmt.Errorf("Error writing %v to cbfs: %v", destPath, err)
		logg.LogError(errMsg)
		return "", errMsg
	}

	logg.LogTo("MODEL", "copied datafile url %v to cbfs: %v", d.Url, destPath)

	return destPath, nil

}

func (d *Datafile) casUpdate(updater func(*Datafile), doneMetric func(Datafile) bool) (bool, error) {

	db := d.Configuration.DbConnection()

	genUpdater := func(datafilePtr interface{}) {
		cjp := datafilePtr.(*Datafile)
		updater(cjp)
	}

	genDoneMetric := func(datafilePtr interface{}) bool {
		cjp := datafilePtr.(*Datafile)
		return doneMetric(*cjp)
	}

	refresh := func(datafilePtr interface{}) error {
		cjp := datafilePtr.(*Datafile)
		return cjp.RefreshFromDB(db)
	}

	return casUpdate(db, d, genUpdater, genDoneMetric, refresh)

}

func (d *Datafile) GetProcessingState() ProcessingState {
	return d.ProcessingState
}

func (d *Datafile) SetProcessingState(newState ProcessingState) {
	d.ProcessingState = newState
}

func (d *Datafile) RefreshFromDB(db couch.Database) error {
	datafile := Datafile{}
	err := db.Retrieve(d.Id, &datafile)
	if err != nil {
		logg.LogTo("MODEL", "Error getting latest: %v", err)
		return err
	}
	*d = datafile
	return nil
}
<commit_msg>Revert "ability to process mnist leveldb files, in progress"<commit_after>package elasticthought

import (
	"fmt"
	"net/http"
	"net/url"
	"path"

	"github.com/couchbaselabs/logg"
	"github.com/tleyden/cbfs/client"
	"github.com/tleyden/go-couch"
)

// A Datafile is a raw "bundle" of data, typically a zip or .tar.gz file.
// It cannot be used by a solver directly, instead it used to create
// dataset objects which can be used by the solver.
// A single datafile can be used to create any number of dataset objects.
type Datafile struct {
	ElasticThoughtDoc
	ProcessingState ProcessingState `json:"processing-state"`
	ProcessingLog   string          `json:"processing-log"`
	UserID          string          `json:"user-id"`
	Url             string          `json:"url" binding:"required"`

	// had to make exported, due to https://github.com/gin-gonic/gin/pull/123
	// waiting for this to get merged into master branch, since go get
	// pulls from master branch.
	Configuration Configuration
}

// Create a new datafile
func NewDatafile(c Configuration) *Datafile {
	return &Datafile{
		ElasticThoughtDoc: ElasticThoughtDoc{Type: DOC_TYPE_DATAFILE},
		Configuration:     c,
	}
}

// Find Datafile by Id from the db
func FindDatafile(db couch.Database, datafileId string) (*Datafile, error) {

	datafile := &Datafile{}
	if err := db.Retrieve(datafileId, datafile); err != nil {
		return nil, err
	}
	return datafile, nil

}

// Save a new version of Datafile to the db
func (d Datafile) Save(db couch.Database) (*Datafile, error) {

	idToRetrieve := ""

	switch d.HasValidId() {
	case true:
		logg.LogTo("MODEL", "calling db.Edit()")
		_, err := db.Edit(d)
		if err != nil {
			return nil, err
		}
		idToRetrieve = d.Id
	default:
		logg.LogTo("MODEL", "calling db.Insert()")
		id, _, err := db.Insert(d)
		if err != nil {
			return nil, err
		}
		idToRetrieve = id
	}

	// load latest version from db to get the _id and _rev fields
	datafile := &Datafile{}
	err := db.Retrieve(idToRetrieve, datafile)
	if err != nil {
		return nil, err
	}

	return datafile, nil

}

// Mark this datafile as having finished processing succesfully
func (d Datafile) FinishedSuccessfully(db couch.Database) error {

	_, err := d.UpdateProcessingState(FinishedSuccessfully)
	if err != nil {
		return err
	}

	return nil

}

// Update the dataset state to record that it failed
// Codereview: datafile.go has same method
func (d Datafile) Failed(db couch.Database, processingErr error) error {

	_, err := d.UpdateProcessingState(Failed)
	if err != nil {
		return err
	}

	return nil

}

// Update the processing state to new state.
func (d *Datafile) UpdateProcessingState(newState ProcessingState) (bool, error) {

	updater := func(datafile *Datafile) {
		datafile.ProcessingState = newState
	}

	doneMetric := func(datafile Datafile) bool {
		return datafile.ProcessingState == newState
	}

	return d.casUpdate(updater, doneMetric)

}

// Does this datafile have a valid Id?
func (d Datafile) HasValidId() bool {
	return len(d.Id) > 0
}

// Copy the contents of Datafile.Url to CBFS and return the cbfs dest path
func (d Datafile) CopyToCBFS(db couch.Database, cbfs *cbfsclient.Client) (string, error) {

	if !d.HasValidId() {
		errMsg := fmt.Errorf("Datafile: %+v must have an id", d)
		logg.LogError(errMsg)
		return "", errMsg
	}

	if len(d.Url) == 0 {
		errMsg := fmt.Errorf("Datafile: %+v must have a non empty url", d)
		logg.LogError(errMsg)
		return "", errMsg
	}

	logg.LogTo("MODEL", "datafile url: |%v|", d.Url)

	// figure out dest path to save to on cbfs
	u, err := url.Parse(d.Url)
	if err != nil {
		errMsg := fmt.Errorf("Error parsing: %v. Err %v", d.Url, err)
		logg.LogError(errMsg)
		return "", errMsg
	}
	urlPath := u.Path
	_, filename := path.Split(urlPath)
	destPath := fmt.Sprintf("%v/%v", d.Id, filename)

	// open input stream to url
	resp, err := http.Get(d.Url)
	if err != nil {
		errMsg := fmt.Errorf("Error opening: %v. Err %v", d.Url, err)
		logg.LogError(errMsg)
		return "", errMsg
	}
	defer resp.Body.Close()

	// write to cbfs
	options := cbfsclient.PutOptions{
		ContentType: resp.Header.Get("Content-Type"),
	}
	if err := cbfs.Put("", destPath, resp.Body, options); err != nil {
		errMsg := fmt.Errorf("Error writing %v to cbfs: %v", destPath, err)
		logg.LogError(errMsg)
		return "", errMsg
	}

	logg.LogTo("MODEL", "copied datafile url %v to cbfs: %v", d.Url, destPath)

	return destPath, nil

}

func (d *Datafile) casUpdate(updater func(*Datafile), doneMetric func(Datafile) bool) (bool, error) {

	db := d.Configuration.DbConnection()

	genUpdater := func(datafilePtr interface{}) {
		cjp := datafilePtr.(*Datafile)
		updater(cjp)
	}

	genDoneMetric := func(datafilePtr interface{}) bool {
		cjp := datafilePtr.(*Datafile)
		return doneMetric(*cjp)
	}

	refresh := func(datafilePtr interface{}) error {
		cjp := datafilePtr.(*Datafile)
		return cjp.RefreshFromDB(db)
	}

	return casUpdate(db, d, genUpdater, genDoneMetric, refresh)

}

func (d *Datafile) GetProcessingState() ProcessingState {
	return d.ProcessingState
}

func (d *Datafile) SetProcessingState(newState ProcessingState) {
	d.ProcessingState = newState
}

func (d *Datafile) RefreshFromDB(db couch.Database) error {
	datafile := Datafile{}
	err := db.Retrieve(d.Id, &datafile)
	if err != nil {
		logg.LogTo("MODEL", "Error getting latest: %v", err)
		return err
	}
	*d = datafile
	return nil
}
<|endoftext|>


<commit_before>package types

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// DateTime хранит дату-время и шаблон для преобразования при сериализации
type DateTime struct {
	time.Time
	Layout string
}

// Date хранит дату и шаблон для преобразования при сериализации
type Date struct {
	time.Time
	Layout string
}

// Шаблоны для сериализации
const (
	DateTimeLayout        = "2006-01-02 15:04:05"
	DateLayout            = "2006-01-02"
	GraphsDateLayout      = "02.01.2006"
	GraphsDateShortLayout = "02.01"
)

var defaultLocation *time.Location

// Задаёт часовой пояс по умолчанию
func init() {
	var err error
	defaultLocation, err = time.LoadLocation("Europe/Moscow")
	if err != nil {
		fmt.Println("Ошибка time.LoadLocation")
	}
}

// ToDateTime формирует объект типа DateTime на основе времени t и шаблона DateTimeLayout
func ToDateTime(t time.Time) DateTime {
	return DateTime{t.In(defaultLocation), DateTimeLayout}
}

// ToDate формирует объект типа Date на основе времени t и шаблона DateLayout
func ToDate(t time.Time) Date {
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), 0, 0, 0)
	d, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	return Date{d.In(defaultLocation), DateLayout}
}

// DaysBefore возвращает количество полных дней, прошедших от d до endDate
// Например, если d было вчера, endDate - сегодня, то возвращается 1
// Если endDate было раньше чем d, то возвращается отрицательное число.
func (d Date) DaysBefore(endDate Date) int {
	return int(endDate.Time.Sub(d.Time).Hours() / 24)
}

// StringToDateTime формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout
func StringToDateTime(s string) (DateTime, error) {
	t, err := time.ParseInLocation(DateTimeLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	return ToDateTime(t), nil
}

// StringDateToDateTimeHMS формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout, и значений часов, минут и секунд,
// заданных параметрами hours, mins, secs соответственно.
func StringDateToDateTimeHMS(s string, hours int, mins int, secs int) (DateTime, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	d := ToDateTime(t)
	d = d.SetHMS(hours, mins, secs)
	return d, nil
}

// StringToDate формирует объект типа Date на основе строки s, заданной по шаблону DateLayout
func StringToDate(s string) (Date, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return Date{}, err
	}
	return ToDate(t), nil
}

// NeverDate возвращает объект Date, соответствующий дате в далёком прошлом
func NeverDate() Date {
	t, _ := time.ParseInLocation(DateLayout, "1990-01-01", defaultLocation)
	return ToDate(t)
}

// DateNow возвращает объект Date, соответствующий дате сегодня
func DateNow() Date {
	return ToDate(time.Now())
}

// DateTimeNow возвращает объект DateTime, соответствующий дате-времени сейчас
func DateTimeNow() DateTime {
	return ToDateTime(time.Now())
}

// DateTimeTodayHMS возвращает объект DateTime, соответствующий дате сегодня,
// с установленными значениями часов, минут, секунд согласно заданным параметрам
// hours, mins, secs соответственно.
func DateTimeTodayHMS(hours int, mins int, secs int) DateTime {
	d := ToDateTime(time.Now())
	return d.SetHMS(hours, mins, secs)
}

// NeverTime возвращает объект DateTime, соответствующий дате-времени в далёком прошлом
func NeverTime() DateTime {
	t, _ := time.ParseInLocation(DateTimeLayout, "1990-01-01 00:00:00", defaultLocation)
	return ToDateTime(t)
}

// setDefaultLayoutIfEmpty устанавливает в объекте DateTime шаблон вывода даты-времени
// по умолчанию DateTimeLayout, если шаблон не установлен
func (d *DateTime) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateTimeLayout
	}
}

// setDefaultLayoutIfEmpty устанавливает в объекте Date шаблон вывода даты
// по умолчанию DateLayout, если шаблон не установлен
func (d *Date) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateLayout
	}
}

// SetHMS возвращает новый объект DateTime на основе объекта d,
// с заданными значениями часов, минут, секунд в параметрах
// hours, mins, secs соответственно.
func (d DateTime) SetHMS(hours int, mins int, secs int) DateTime {
	t := d.Time
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), hours, mins, secs)
	dt, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	d.Time = dt
	return d
}

// ConvertToDate преобразует объект DateTime в объект Date
func (d DateTime) ConvertToDate() Date {
	dS := d.Time.Format(DateLayout)
	t, _ := time.ParseInLocation(DateLayout, dS, defaultLocation)
	return ToDate(t)
}

// ConvertToDateTimeHMS преобразует объект Date в объект DateTime
// с учётом заданных часов, минут, секунд в параметрах hours, mind, secs соответственно.
func (d Date) ConvertToDateTimeHMS(hours int, mins int, secs int) DateTime {
	dt := DateTime{
		Time:   d.Time,
		Layout: d.Layout,
	}
	dt = dt.SetHMS(hours, mins, secs)

	return dt
}

// After возвращает true если дата d позднее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) After(d1 Date) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата d ранее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Before(d1 Date) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата d находится в интервале дат (d1; d2), иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Between(d1, d2 Date) bool {
	return d.After(d1) && d.Before(d2)
}

// After возвращает true если дата-время d позднее d1, иначе false
func (d DateTime) After(d1 DateTime) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата-время d ранее d1, иначе false
func (d DateTime) Before(d1 DateTime) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата-время d находится в интервале
// даты-времени (d1; d2), иначе false
func (d DateTime) Between(d1, d2 DateTime) bool {
	return d.After(d1) && d.Before(d2)
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта DateTime
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *DateTime) UnmarshalJSON(data []byte) error {
	d.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта DateTime
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d DateTime) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта Date
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *Date) UnmarshalJSON(data []byte) error {
	d.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта Date
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d Date) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// String преобразует объект DateTime в строку согласно шаблона в свойстве Layout
func (d DateTime) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

// String преобразует объект Date в строку согласно шаблона в свойстве Layout
func (d Date) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

func scan(value interface{}) (time.Time, error) {
	t := time.Time{}
	if value == nil {
		return t, nil
	}
	t, ok := value.(time.Time)
	if !ok {
		return t, errors.New("Ошибка преобразования значения к типу time.Time")
	}
	return t.In(defaultLocation), nil
}

// Scan преобразует значение времени в БД к типу DateTime
func (d *DateTime) Scan(value interface{}) error {
	d.setDefaultLayoutIfEmpty()
	t, err := scan(value)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// Value преобразует значение типа DateTime к значению в БД
func (d DateTime) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateTimeLayout), nil
}

// Scan преобразует значение времени в БД к типу Date
func (d *Date) Scan(value interface{}) error {
	d.setDefaultLayoutIfEmpty()
	t, err := scanInternal(value)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// Value преобразует значение типа Date к значению в БД
func (d Date) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateLayout), nil
}
<commit_msg>Добавил пару комментов<commit_after>package types

import (
	"database/sql/driver"
	"encoding/json"
	"errors"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// DateTime хранит дату-время и шаблон для преобразования при сериализации
type DateTime struct {
	time.Time
	Layout string
}

// Date хранит дату и шаблон для преобразования при сериализации
type Date struct {
	time.Time
	Layout string
}

// Шаблоны для сериализации
const (
	DateTimeLayout        = "2006-01-02 15:04:05"
	DateLayout            = "2006-01-02"
	GraphsDateLayout      = "02.01.2006"
	GraphsDateShortLayout = "02.01"
)

var defaultLocation *time.Location

// Задаёт часовой пояс по умолчанию
func init() {
	var err error
	defaultLocation, err = time.LoadLocation("Europe/Moscow")
	if err != nil {
		fmt.Println("Ошибка time.LoadLocation")
	}
}

// ToDateTime формирует объект типа DateTime на основе времени t и шаблона DateTimeLayout
func ToDateTime(t time.Time) DateTime {
	return DateTime{t.In(defaultLocation), DateTimeLayout}
}

// ToDate формирует объект типа Date на основе времени t и шаблона DateLayout
func ToDate(t time.Time) Date {
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), 0, 0, 0)
	d, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	return Date{d.In(defaultLocation), DateLayout}
}

// DaysBefore возвращает количество полных дней, прошедших от d до endDate
// Например, если d было вчера, endDate - сегодня, то возвращается 1
// Если endDate было раньше чем d, то возвращается отрицательное число.
func (d Date) DaysBefore(endDate Date) int {
	return int(endDate.Time.Sub(d.Time).Hours() / 24)
}

// StringToDateTime формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout
func StringToDateTime(s string) (DateTime, error) {
	t, err := time.ParseInLocation(DateTimeLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	return ToDateTime(t), nil
}

// StringDateToDateTimeHMS формирует объект типа DateTime на основе строки s,
// заданной по шаблону DateTimeLayout, и значений часов, минут и секунд,
// заданных параметрами hours, mins, secs соответственно.
func StringDateToDateTimeHMS(s string, hours int, mins int, secs int) (DateTime, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return DateTime{}, err
	}
	d := ToDateTime(t)
	d = d.SetHMS(hours, mins, secs)
	return d, nil
}

// StringToDate формирует объект типа Date на основе строки s, заданной по шаблону DateLayout
func StringToDate(s string) (Date, error) {
	t, err := time.ParseInLocation(DateLayout, s, defaultLocation)
	if err != nil {
		return Date{}, err
	}
	return ToDate(t), nil
}

// NeverDate возвращает объект Date, соответствующий дате в далёком прошлом
func NeverDate() Date {
	t, _ := time.ParseInLocation(DateLayout, "1990-01-01", defaultLocation)
	return ToDate(t)
}

// DateNow возвращает объект Date, соответствующий дате сегодня
func DateNow() Date {
	return ToDate(time.Now())
}

// DateTimeNow возвращает объект DateTime, соответствующий дате-времени сейчас
func DateTimeNow() DateTime {
	return ToDateTime(time.Now())
}

// DateTimeTodayHMS возвращает объект DateTime, соответствующий дате сегодня,
// с установленными значениями часов, минут, секунд согласно заданным параметрам
// hours, mins, secs соответственно.
func DateTimeTodayHMS(hours int, mins int, secs int) DateTime {
	d := ToDateTime(time.Now())
	return d.SetHMS(hours, mins, secs)
}

// NeverTime возвращает объект DateTime, соответствующий дате-времени в далёком прошлом
func NeverTime() DateTime {
	t, _ := time.ParseInLocation(DateTimeLayout, "1990-01-01 00:00:00", defaultLocation)
	return ToDateTime(t)
}

// setDefaultLayoutIfEmpty устанавливает в объекте DateTime шаблон вывода даты-времени
// по умолчанию DateTimeLayout, если шаблон не установлен
func (d *DateTime) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateTimeLayout
	}
}

// setDefaultLayoutIfEmpty устанавливает в объекте Date шаблон вывода даты
// по умолчанию DateLayout, если шаблон не установлен
func (d *Date) setDefaultLayoutIfEmpty() {
	if strings.TrimSpace(d.Layout) == "" {
		d.Layout = DateLayout
	}
}

// SetHMS возвращает новый объект DateTime на основе объекта d,
// с заданными значениями часов, минут, секунд в параметрах
// hours, mins, secs соответственно.
func (d DateTime) SetHMS(hours int, mins int, secs int) DateTime {
	t := d.Time
	dS := fmt.Sprintf("%s %02d:%02d:%02d", t.Format(DateLayout), hours, mins, secs)
	dt, _ := time.ParseInLocation(DateTimeLayout, dS, defaultLocation)
	d.Time = dt
	return d
}

// ConvertToDate преобразует объект DateTime в объект Date
func (d DateTime) ConvertToDate() Date {
	dS := d.Time.Format(DateLayout)
	t, _ := time.ParseInLocation(DateLayout, dS, defaultLocation)
	return ToDate(t)
}

// ConvertToDateTimeHMS преобразует объект Date в объект DateTime
// с учётом заданных часов, минут, секунд в параметрах hours, mind, secs соответственно.
func (d Date) ConvertToDateTimeHMS(hours int, mins int, secs int) DateTime {
	dt := DateTime{
		Time:   d.Time,
		Layout: d.Layout,
	}
	dt = dt.SetHMS(hours, mins, secs)

	return dt
}

// After возвращает true если дата d позднее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) After(d1 Date) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата d ранее d1, иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Before(d1 Date) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата d находится в интервале дат (d1; d2), иначе false
// Сравнение происходит с точностью до дня.
func (d Date) Between(d1, d2 Date) bool {
	return d.After(d1) && d.Before(d2)
}

// After возвращает true если дата-время d позднее d1, иначе false
func (d DateTime) After(d1 DateTime) bool {
	return d.Time.After(d1.Time)
}

// Before возвращает true если дата-время d ранее d1, иначе false
func (d DateTime) Before(d1 DateTime) bool {
	return d.Time.Before(d1.Time)
}

// Between возвращает true если дата-время d находится в интервале
// даты-времени (d1; d2), иначе false
func (d DateTime) Between(d1, d2 DateTime) bool {
	return d.After(d1) && d.Before(d2)
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта DateTime
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *DateTime) UnmarshalJSON(data []byte) error {
	d.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта DateTime
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d DateTime) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// UnmarshalJSON - реализует интерфейс json.Unmarshaler для объекта Date
// десериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d *Date) UnmarshalJSON(data []byte) error {
	d.setDefaultLayoutIfEmpty()
	var s string
	if err := json.Unmarshal(data, &s); err != nil {
		return err
	}
	t, err := time.ParseInLocation(d.Layout, s, defaultLocation)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// MarshalJSON - реализует интерфейс json.Marshaler для объекта Date
// сериализация происходит с учётом шаблона, заданного в свойстве Layout
func (d Date) MarshalJSON() ([]byte, error) {
	d.setDefaultLayoutIfEmpty()
	return []byte(strconv.Quote(d.String())), nil
}

// String преобразует объект DateTime в строку согласно шаблона в свойстве Layout
func (d DateTime) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

// String преобразует объект Date в строку согласно шаблона в свойстве Layout
func (d Date) String() string {
	d.setDefaultLayoutIfEmpty()
	return d.Time.Format(d.Layout)
}

func scan(value interface{}) (time.Time, error) {
	t := time.Time{}
	if value == nil {
		return t, nil
	}
	t, ok := value.(time.Time)
	if !ok {
		return t, errors.New("Ошибка преобразования значения к типу time.Time")
	}
	return t.In(defaultLocation), nil
}

// Scan преобразует значение времени в БД к типу DateTime
// Реализует интерфейс sql.Scanner
func (d *DateTime) Scan(value interface{}) error {
	d.setDefaultLayoutIfEmpty()
	t, err := scan(value)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// Value преобразует значение типа DateTime к значению в БД
// Реализует интерфейс driver.Valuer
func (d DateTime) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateTimeLayout), nil
}

// Scan преобразует значение времени в БД к типу Date
// Реализует интерфейс sql.Scanner
func (d *Date) Scan(value interface{}) error {
	d.setDefaultLayoutIfEmpty()
	t, err := scanInternal(value)
	if err != nil {
		return err
	}
	d.Time = t
	return nil
}

// Value преобразует значение типа Date к значению в БД
// Реализует интерфейс driver.Valuer
func (d Date) Value() (driver.Value, error) {
	return d.Time.In(defaultLocation).Format(DateLayout), nil
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// Convenient function to exec a command.
func cmd(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// Convenient function to launch VBoxManage.
func vbm(args ...string) error {
	return cmd(B2D.VBM, args...)
}

// Get the state of a VM.
func status(vm string) vmState {
	// Check if the VM exists.
	out, err := exec.Command(B2D.VBM, "list", "vms").Output()
	if err != nil {
		return vmUnknown
	}
	found, err := regexp.Match(fmt.Sprintf(`(?m)^"%s"`, regexp.QuoteMeta(vm)), out)
	if err != nil {
		return vmUnknown
	}
	if !found {
		return vmUnregistered
	}

	if out, err = exec.Command(B2D.VBM, "showvminfo", vm, "--machinereadable").Output(); err != nil {
		return vmUnknown
	}
	groups := regexp.MustCompile(`(?m)^VMState="(\w+)"$`).FindSubmatch(out)
	if len(groups) < 2 {
		return vmUnknown
	}
	switch state := vmState(groups[1]); state {
	case vmRunning, vmPaused, vmSaved, vmPoweroff, vmAborted:
		return state
	default:
		return vmUnknown
	}
}

// Make a boot2docker VM disk image.
func makeDiskImage(dest string, size int) error {
	// Create the dest dir.
	if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
		return err
	}
	cmd := exec.Command(B2D.VBM, "convertfromraw", "stdin", dest, fmt.Sprintf("%d", size*1024*1024), "--format", "VMDK")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	w, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	// Write the magic string so the VM auto-formats the disk upon first boot.
	if _, err := w.Write([]byte("boot2docker, please format-me")); err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}

	return cmd.Run()
}
<commit_msg>Regexp multiline matches optional carriage return<commit_after>package main

import (
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
)

// Convenient function to exec a command.
func cmd(name string, args ...string) error {
	cmd := exec.Command(name, args...)
	cmd.Stdin = os.Stdin
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	return cmd.Run()
}

// Convenient function to launch VBoxManage.
func vbm(args ...string) error {
	return cmd(B2D.VBM, args...)
}

// Get the state of a VM.
func status(vm string) vmState {
	// Check if the VM exists.
	out, err := exec.Command(B2D.VBM, "list", "vms").Output()
	if err != nil {
		return vmUnknown
	}
	found, err := regexp.Match(fmt.Sprintf(`(?m)^"%s"`, regexp.QuoteMeta(vm)), out)
	if err != nil {
		return vmUnknown
	}
	if !found {
		return vmUnregistered
	}

	if out, err = exec.Command(B2D.VBM, "showvminfo", vm, "--machinereadable").Output(); err != nil {
		return vmUnknown
	}
	groups := regexp.MustCompile(`(?m)^VMState="(\w+)"\r?$`).FindSubmatch(out)
	if len(groups) < 2 {
		return vmUnknown
	}
	switch state := vmState(groups[1]); state {
	case vmRunning, vmPaused, vmSaved, vmPoweroff, vmAborted:
		return state
	default:
		return vmUnknown
	}
}

// Make a boot2docker VM disk image.
func makeDiskImage(dest string, size int) error {
	// Create the dest dir.
	if err := os.MkdirAll(filepath.Dir(dest), 0755); err != nil {
		return err
	}
	cmd := exec.Command(B2D.VBM, "convertfromraw", "stdin", dest, fmt.Sprintf("%d", size*1024*1024), "--format", "VMDK")
	cmd.Stdout = os.Stdout
	cmd.Stderr = os.Stderr
	w, err := cmd.StdinPipe()
	if err != nil {
		return err
	}
	// Write the magic string so the VM auto-formats the disk upon first boot.
	if _, err := w.Write([]byte("boot2docker, please format-me")); err != nil {
		return err
	}
	if err := w.Close(); err != nil {
		return err
	}

	return cmd.Run()
}
<|endoftext|>


<commit_before>// Package chunk implements functions for finding useful chunks in text previously tagged from parts of speech.
//
package chunk

import (
	"regexp"

	"github.com/jdkato/prose/tag"
)

// quadString creates a string containing all of the tags, each padded to 4 characters wide.
func quadsString(tagged []tag.Token) string {
	tagQuads := ""
	for _, tok := range tagged {
		padding := ""
		tag := tok.Tag
		switch len(tag) {
		case 0:
			padding = "____" // should not exist
		case 1:
			padding = "___"
		case 2:
			padding = "__"
		case 3:
			padding = "_"
		case 4: // no padding required
		default:
			tag = tag[:4] // longer than 4 ... truncate!
		}
		tagQuads += tag + padding
	}
	return tagQuads
}

// TreebankNamedEntities matches proper names, including prior adjectives,
// possibly including numbers, and possibly including a linkage by preposition
// or subordinating conjunctions (for example "Bank of England").
var TreebankNamedEntities = regexp.MustCompile(
	// at least one proper noun, maybe preceded by an adjective and/or number
	`((JJ._)*(CD__)*(NNP.)+(CD__|NNP.)*)+` +
		// then zero or more subordinated noun phrases
		`((IN__)*(JJ._)*(CD__)*(NNP.)+(CD__|NNP.)*)*`)

// Chunk returns a slice containing the chunks of interest according to the
// regexp.
//
// This is a convenience wrapper around Locate, which should be used if you
// need access the to the in-text locations of each chunk.
func Chunk(tagged []tag.Token, rx *regexp.Regexp) []string {
	chunks := []string{}
	for _, loc := range Locate(tagged, TreebankNamedEntities) {
		res := ""
		for t, tt := range tagged[loc[0]:loc[1]] {
			if t != 0 {
				res += " "
			}
			res += tt.Text
		}
		chunks = append(chunks, res)
	}
	return chunks
}

// Locate finds the chunks of interest according to the regexp.
func Locate(tagged []tag.Token, rx *regexp.Regexp) [][]int {
	rx.Longest() // make sure we find the longest possible sequences
	rs := rx.FindAllStringIndex(quadsString(tagged), -1)
	for i, ii := range rs {
		for j := range ii {
			// quadsString makes every offset 4x what it should be
			rs[i][j] /= 4
		}
	}
	return rs
}
<commit_msg>Fix incorrect reference to TreebankNamedEntities<commit_after>// Package chunk implements functions for finding useful chunks in text previously tagged from parts of speech.
//
package chunk

import (
	"regexp"

	"github.com/jdkato/prose/tag"
)

// quadString creates a string containing all of the tags, each padded to 4 characters wide.
func quadsString(tagged []tag.Token) string {
	tagQuads := ""
	for _, tok := range tagged {
		padding := ""
		tag := tok.Tag
		switch len(tag) {
		case 0:
			padding = "____" // should not exist
		case 1:
			padding = "___"
		case 2:
			padding = "__"
		case 3:
			padding = "_"
		case 4: // no padding required
		default:
			tag = tag[:4] // longer than 4 ... truncate!
		}
		tagQuads += tag + padding
	}
	return tagQuads
}

// TreebankNamedEntities matches proper names, including prior adjectives,
// possibly including numbers, and possibly including a linkage by preposition
// or subordinating conjunctions (for example "Bank of England").
var TreebankNamedEntities = regexp.MustCompile(
	// at least one proper noun, maybe preceded by an adjective and/or number
	`((JJ._)*(CD__)*(NNP.)+(CD__|NNP.)*)+` +
		// then zero or more subordinated noun phrases
		`((IN__)*(JJ._)*(CD__)*(NNP.)+(CD__|NNP.)*)*`)

// Chunk returns a slice containing the chunks of interest according to the
// regexp.
//
// This is a convenience wrapper around Locate, which should be used if you
// need access the to the in-text locations of each chunk.
func Chunk(tagged []tag.Token, rx *regexp.Regexp) []string {
	chunks := []string{}
	for _, loc := range Locate(tagged, rx) {
		res := ""
		for t, tt := range tagged[loc[0]:loc[1]] {
			if t != 0 {
				res += " "
			}
			res += tt.Text
		}
		chunks = append(chunks, res)
	}
	return chunks
}

// Locate finds the chunks of interest according to the regexp.
func Locate(tagged []tag.Token, rx *regexp.Regexp) [][]int {
	rx.Longest() // make sure we find the longest possible sequences
	rs := rx.FindAllStringIndex(quadsString(tagged), -1)
	for i, ii := range rs {
		for j := range ii {
			// quadsString makes every offset 4x what it should be
			rs[i][j] /= 4
		}
	}
	return rs
}
<|endoftext|>


<commit_before>package bot

import (
	"fmt"
	"regexp"
	"time"
)

const runJobRegex = `run +job +(` + identifierRegex + `)`

var runJobRe = regexp.MustCompile(`(?i:^\s*` + runJobRegex + `\s*$)`)

// checkJobMatchersAndRun handles triggers, 'run job <foo>', 'history <foo>'
func (bot *botContext) checkJobMatchersAndRun() (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	var runTask interface{}
	var triggerArgs []string
	// First, check triggers
	for _, t := range bot.tasks.t {
		task, _, job := getTask(t)
		if job == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled job '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugT(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking triggers for job '%s'", task.name))
		triggers := job.Triggers
		bot.debugT(t, fmt.Sprintf("Checking %d JobTriggers against message: '%s' from user '%s' in channel '%s'", len(triggers), bot.msg, bot.User, bot.Channel), false)
		for _, trigger := range triggers {
			Log(Trace, fmt.Sprintf("Checking '%s' against user '%s', channel '%s', regex: '%s'", bot.msg, trigger.User, trigger.Channel, trigger.Regex))
			if bot.User != trigger.User {
				bot.debugT(t, fmt.Sprintf("User '%s' doesn't match trigger user '%s'", bot.User, trigger.User), false)
				continue
			}
			if bot.Channel != trigger.Channel {
				bot.debugT(t, fmt.Sprintf("Channel '%s' doesn't match trigger", bot.Channel), false)
				continue
			}
			matches := trigger.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugT(t, fmt.Sprintf("Matched trigger regex '%s'", trigger.Regex), false)
				Log(Trace, fmt.Sprintf("Message '%s' matches trigger for job '%s'", bot.msg, task.name))
				matched = true
				bot.User = task.User
				triggerArgs = matches[0][1:]
			} else {
				bot.debugT(t, fmt.Sprintf("Not matched: %s", trigger.Regex), false)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' from user '%s' in channel '%s' matched triggers for multiple jobs: '%s' and '%s', ignoring", bot.msg, bot.User, bot.Channel, prevTask.name, task.name))
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				bot.Channel = task.Channel
				break
			}
		} // end of triggerer checking
	} // end of job trigger checking
	if messageMatched {
		r.messageHeard()
		robot.RLock()
		if robot.shuttingDown {
			r.Say("Ignoring triggered job: shutting down")
			robot.RUnlock()
			return
		} else if robot.paused {
			r.Say("Ignoring triggered job: paused")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Jobs triggers should only match apps / bots, not real users!
		bot.automaticTask = true
		bot.startPipeline(runTask, jobTrigger, "run", triggerArgs...)
		return
	}
	// Check for built-in run job
	var jobName string
	matches := runJobRe.FindAllStringSubmatch(bot.msg, -1)
	if matches != nil {
		jobName = matches[0][1]
	} else {
		return
	}
	t := bot.jobAvailable(jobName)
	if t != nil {
		// remember which job we're talking about
		ctx := memoryContext{"context:task", bot.User, bot.Channel}
		s := shortTermMemory{jobName, time.Now()}
		shortTermMemories.Lock()
		shortTermMemories.m[ctx] = s
		shortTermMemories.Unlock()

		bot.startPipeline(t, jobCmd, "run")
	} // jobAvailable sends a message if it's not
	return
}
<commit_msg>Collapse spaces for run job command<commit_after>package bot

import (
	"fmt"
	"regexp"
	"time"
)

const runJobRegex = `run +job +(` + identifierRegex + `)`

var runJobRe = regexp.MustCompile(`(?i:^\s*` + runJobRegex + `\s*$)`)

// checkJobMatchersAndRun handles triggers, 'run job <foo>', 'history <foo>'
func (bot *botContext) checkJobMatchersAndRun() (messageMatched bool) {
	r := bot.makeRobot()
	// un-needed, but more clear
	messageMatched = false
	var runTask interface{}
	var triggerArgs []string
	// First, check triggers
	for _, t := range bot.tasks.t {
		task, _, job := getTask(t)
		if job == nil {
			continue
		}
		if task.Disabled {
			msg := fmt.Sprintf("Skipping disabled job '%s', reason: %s", task.name, task.reason)
			Log(Trace, msg)
			bot.debugT(t, msg, false)
			continue
		}
		Log(Trace, fmt.Sprintf("Checking triggers for job '%s'", task.name))
		triggers := job.Triggers
		bot.debugT(t, fmt.Sprintf("Checking %d JobTriggers against message: '%s' from user '%s' in channel '%s'", len(triggers), bot.msg, bot.User, bot.Channel), false)
		for _, trigger := range triggers {
			Log(Trace, fmt.Sprintf("Checking '%s' against user '%s', channel '%s', regex: '%s'", bot.msg, trigger.User, trigger.Channel, trigger.Regex))
			if bot.User != trigger.User {
				bot.debugT(t, fmt.Sprintf("User '%s' doesn't match trigger user '%s'", bot.User, trigger.User), false)
				continue
			}
			if bot.Channel != trigger.Channel {
				bot.debugT(t, fmt.Sprintf("Channel '%s' doesn't match trigger", bot.Channel), false)
				continue
			}
			matches := trigger.re.FindAllStringSubmatch(bot.msg, -1)
			matched := false
			if matches != nil {
				bot.debugT(t, fmt.Sprintf("Matched trigger regex '%s'", trigger.Regex), false)
				Log(Trace, fmt.Sprintf("Message '%s' matches trigger for job '%s'", bot.msg, task.name))
				matched = true
				bot.User = task.User
				triggerArgs = matches[0][1:]
			} else {
				bot.debugT(t, fmt.Sprintf("Not matched: %s", trigger.Regex), false)
			}
			if matched {
				if messageMatched {
					prevTask, _, _ := getTask(runTask)
					Log(Error, fmt.Sprintf("Message '%s' from user '%s' in channel '%s' matched triggers for multiple jobs: '%s' and '%s', ignoring", bot.msg, bot.User, bot.Channel, prevTask.name, task.name))
					emit(MultipleMatchesNoAction)
					return
				}
				messageMatched = true
				runTask = t
				bot.Channel = task.Channel
				break
			}
		} // end of triggerer checking
	} // end of job trigger checking
	if messageMatched {
		r.messageHeard()
		robot.RLock()
		if robot.shuttingDown {
			r.Say("Ignoring triggered job: shutting down")
			robot.RUnlock()
			return
		} else if robot.paused {
			r.Say("Ignoring triggered job: paused")
			robot.RUnlock()
			return
		}
		robot.RUnlock()
		// Jobs triggers should only match apps / bots, not real users!
		bot.automaticTask = true
		bot.startPipeline(runTask, jobTrigger, "run", triggerArgs...)
		return
	}
	// Check for built-in run job
	var jobName string
	cmsg := spaceRe.ReplaceAllString(bot.msg, " ")
	matches := runJobRe.FindAllStringSubmatch(cmsg, -1)
	if matches != nil {
		jobName = matches[0][1]
	} else {
		return
	}
	t := bot.jobAvailable(jobName)
	if t != nil {
		// remember which job we're talking about
		ctx := memoryContext{"context:task", bot.User, bot.Channel}
		s := shortTermMemory{jobName, time.Now()}
		shortTermMemories.Lock()
		shortTermMemories.m[ctx] = s
		shortTermMemories.Unlock()

		bot.startPipeline(t, jobCmd, "run")
	} // jobAvailable sends a message if it's not
	return
}
<|endoftext|>


<commit_before>// Copyright 2018 Google 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
//
//     https://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 watchdog implements a simple watchdog timer which dumps a trace of
// all goroutines to a file, and then ends the program, if the timer reaches its
// limit.
package watchdog

import (
	"io/ioutil"
	"runtime/pprof"
	"time"

	log "github.com/golang/glog"
)

type Watchdog struct {
	dir      string
	prefix   string
	duration time.Duration
	reset    chan struct{}
	exit     bool
}

// MakeWatchdog creates and starts running a watchdog timer. If <duration>
// passes without a reset it writes stack traces to a temporary file determined
// by dir, prefix. Then it exits the program if exit is set.
func MakeWatchdog(dir, prefix string, duration time.Duration, exit bool) *Watchdog {
	r := &Watchdog{
		dir:      dir,
		prefix:   prefix,
		duration: duration,
		reset:    make(chan struct{}),
		exit:     exit,
	}
	go r.watch()
	return r
}

// Reset resets the watchdog's timer to 0.
func (w *Watchdog) Reset() {
	select {
	case w.reset <- struct{}{}:
	default:
	}
}

func (w *Watchdog) watch() {
	var t *time.Timer
	defer func() {
		if t != nil {
			t.Stop()
		}
	}()
	for {
		t = time.NewTimer(w.duration)
		select {
		case _, ok := <-w.reset:
			if !ok {
				return
			}
			t.Stop()
			t = nil
		case <-t.C:
			log.Errorf("Watchdog expired, attempting to write goroutine traces.")
			f, err := ioutil.TempFile(w.dir, w.prefix)
			if err != nil {
				log.Errorf("Unable to create file for goroutine traces: %v", err)
			} else {
				if err := pprof.Lookup("goroutine").WriteTo(f, 2); err != nil {
					log.Errorf("Unable to write goroutine traces to [%s]: %v", f.Name(), err)
				}
				if err := f.Close(); err != nil {
					log.Errorf("Unable to close file [%s]: %v", f.Name(), err)
				}
				log.Infof("Wrote goroutine traces to %s", f.Name())
			}
			if !w.exit {
				log.Exitf("Watchdog expired.")
				return
			}
		}
	}
}

// Stop stops the watchdog timer, so that it will no longer trigger.
func (w *Watchdog) Stop() {
	close(w.reset)
}
<commit_msg>Bugfix.<commit_after>// Copyright 2018 Google 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
//
//     https://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 watchdog implements a simple watchdog timer which dumps a trace of
// all goroutines to a file, and then ends the program, if the timer reaches its
// limit.
package watchdog

import (
	"io/ioutil"
	"runtime/pprof"
	"time"

	log "github.com/golang/glog"
)

type Watchdog struct {
	dir      string
	prefix   string
	duration time.Duration
	reset    chan struct{}
	exit     bool
}

// MakeWatchdog creates and starts running a watchdog timer. If <duration>
// passes without a reset it writes stack traces to a temporary file determined
// by dir, prefix. Then it exits the program if exit is set.
func MakeWatchdog(dir, prefix string, duration time.Duration, exit bool) *Watchdog {
	r := &Watchdog{
		dir:      dir,
		prefix:   prefix,
		duration: duration,
		reset:    make(chan struct{}),
		exit:     exit,
	}
	go r.watch()
	return r
}

// Reset resets the watchdog's timer to 0.
func (w *Watchdog) Reset() {
	select {
	case w.reset <- struct{}{}:
	default:
	}
}

func (w *Watchdog) watch() {
	var t *time.Timer
	defer func() {
		if t != nil {
			t.Stop()
		}
	}()
	for {
		t = time.NewTimer(w.duration)
		select {
		case _, ok := <-w.reset:
			if !ok {
				return
			}
			t.Stop()
			t = nil
		case <-t.C:
			log.Errorf("Watchdog expired, attempting to write goroutine traces.")
			f, err := ioutil.TempFile(w.dir, w.prefix)
			if err != nil {
				log.Errorf("Unable to create file for goroutine traces: %v", err)
			} else {
				if err := pprof.Lookup("goroutine").WriteTo(f, 2); err != nil {
					log.Errorf("Unable to write goroutine traces to [%s]: %v", f.Name(), err)
				}
				if err := f.Close(); err != nil {
					log.Errorf("Unable to close file [%s]: %v", f.Name(), err)
				}
				log.Infof("Wrote goroutine traces to %s", f.Name())
			}
			if w.exit {
				log.Exitf("Watchdog expired.")
				return
			}
		}
	}
}

// Stop stops the watchdog timer, so that it will no longer trigger.
func (w *Watchdog) Stop() {
	close(w.reset)
}
<|endoftext|>


<commit_before>package dht

import (
	"fmt"
	"time"

	ds "github.com/ipfs/go-datastore"
	dssync "github.com/ipfs/go-datastore/sync"
	"github.com/ipfs/go-ipns"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/protocol"
	"github.com/libp2p/go-libp2p-kad-dht/providers"
	record "github.com/libp2p/go-libp2p-record"
)

// ModeOpt describes what mode the dht should operate in
type ModeOpt int

const (
	// ModeAuto utilizes EvtLocalReachabilityChanged events sent over the event bus to dynamically switch the DHT
	// between Client and Server modes based on network conditions
	ModeAuto ModeOpt = iota
	// ModeClient operates the DHT as a client only, it cannot respond to incoming queries
	ModeClient
	// ModeServer operates the DHT as a server, it can both send and respond to queries
	ModeServer
	// ModeAutoServer operates in the same way as ModeAuto, but acts as a server when reachability is unknown
	ModeAutoServer
)

// DefaultPrefix is the application specific prefix attached to all DHT protocols by default.
const DefaultPrefix protocol.ID = "/ipfs"

// Options is a structure containing all the options that can be used when constructing a DHT.
type config struct {
	datastore        ds.Batching
	validator        record.Validator
	validatorChanged bool // if true implies that the validator has been changed and that defaults should not be used
	mode             ModeOpt
	protocolPrefix   protocol.ID
	bucketSize       int
	concurrency      int
	resiliency       int
	maxRecordAge     time.Duration
	enableProviders  bool
	enableValues     bool
	providersOptions []providers.Option
	queryPeerFilter  QueryFilterFunc

	routingTable struct {
		refreshQueryTimeout time.Duration
		refreshInterval     time.Duration
		autoRefresh         bool
		latencyTolerance    time.Duration
		checkInterval       time.Duration
		peerFilter          RouteTableFilterFunc
	}

	// set to true if we're operating in v1 dht compatible mode
	v1CompatibleMode bool
}

func emptyQueryFilter(_ *IpfsDHT, ai peer.AddrInfo) bool  { return true }
func emptyRTFilter(_ *IpfsDHT, conns []network.Conn) bool { return true }

// apply applies the given options to this Option
func (c *config) apply(opts ...Option) error {
	for i, opt := range opts {
		if err := opt(c); err != nil {
			return fmt.Errorf("dht option %d failed: %s", i, err)
		}
	}
	return nil
}

// applyFallbacks sets default values that could not be applied during config creation since they are dependent
// on other configuration parameters (e.g. optA is by default 2x optB) and/or on the Host
func (c *config) applyFallbacks(h host.Host) error {
	if !c.validatorChanged {
		nsval, ok := c.validator.(record.NamespacedValidator)
		if ok {
			if _, pkFound := nsval["pk"]; !pkFound {
				nsval["pk"] = record.PublicKeyValidator{}
			}
			if _, ipnsFound := nsval["ipns"]; !ipnsFound {
				nsval["ipns"] = ipns.Validator{KeyBook: h.Peerstore()}
			}
		} else {
			return fmt.Errorf("the default validator was changed without being marked as changed")
		}
	}
	return nil
}

// Option DHT option type.
type Option func(*config) error

const defaultBucketSize = 20

// defaults are the default DHT options. This option will be automatically
// prepended to any options you pass to the DHT constructor.
var defaults = func(o *config) error {
	o.validator = record.NamespacedValidator{}
	o.datastore = dssync.MutexWrap(ds.NewMapDatastore())
	o.protocolPrefix = DefaultPrefix
	o.enableProviders = true
	o.enableValues = true
	o.queryPeerFilter = emptyQueryFilter

	o.routingTable.latencyTolerance = time.Minute
	o.routingTable.refreshQueryTimeout = 1 * time.Minute
	o.routingTable.refreshInterval = 10 * time.Minute
	o.routingTable.autoRefresh = true
	o.routingTable.peerFilter = emptyRTFilter
	o.maxRecordAge = time.Hour * 36

	o.bucketSize = defaultBucketSize
	o.concurrency = 3
	o.resiliency = 3

	o.v1CompatibleMode = true

	return nil
}

func (c *config) validate() error {
	if c.protocolPrefix != DefaultPrefix {
		return nil
	}
	if c.bucketSize != defaultBucketSize {
		return fmt.Errorf("protocol prefix %s must use bucket size %d", DefaultPrefix, defaultBucketSize)
	}
	if !c.enableProviders {
		return fmt.Errorf("protocol prefix %s must have providers enabled", DefaultPrefix)
	}
	if !c.enableValues {
		return fmt.Errorf("protocol prefix %s must have values enabled", DefaultPrefix)
	}

	nsval, isNSVal := c.validator.(record.NamespacedValidator)
	if !isNSVal {
		return fmt.Errorf("protocol prefix %s must use a namespaced validator", DefaultPrefix)
	}

	if len(nsval) != 2 {
		return fmt.Errorf("protocol prefix %s must have exactly two namespaced validators - /pk and /ipns", DefaultPrefix)
	}

	if pkVal, pkValFound := nsval["pk"]; !pkValFound {
		return fmt.Errorf("protocol prefix %s must support the /pk namespaced validator", DefaultPrefix)
	} else if _, ok := pkVal.(record.PublicKeyValidator); !ok {
		return fmt.Errorf("protocol prefix %s must use the record.PublicKeyValidator for the /pk namespace", DefaultPrefix)
	}

	if ipnsVal, ipnsValFound := nsval["ipns"]; !ipnsValFound {
		return fmt.Errorf("protocol prefix %s must support the /ipns namespaced validator", DefaultPrefix)
	} else if _, ok := ipnsVal.(ipns.Validator); !ok {
		return fmt.Errorf("protocol prefix %s must use ipns.Validator for the /ipns namespace", DefaultPrefix)
	}
	return nil
}

// RoutingTableLatencyTolerance sets the maximum acceptable latency for peers
// in the routing table's cluster.
func RoutingTableLatencyTolerance(latency time.Duration) Option {
	return func(c *config) error {
		c.routingTable.latencyTolerance = latency
		return nil
	}
}

// RoutingTableRefreshQueryTimeout sets the timeout for routing table refresh
// queries.
func RoutingTableRefreshQueryTimeout(timeout time.Duration) Option {
	return func(c *config) error {
		c.routingTable.refreshQueryTimeout = timeout
		return nil
	}
}

// RoutingTableRefreshPeriod sets the period for refreshing buckets in the
// routing table. The DHT will refresh buckets every period by:
//
// 1. First searching for nearby peers to figure out how many buckets we should try to fill.
// 1. Then searching for a random key in each bucket that hasn't been queried in
//    the last refresh period.
func RoutingTableRefreshPeriod(period time.Duration) Option {
	return func(c *config) error {
		c.routingTable.refreshInterval = period
		return nil
	}
}

// Datastore configures the DHT to use the specified datastore.
//
// Defaults to an in-memory (temporary) map.
func Datastore(ds ds.Batching) Option {
	return func(c *config) error {
		c.datastore = ds
		return nil
	}
}

// Mode configures which mode the DHT operates in (Client, Server, Auto).
//
// Defaults to ModeAuto.
func Mode(m ModeOpt) Option {
	return func(c *config) error {
		c.mode = m
		return nil
	}
}

// Validator configures the DHT to use the specified validator.
//
// Defaults to a namespaced validator that can validate both public key (under the "pk"
// namespace) and IPNS records (under the "ipns" namespace). Setting the validator
// implies that the user wants to control the validators and therefore the default
// public key and IPNS validators will not be added.
func Validator(v record.Validator) Option {
	return func(c *config) error {
		c.validator = v
		c.validatorChanged = true
		return nil
	}
}

// NamespacedValidator adds a validator namespaced under `ns`. This option fails
// if the DHT is not using a `record.NamespacedValidator` as its validator (it
// uses one by default but this can be overridden with the `Validator` option).
// Adding a namespaced validator without changing the `Validator` will result in
// adding a new validator in addition to the default public key and IPNS validators.
// The "pk" and "ipns" namespaces cannot be overridden here unless a new `Validator`
// has been set first.
//
// Example: Given a validator registered as `NamespacedValidator("ipns",
// myValidator)`, all records with keys starting with `/ipns/` will be validated
// with `myValidator`.
func NamespacedValidator(ns string, v record.Validator) Option {
	return func(c *config) error {
		nsval, ok := c.validator.(record.NamespacedValidator)
		if !ok {
			return fmt.Errorf("can only add namespaced validators to a NamespacedValidator")
		}
		nsval[ns] = v
		return nil
	}
}

// ProtocolPrefix sets an application specific prefix to be attached to all DHT protocols. For example,
// /myapp/kad/1.0.0 instead of /ipfs/kad/1.0.0. Prefix should be of the form /myapp.
//
// Defaults to dht.DefaultPrefix
func ProtocolPrefix(prefix protocol.ID) Option {
	return func(c *config) error {
		c.protocolPrefix = prefix
		return nil
	}
}

// ProtocolExtension adds an application specific protocol to the DHT protocol. For example,
// /ipfs/lan/kad/1.0.0 instead of /ipfs/kad/1.0.0. extension should be of the form /lan.
func ProtocolExtension(ext protocol.ID) Option {
	return func(c *config) error {
		c.protocolPrefix += ext
		return nil
	}
}

// BucketSize configures the bucket size (k in the Kademlia paper) of the routing table.
//
// The default value is 20.
func BucketSize(bucketSize int) Option {
	return func(c *config) error {
		c.bucketSize = bucketSize
		return nil
	}
}

// Concurrency configures the number of concurrent requests (alpha in the Kademlia paper) for a given query path.
//
// The default value is 3.
func Concurrency(alpha int) Option {
	return func(c *config) error {
		c.concurrency = alpha
		return nil
	}
}

// Resiliency configures the number of peers closest to a target that must have responded in order for a given query
// path to complete.
//
// The default value is 3.
func Resiliency(beta int) Option {
	return func(c *config) error {
		c.resiliency = beta
		return nil
	}
}

// MaxRecordAge specifies the maximum time that any node will hold onto a record ("PutValue record")
// from the time its received. This does not apply to any other forms of validity that
// the record may contain.
// For example, a record may contain an ipns entry with an EOL saying its valid
// until the year 2020 (a great time in the future). For that record to stick around
// it must be rebroadcasted more frequently than once every 'MaxRecordAge'
func MaxRecordAge(maxAge time.Duration) Option {
	return func(c *config) error {
		c.maxRecordAge = maxAge
		return nil
	}
}

// DisableAutoRefresh completely disables 'auto-refresh' on the DHT routing
// table. This means that we will neither refresh the routing table periodically
// nor when the routing table size goes below the minimum threshold.
func DisableAutoRefresh() Option {
	return func(c *config) error {
		c.routingTable.autoRefresh = false
		return nil
	}
}

// DisableProviders disables storing and retrieving provider records.
//
// Defaults to enabled.
//
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
// network and/or distinct DHT protocols with the `Protocols` option).
func DisableProviders() Option {
	return func(c *config) error {
		c.enableProviders = false
		return nil
	}
}

// DisableValues disables storing and retrieving value records (including
// public keys).
//
// Defaults to enabled.
//
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
// network and/or distinct DHT protocols with the `Protocols` option).
func DisableValues() Option {
	return func(c *config) error {
		c.enableValues = false
		return nil
	}
}

// ProvidersOptions are options passed directly to the provider manager.
//
// The provider manager adds and gets provider records from the datastore, cahing
// them in between. These options are passed to the provider manager allowing
// customisation of things like the GC interval and cache implementation.
func ProvidersOptions(opts []providers.Option) Option {
	return func(c *config) error {
		c.providersOptions = opts
		return nil
	}
}

// QueryFilter sets a function that approves which peers may be dialed in a query
func QueryFilter(filter QueryFilterFunc) Option {
	return func(c *config) error {
		c.queryPeerFilter = filter
		return nil
	}
}

// RoutingTableFilter sets a function that approves which peers may be added to the routing table. The host should
// already have at least one connection to the peer under consideration.
func RoutingTableFilter(filter RouteTableFilterFunc) Option {
	return func(c *config) error {
		c.routingTable.peerFilter = filter
		return nil
	}
}

// V1CompatibleMode sets the DHT to operate in V1 compatible mode. In this mode,
// the DHT node will act like a V1 DHT node (use the V1 protocol names) but will
// use the V2 query and routing table logic.
//
// For now, this option defaults to true for backwards compatibility. In the
// near future, it will switch to false.
//
// This option is perma-unstable and may be removed in the future.
func V1CompatibleMode(enable bool) Option {
	return func(c *config) error {
		c.v1CompatibleMode = enable
		return nil
	}
}
<commit_msg>defaults: set default concurrency parameter to 10<commit_after>package dht

import (
	"fmt"
	"time"

	ds "github.com/ipfs/go-datastore"
	dssync "github.com/ipfs/go-datastore/sync"
	"github.com/ipfs/go-ipns"
	"github.com/libp2p/go-libp2p-core/host"
	"github.com/libp2p/go-libp2p-core/network"
	"github.com/libp2p/go-libp2p-core/peer"
	"github.com/libp2p/go-libp2p-core/protocol"
	"github.com/libp2p/go-libp2p-kad-dht/providers"
	record "github.com/libp2p/go-libp2p-record"
)

// ModeOpt describes what mode the dht should operate in
type ModeOpt int

const (
	// ModeAuto utilizes EvtLocalReachabilityChanged events sent over the event bus to dynamically switch the DHT
	// between Client and Server modes based on network conditions
	ModeAuto ModeOpt = iota
	// ModeClient operates the DHT as a client only, it cannot respond to incoming queries
	ModeClient
	// ModeServer operates the DHT as a server, it can both send and respond to queries
	ModeServer
	// ModeAutoServer operates in the same way as ModeAuto, but acts as a server when reachability is unknown
	ModeAutoServer
)

// DefaultPrefix is the application specific prefix attached to all DHT protocols by default.
const DefaultPrefix protocol.ID = "/ipfs"

// Options is a structure containing all the options that can be used when constructing a DHT.
type config struct {
	datastore        ds.Batching
	validator        record.Validator
	validatorChanged bool // if true implies that the validator has been changed and that defaults should not be used
	mode             ModeOpt
	protocolPrefix   protocol.ID
	bucketSize       int
	concurrency      int
	resiliency       int
	maxRecordAge     time.Duration
	enableProviders  bool
	enableValues     bool
	providersOptions []providers.Option
	queryPeerFilter  QueryFilterFunc

	routingTable struct {
		refreshQueryTimeout time.Duration
		refreshInterval     time.Duration
		autoRefresh         bool
		latencyTolerance    time.Duration
		checkInterval       time.Duration
		peerFilter          RouteTableFilterFunc
	}

	// set to true if we're operating in v1 dht compatible mode
	v1CompatibleMode bool
}

func emptyQueryFilter(_ *IpfsDHT, ai peer.AddrInfo) bool  { return true }
func emptyRTFilter(_ *IpfsDHT, conns []network.Conn) bool { return true }

// apply applies the given options to this Option
func (c *config) apply(opts ...Option) error {
	for i, opt := range opts {
		if err := opt(c); err != nil {
			return fmt.Errorf("dht option %d failed: %s", i, err)
		}
	}
	return nil
}

// applyFallbacks sets default values that could not be applied during config creation since they are dependent
// on other configuration parameters (e.g. optA is by default 2x optB) and/or on the Host
func (c *config) applyFallbacks(h host.Host) error {
	if !c.validatorChanged {
		nsval, ok := c.validator.(record.NamespacedValidator)
		if ok {
			if _, pkFound := nsval["pk"]; !pkFound {
				nsval["pk"] = record.PublicKeyValidator{}
			}
			if _, ipnsFound := nsval["ipns"]; !ipnsFound {
				nsval["ipns"] = ipns.Validator{KeyBook: h.Peerstore()}
			}
		} else {
			return fmt.Errorf("the default validator was changed without being marked as changed")
		}
	}
	return nil
}

// Option DHT option type.
type Option func(*config) error

const defaultBucketSize = 20

// defaults are the default DHT options. This option will be automatically
// prepended to any options you pass to the DHT constructor.
var defaults = func(o *config) error {
	o.validator = record.NamespacedValidator{}
	o.datastore = dssync.MutexWrap(ds.NewMapDatastore())
	o.protocolPrefix = DefaultPrefix
	o.enableProviders = true
	o.enableValues = true
	o.queryPeerFilter = emptyQueryFilter

	o.routingTable.latencyTolerance = time.Minute
	o.routingTable.refreshQueryTimeout = 1 * time.Minute
	o.routingTable.refreshInterval = 10 * time.Minute
	o.routingTable.autoRefresh = true
	o.routingTable.peerFilter = emptyRTFilter
	o.maxRecordAge = time.Hour * 36

	o.bucketSize = defaultBucketSize
	o.concurrency = 10
	o.resiliency = 3

	o.v1CompatibleMode = true

	return nil
}

func (c *config) validate() error {
	if c.protocolPrefix != DefaultPrefix {
		return nil
	}
	if c.bucketSize != defaultBucketSize {
		return fmt.Errorf("protocol prefix %s must use bucket size %d", DefaultPrefix, defaultBucketSize)
	}
	if !c.enableProviders {
		return fmt.Errorf("protocol prefix %s must have providers enabled", DefaultPrefix)
	}
	if !c.enableValues {
		return fmt.Errorf("protocol prefix %s must have values enabled", DefaultPrefix)
	}

	nsval, isNSVal := c.validator.(record.NamespacedValidator)
	if !isNSVal {
		return fmt.Errorf("protocol prefix %s must use a namespaced validator", DefaultPrefix)
	}

	if len(nsval) != 2 {
		return fmt.Errorf("protocol prefix %s must have exactly two namespaced validators - /pk and /ipns", DefaultPrefix)
	}

	if pkVal, pkValFound := nsval["pk"]; !pkValFound {
		return fmt.Errorf("protocol prefix %s must support the /pk namespaced validator", DefaultPrefix)
	} else if _, ok := pkVal.(record.PublicKeyValidator); !ok {
		return fmt.Errorf("protocol prefix %s must use the record.PublicKeyValidator for the /pk namespace", DefaultPrefix)
	}

	if ipnsVal, ipnsValFound := nsval["ipns"]; !ipnsValFound {
		return fmt.Errorf("protocol prefix %s must support the /ipns namespaced validator", DefaultPrefix)
	} else if _, ok := ipnsVal.(ipns.Validator); !ok {
		return fmt.Errorf("protocol prefix %s must use ipns.Validator for the /ipns namespace", DefaultPrefix)
	}
	return nil
}

// RoutingTableLatencyTolerance sets the maximum acceptable latency for peers
// in the routing table's cluster.
func RoutingTableLatencyTolerance(latency time.Duration) Option {
	return func(c *config) error {
		c.routingTable.latencyTolerance = latency
		return nil
	}
}

// RoutingTableRefreshQueryTimeout sets the timeout for routing table refresh
// queries.
func RoutingTableRefreshQueryTimeout(timeout time.Duration) Option {
	return func(c *config) error {
		c.routingTable.refreshQueryTimeout = timeout
		return nil
	}
}

// RoutingTableRefreshPeriod sets the period for refreshing buckets in the
// routing table. The DHT will refresh buckets every period by:
//
// 1. First searching for nearby peers to figure out how many buckets we should try to fill.
// 1. Then searching for a random key in each bucket that hasn't been queried in
//    the last refresh period.
func RoutingTableRefreshPeriod(period time.Duration) Option {
	return func(c *config) error {
		c.routingTable.refreshInterval = period
		return nil
	}
}

// Datastore configures the DHT to use the specified datastore.
//
// Defaults to an in-memory (temporary) map.
func Datastore(ds ds.Batching) Option {
	return func(c *config) error {
		c.datastore = ds
		return nil
	}
}

// Mode configures which mode the DHT operates in (Client, Server, Auto).
//
// Defaults to ModeAuto.
func Mode(m ModeOpt) Option {
	return func(c *config) error {
		c.mode = m
		return nil
	}
}

// Validator configures the DHT to use the specified validator.
//
// Defaults to a namespaced validator that can validate both public key (under the "pk"
// namespace) and IPNS records (under the "ipns" namespace). Setting the validator
// implies that the user wants to control the validators and therefore the default
// public key and IPNS validators will not be added.
func Validator(v record.Validator) Option {
	return func(c *config) error {
		c.validator = v
		c.validatorChanged = true
		return nil
	}
}

// NamespacedValidator adds a validator namespaced under `ns`. This option fails
// if the DHT is not using a `record.NamespacedValidator` as its validator (it
// uses one by default but this can be overridden with the `Validator` option).
// Adding a namespaced validator without changing the `Validator` will result in
// adding a new validator in addition to the default public key and IPNS validators.
// The "pk" and "ipns" namespaces cannot be overridden here unless a new `Validator`
// has been set first.
//
// Example: Given a validator registered as `NamespacedValidator("ipns",
// myValidator)`, all records with keys starting with `/ipns/` will be validated
// with `myValidator`.
func NamespacedValidator(ns string, v record.Validator) Option {
	return func(c *config) error {
		nsval, ok := c.validator.(record.NamespacedValidator)
		if !ok {
			return fmt.Errorf("can only add namespaced validators to a NamespacedValidator")
		}
		nsval[ns] = v
		return nil
	}
}

// ProtocolPrefix sets an application specific prefix to be attached to all DHT protocols. For example,
// /myapp/kad/1.0.0 instead of /ipfs/kad/1.0.0. Prefix should be of the form /myapp.
//
// Defaults to dht.DefaultPrefix
func ProtocolPrefix(prefix protocol.ID) Option {
	return func(c *config) error {
		c.protocolPrefix = prefix
		return nil
	}
}

// ProtocolExtension adds an application specific protocol to the DHT protocol. For example,
// /ipfs/lan/kad/1.0.0 instead of /ipfs/kad/1.0.0. extension should be of the form /lan.
func ProtocolExtension(ext protocol.ID) Option {
	return func(c *config) error {
		c.protocolPrefix += ext
		return nil
	}
}

// BucketSize configures the bucket size (k in the Kademlia paper) of the routing table.
//
// The default value is 20.
func BucketSize(bucketSize int) Option {
	return func(c *config) error {
		c.bucketSize = bucketSize
		return nil
	}
}

// Concurrency configures the number of concurrent requests (alpha in the Kademlia paper) for a given query path.
//
// The default value is 10.
func Concurrency(alpha int) Option {
	return func(c *config) error {
		c.concurrency = alpha
		return nil
	}
}

// Resiliency configures the number of peers closest to a target that must have responded in order for a given query
// path to complete.
//
// The default value is 3.
func Resiliency(beta int) Option {
	return func(c *config) error {
		c.resiliency = beta
		return nil
	}
}

// MaxRecordAge specifies the maximum time that any node will hold onto a record ("PutValue record")
// from the time its received. This does not apply to any other forms of validity that
// the record may contain.
// For example, a record may contain an ipns entry with an EOL saying its valid
// until the year 2020 (a great time in the future). For that record to stick around
// it must be rebroadcasted more frequently than once every 'MaxRecordAge'
func MaxRecordAge(maxAge time.Duration) Option {
	return func(c *config) error {
		c.maxRecordAge = maxAge
		return nil
	}
}

// DisableAutoRefresh completely disables 'auto-refresh' on the DHT routing
// table. This means that we will neither refresh the routing table periodically
// nor when the routing table size goes below the minimum threshold.
func DisableAutoRefresh() Option {
	return func(c *config) error {
		c.routingTable.autoRefresh = false
		return nil
	}
}

// DisableProviders disables storing and retrieving provider records.
//
// Defaults to enabled.
//
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
// network and/or distinct DHT protocols with the `Protocols` option).
func DisableProviders() Option {
	return func(c *config) error {
		c.enableProviders = false
		return nil
	}
}

// DisableValues disables storing and retrieving value records (including
// public keys).
//
// Defaults to enabled.
//
// WARNING: do not change this unless you're using a forked DHT (i.e., a private
// network and/or distinct DHT protocols with the `Protocols` option).
func DisableValues() Option {
	return func(c *config) error {
		c.enableValues = false
		return nil
	}
}

// ProvidersOptions are options passed directly to the provider manager.
//
// The provider manager adds and gets provider records from the datastore, cahing
// them in between. These options are passed to the provider manager allowing
// customisation of things like the GC interval and cache implementation.
func ProvidersOptions(opts []providers.Option) Option {
	return func(c *config) error {
		c.providersOptions = opts
		return nil
	}
}

// QueryFilter sets a function that approves which peers may be dialed in a query
func QueryFilter(filter QueryFilterFunc) Option {
	return func(c *config) error {
		c.queryPeerFilter = filter
		return nil
	}
}

// RoutingTableFilter sets a function that approves which peers may be added to the routing table. The host should
// already have at least one connection to the peer under consideration.
func RoutingTableFilter(filter RouteTableFilterFunc) Option {
	return func(c *config) error {
		c.routingTable.peerFilter = filter
		return nil
	}
}

// V1CompatibleMode sets the DHT to operate in V1 compatible mode. In this mode,
// the DHT node will act like a V1 DHT node (use the V1 protocol names) but will
// use the V2 query and routing table logic.
//
// For now, this option defaults to true for backwards compatibility. In the
// near future, it will switch to false.
//
// This option is perma-unstable and may be removed in the future.
func V1CompatibleMode(enable bool) Option {
	return func(c *config) error {
		c.v1CompatibleMode = enable
		return nil
	}
}
<|endoftext|>


<commit_before>package chromedp

import (
	"testing"

	"github.com/chromedp/cdproto/page"
)

func TestCloseDialog(t *testing.T) {
	t.Parallel()

	t.Run("Alert", func(t *testing.T) {
		ctx, cancel := testAllocate(t, "")
		defer cancel()

		ListenTarget(ctx, func(ev interface{}) {
			switch ev.(type) {
			case *page.EventJavascriptDialogOpening:
				if err := Run(ctx,
					page.HandleJavaScriptDialog(true),
				); err != nil {
					t.Error(err)
				}
			}
		})

		if err := Run(ctx,
			Navigate(testdataDir+"/dialog.html"),
			Click("#alert", ByID, NodeVisible),
		); err != nil {
			t.Fatalf("got error on DialogText %v", err)
		}
	})
}
<commit_msg>dialog: add more tests<commit_after>package chromedp

import (
	"testing"

	"github.com/chromedp/cdproto/page"
)

func TestCloseDialog(t *testing.T) {
	t.Parallel()

	tests := []struct {
		name       string
		accept     bool
		promptText string
		dialogType page.DialogType
		sel        string
		want       string
	}{
		{
			name:       "AlertAcceptWithPromptText",
			accept:     true,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypeAlert,
			sel:        "#alert",
			want:       "alert text",
		},
		{
			name:       "AlertDismissWithPromptText",
			accept:     false,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypeAlert,
			sel:        "#alert",
			want:       "alert text",
		},
		{
			name:       "AlertAcceptWithoutPromptText",
			accept:     true,
			dialogType: page.DialogTypeAlert,
			sel:        "#alert",
			want:       "alert text",
		},
		{
			name:       "AlertDismissWithoutPromptText",
			accept:     false,
			dialogType: page.DialogTypeAlert,
			sel:        "#alert",
			want:       "alert text",
		},
		{
			name:       "PromptAcceptWithPromptText",
			accept:     true,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypePrompt,
			sel:        "#prompt",
			want:       "prompt text",
		},
		{
			name:       "PromptDismissWithPromptText",
			accept:     false,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypePrompt,
			sel:        "#prompt",
			want:       "prompt text",
		},
		{
			name:       "PromptAcceptWithoutPromptText",
			accept:     true,
			dialogType: page.DialogTypePrompt,
			sel:        "#prompt",
			want:       "prompt text",
		},
		{
			name:       "PromptDismissWithoutPromptText",
			accept:     false,
			dialogType: page.DialogTypePrompt,
			sel:        "#prompt",
			want:       "prompt text",
		},
		{
			name:       "ConfirmAcceptWithPromptText",
			accept:     true,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypeConfirm,
			sel:        "#confirm",
			want:       "confirm text",
		},
		{
			name:       "ConfirmDismissWithPromptText",
			accept:     false,
			promptText: "this is a prompt text",
			dialogType: page.DialogTypeConfirm,
			sel:        "#confirm",
			want:       "confirm text",
		},
		{
			name:       "ConfirmAcceptWithoutPromptText",
			accept:     true,
			dialogType: page.DialogTypeConfirm,
			sel:        "#confirm",
			want:       "confirm text",
		},
		{
			name:       "ConfirmDismissWithoutPromptText",
			accept:     false,
			dialogType: page.DialogTypeConfirm,
			sel:        "#confirm",
			want:       "confirm text",
		},
	}

	for _, test := range tests {
		t.Run(test.name, func(t *testing.T) {
			t.Parallel()

			ctx, cancel := testAllocate(t, "")
			defer cancel()

			ListenTarget(ctx, func(ev interface{}) {
				switch e := ev.(type) {
				case *page.EventJavascriptDialogOpening:
					if e.Type != test.dialogType {
						t.Errorf("expected dialog type to be '%s', got: '%s'", test.dialogType, e.Type)
					}
					if e.Message != test.want {
						t.Errorf("expected dialog message to be '%s', got: '%s'", test.want, e.Message)
					}

					task := page.HandleJavaScriptDialog(test.accept)
					if test.promptText != "" {
						task = task.WithPromptText(test.promptText)
					}
					if err := Run(ctx, task); err != nil {
						t.Error(err)
					}
				case *page.EventJavascriptDialogClosed:
					if e.Result != test.accept {
						t.Errorf("expected result to be %t, got %t", test.accept, e.Result)
					}
					if e.UserInput != test.promptText {
						t.Errorf("expected user input to be %q, got %q", test.promptText, e.UserInput)
					}
				}
			})

			if err := Run(ctx,
				Navigate(testdataDir+"/dialog.html"),
				Click(test.sel, ByID, NodeVisible),
			); err != nil {
				t.Fatalf("got error on DialogText %v", err)
			}
		})
	}
}
<|endoftext|>


<commit_before>package gate

import (
	"github.com/name5566/leaf/log"
	"github.com/name5566/leaf/network"
	"github.com/name5566/leaf/network/json"
	"github.com/name5566/leaf/network/protobuf"
)

type TCPGate struct {
	Addr              string
	MaxConnNum        int
	PendingWriteNum   int
	LenMsgLen         int
	MinMsgLen         uint32
	MaxMsgLen         uint32
	LittleEndian      bool
	JSONProcessor     *json.Processor
	ProtobufProcessor *protobuf.Processor
}

func (gate *TCPGate) Run(closeSig chan bool) {
	server := new(network.TCPServer)
	server.Addr = gate.Addr
	server.MaxConnNum = gate.MaxConnNum
	server.PendingWriteNum = gate.PendingWriteNum
	server.LenMsgLen = gate.LenMsgLen
	server.MinMsgLen = gate.MinMsgLen
	server.MaxMsgLen = gate.MaxMsgLen
	server.LittleEndian = gate.LittleEndian
	server.NewAgent = func(conn *network.TCPConn) network.Agent {
		a := new(TCPAgent)
		a.conn = conn
		a.gate = gate
		return a
	}

	server.Start()
	<-closeSig
	server.Close()
}

func (gate *TCPGate) OnDestroy() {}

type TCPAgent struct {
	conn *network.TCPConn
	gate *TCPGate
}

func (a *TCPAgent) Run() {
	for {
		data, err := a.conn.ReadMsg()
		if err != nil {
			log.Debug("read msg error: %v", err)
			break
		}

		// json
		if a.gate.JSONProcessor != nil {
			msg, err := a.gate.JSONProcessor.Unmarshal(data)
			if err != nil {
				log.Debug("unmarshal json error: %v", err)
				break
			}
			err = a.gate.JSONProcessor.Route(msg, a)
			if err != nil {
				log.Debug("route msg error: %v", err)
				break
			}
		}

		// protobuf
		if a.gate.ProtobufProcessor != nil {
			msg, err := a.gate.ProtobufProcessor.Unmarshal(data)
			if err != nil {
				log.Debug("unmarshal protobuf error: %v", err)
				break
			}
			err = a.gate.ProtobufProcessor.Route(msg, a)
			if err != nil {
				log.Debug("route msg error: %v", err)
				break
			}
		}
	}
}

func (a *TCPAgent) OnClose() {

}
<commit_msg>update log message<commit_after>package gate

import (
	"github.com/name5566/leaf/log"
	"github.com/name5566/leaf/network"
	"github.com/name5566/leaf/network/json"
	"github.com/name5566/leaf/network/protobuf"
)

type TCPGate struct {
	Addr              string
	MaxConnNum        int
	PendingWriteNum   int
	LenMsgLen         int
	MinMsgLen         uint32
	MaxMsgLen         uint32
	LittleEndian      bool
	JSONProcessor     *json.Processor
	ProtobufProcessor *protobuf.Processor
}

func (gate *TCPGate) Run(closeSig chan bool) {
	server := new(network.TCPServer)
	server.Addr = gate.Addr
	server.MaxConnNum = gate.MaxConnNum
	server.PendingWriteNum = gate.PendingWriteNum
	server.LenMsgLen = gate.LenMsgLen
	server.MinMsgLen = gate.MinMsgLen
	server.MaxMsgLen = gate.MaxMsgLen
	server.LittleEndian = gate.LittleEndian
	server.NewAgent = func(conn *network.TCPConn) network.Agent {
		a := new(TCPAgent)
		a.conn = conn
		a.gate = gate
		return a
	}

	server.Start()
	<-closeSig
	server.Close()
}

func (gate *TCPGate) OnDestroy() {}

type TCPAgent struct {
	conn *network.TCPConn
	gate *TCPGate
}

func (a *TCPAgent) Run() {
	for {
		data, err := a.conn.ReadMsg()
		if err != nil {
			log.Debug("read message error: %v", err)
			break
		}

		// json
		if a.gate.JSONProcessor != nil {
			msg, err := a.gate.JSONProcessor.Unmarshal(data)
			if err != nil {
				log.Debug("unmarshal json error: %v", err)
				break
			}
			err = a.gate.JSONProcessor.Route(msg, a)
			if err != nil {
				log.Debug("route message error: %v", err)
				break
			}
		}

		// protobuf
		if a.gate.ProtobufProcessor != nil {
			msg, err := a.gate.ProtobufProcessor.Unmarshal(data)
			if err != nil {
				log.Debug("unmarshal protobuf error: %v", err)
				break
			}
			err = a.gate.ProtobufProcessor.Route(msg, a)
			if err != nil {
				log.Debug("route message error: %v", err)
				break
			}
		}
	}
}

func (a *TCPAgent) OnClose() {

}
<|endoftext|>