<commit_before>package parameters

type HostParams struct {
	Generate bool
	Listen   bool
	Serve    bool
	Help     bool
	Exit     bool
	Windows  bool
	MacOS    bool
	Linux    bool
	LHost    string
	LPort    string
	FName    string
}

// type TargetParams struct {
// 	Download     bool
// 	DownloadPath string
// 	Upload       bool
// 	UploadPath   string
// 	OpenURL      bool
// 	OpenURLPath  string
// 	// Screenshot         bool
// 	// KeyloggerStart     bool
// 	// KeyloggerShow      bool
// 	// PersistenceEnable  bool
// 	// PersistenceDisable bool
// 	// GetOS              bool
// 	// LockScreen         bool
// 	// Bomb               bool
// 	// ClearScreen        bool
// 	// Back               bool
// 	// Exit               bool
// 	// Help               bool
// }
<commit_msg>Update parameters.go<commit_after>package parameters

type HostParams struct {
	Generate bool
	Listen   bool
	Serve    bool
	Help     bool
	Exit     bool
	Windows  bool
	MacOS    bool
	Linux    bool
	LHost    string
	LPort    string
	FName    string
}
<|endoftext|>


<commit_before>package main

import (
	"github.com/go-sql-driver/mysql"
	"database/sql/driver"
	"fmt"
	"time"
	"sync"
	"runtime"
	"flag"
//	"database/sql"
//  _ "github.com/go-sql-driver/mysql"
//  _ "net/http/pprof"
//  "net/http"
	"math/big"
	"math"
	"os"
	"io"
)

/*
type TestResult struct {
	connOk bool
	queryOk bool
	connTime time.Duration
	queryTime time.Duration
}*/

const (
	STAGE_CONN  byte = 0
	STAGE_QUERY byte = 1
	STAGE_READ  byte = 2
	STAGE_TOTAL byte = 3
	//
	STAGE_MAX   byte = 4
)

type TestResult struct {
	stage                  byte
	ok                     bool
	time                   time.Duration
}

/*
type SummeryResult struct {
	count                 int64

	connFailCount         int64
	totalConnTime         time.Duration
	totalSquareConnTime   big.Int
	maxConnTime           time.Duration
	minConnTime           time.Duration
	avgConnTime           time.Duration
	stddevConnTime        time.Duration

	queryFailCount        int64
	totalQueryTime        time.Duration
	totalSquareQueryTime  big.Int
	maxQueryTime          time.Duration
	minQueryTime          time.Duration
	avgQueryTime          time.Duration
	stddevQueryTime       time.Duration
}*/

type SummeryResult struct {
	stage             byte
	count             int64

	failCount         int64
	totalTime         time.Duration
	totalSquareTime   big.Int
	maxTime           time.Duration
	minTime           time.Duration
	avgTime           time.Duration
	stddevTime        time.Duration
}

func getColumnCount(dsn, query string) (int, error) {
	db, err := (mysql.MySQLDriver{}).Open(dsn)
	if err != nil {
		return 0, err
	}
	defer db.Close()

	rows, err := db.(driver.Queryer).Query(query, []driver.Value{})
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	return len(rows.Columns()), nil
}

func testOnce(dsn, query string, row []driver.Value, result [STAGE_MAX]TestResult) {
	result[STAGE_TOTAL].ok = false
	beforeConn := time.Now()
	db, err := (mysql.MySQLDriver{}).Open(dsn)
	if err != nil {
		//fmt.Println(err.Error())
		result[STAGE_CONN].ok = false
		return
	}
	result[STAGE_CONN].ok = true
	afterConn := time.Now()
	result[STAGE_CONN].time = afterConn.Sub(beforeConn)
	defer db.Close()

	rows, err := db.(driver.Queryer).Query(query, []driver.Value{})
	if err != nil {
		//fmt.Println(err.Error())
		result[STAGE_QUERY].ok = false
		return
	}
	afterQuery := time.Now()
	result[STAGE_QUERY].ok = true
	result[STAGE_QUERY].time = afterQuery.Sub(afterConn)
	defer rows.Close()
	for {
		err = rows.Next(row)
		if err != nil {
			break
		}
	}
	if err != io.EOF {
		result[STAGE_QUERY].ok = false
	} else {
		afterRead := time.Now()
		result[STAGE_READ].ok = true
		result[STAGE_TOTAL].ok = true
		result[STAGE_READ].time = afterRead.Sub(afterQuery)
		result[STAGE_TOTAL].time = afterRead.Sub(beforeConn)
	}
}

/*
func testOnce(dsn, query string, row []driver.Value) TestResult {
	result := TestResult{}
	beforeConn := time.Now()
	db, err := (mysql.MySQLDriver{}).Open(dsn)
	if err != nil {
		//fmt.Println(err.Error())
		result.connOk = false
		return result
	}
	result.connOk = true
	afterConn := time.Now()
	result.connTime = afterConn.Sub(beforeConn)
	defer db.Close()

	rows, err := db.(driver.Queryer).Query(query, []driver.Value{})
	if err != nil {
		//fmt.Println(err.Error())
		result.queryOk = false
		return result
	}
	afterQuery := time.Now()
	result.queryTime = afterQuery.Sub(afterConn)
	result.queryOk = true
	defer rows.Close()
	for {
		err = rows.Next(row)
		if err != nil {
			break
		}
	}
	// result.queryTime = afterQuery.Sub(afterConn)
	return result
}*/

func testRoutine(dsn, query string, n int, colNum int, outChan chan<- [STAGE_MAX]TestResult) {
	var result [STAGE_MAX]TestResult
	result[STAGE_CONN].stage = STAGE_CONN
	result[STAGE_QUERY].stage = STAGE_QUERY
	result[STAGE_READ].stage = STAGE_READ
	result[STAGE_TOTAL].stage = STAGE_TOTAL

	row := make([]driver.Value, colNum)
	for i := 0; i < n; i++ {
		testOnce(dsn, query, row, result)
		outChan <-result
	}
}

func summeryRoutine(inChan <-chan [STAGE_MAX]TestResult, outChan chan<- [STAGE_MAX]SummeryResult, summeryIntervalSecond int) {
	var ret   [STAGE_MAX]SummeryResult
	var bigA  big.Int
	var ticker *time.Ticker
	for i := byte(0); i < STAGE_MAX; i++ {
		ret[i].minTime = math.MaxInt64
		ret[i].stage = (byte)(i)
	}

	if summeryIntervalSecond > 0 {
		summeryInterval := time.Second * time.Duration(summeryIntervalSecond)
		ticker = time.NewTicker(summeryInterval)
	}
	for result := range inChan {
		for i := byte(0); i < STAGE_MAX; i++ {
			ret[i].count++
			if result[i].ok {
				if result[i].time > ret[i].maxTime {
					ret[i].maxTime = result[i].time
				}
				if result[i].time < ret[i].minTime {
					ret[i].minTime = result[i].time
				}
				ret[i].totalTime+= result[i].time
				bigA.SetInt64((int64)(result[i].time)).Mul(&bigA, &bigA)
				ret[i].totalSquareTime.Add(&ret[i].totalSquareTime, &bigA)
			} else {
				ret[i].failCount++
			}

			if summeryIntervalSecond > 0 {
				if _, ok := <-ticker.C; ok {
					ret[i].Summery()
					outChan<-ret
					ret = [STAGE_MAX]SummeryResult{}
				}
			}
		}
	}
	for i := byte(0); i < STAGE_MAX; i++ {
		ret[i].Summery()
	}
	outChan<-ret
	close(outChan)
	return
}

func (self *SummeryResult) Summery() {
	var bigA, big2 big.Int
	var bigR1, bigR2, big1N, big1N1 big.Rat
	big2.SetInt64(2)
	//  ∑(i-miu)2 = ∑(i2)-(∑i)2/n
	n := self.count - self.failCount
	if n > 1 {
		self.avgTime = (time.Duration)((int64)(self.totalTime) / n)

		big1N.SetInt64(n).Inv(&big1N) // 1/n
		big1N1.SetInt64(n-1).Inv(&big1N1) // 1/(n-1)
		bigA.SetInt64((int64)(self.totalTime)).Mul(&bigA, &bigA) // (∑i)2
		bigR1.SetInt(&bigA).Mul(&bigR1, &big1N) // (∑i)2/n
		bigR2.SetInt(&self.totalSquareTime).Sub(&bigR2, &bigR1)
		s2, _ := bigR2.Mul(&bigR2, &big1N1).Float64()
		self.stddevTime = (time.Duration)((int64)(math.Sqrt(s2)))
	}
	if self.minTime == math.MaxInt64 {
		self.minTime = 0
	}
}

/*
func summeryRoutine(inChan <-chan TestResult, outChan chan<- SummeryResult, summeryIntervalSecond int) {
	var ret   SummeryResult
	var bigA  big.Int
	ret.minConnTime = math.MaxInt64
	ret.minQueryTime = math.MaxInt64
	var ticker *time.Ticker
	if summeryIntervalSecond > 0 {
		summeryInterval := time.Second * time.Duration(summeryIntervalSecond)
		ticker = time.NewTicker(summeryInterval)
	}
	for result := range inChan {
		ret.count++
		if result.connOk {
			if result.connTime > ret.maxConnTime {
				ret.maxConnTime = result.connTime
			}
			if result.connTime < ret.minConnTime {
				ret.minConnTime = result.connTime
			}
			ret.totalConnTime+= result.connTime
			bigA.SetInt64((int64)(result.connTime)).Mul(&bigA, &bigA)
			ret.totalSquareConnTime.Add(&ret.totalSquareConnTime, &bigA)
		} else {
			ret.connFailCount++
		}
		if result.queryOk {
			if result.queryTime > ret.maxQueryTime {
				ret.maxQueryTime = result.queryTime
			}
			if result.queryTime < ret.minQueryTime {
				ret.minQueryTime = result.queryTime
			}
			ret.totalQueryTime+= result.queryTime
			bigA.SetInt64((int64)(result.queryTime)).Mul(&bigA, &bigA)
			ret.totalSquareQueryTime.Add(&ret.totalSquareQueryTime, &bigA)
		} else {
			ret.queryFailCount++
		}
		if summeryIntervalSecond > 0 {
			select {
			case <-ticker.C:
				ret.Summery()
				outChan<-ret
				ret = SummeryResult{}
                        default:
				//
			}
		}
	}
	ret.Summery()
	outChan<-ret
        close(outChan)
	return
}

func (self *SummeryResult) Summery() {
	var bigA, big2 big.Int
	var bigR1, bigR2, big1N, big1N1 big.Rat
	big2.SetInt64(2)
	//  ∑(i-miu)2 = ∑(i2)-(∑i)2/n
	n := self.count - self.connFailCount
	if n > 1 {
		self.avgConnTime = (time.Duration)((int64)(self.totalConnTime) / n)

		big1N.SetInt64(n).Inv(&big1N) // 1/n
		big1N1.SetInt64(n-1).Inv(&big1N1) // 1/(n-1)
		bigA.SetInt64((int64)(self.totalConnTime)).Mul(&bigA, &bigA) // (∑i)2
		bigR1.SetInt(&bigA).Mul(&bigR1, &big1N) // (∑i)2/n
		bigR2.SetInt(&self.totalSquareConnTime).Sub(&bigR2, &bigR1)
		s2, _ := bigR2.Mul(&bigR2, &big1N1).Float64()
		self.stddevConnTime = (time.Duration)((int64)(math.Sqrt(s2)))
	}

	n = self.count - self.queryFailCount
	if n > 1 {
		self.avgQueryTime = (time.Duration)((int64)(self.totalQueryTime) / n)

		big1N.SetInt64(n).Inv(&big1N) // 1/n
		big1N1.SetInt64(n-1).Inv(&big1N1) // 1/(n-1)
		bigA.SetInt64((int64)(self.totalQueryTime)).Mul(&bigA, &bigA) // (∑i)2
		bigR1.SetInt(&bigA).Mul(&bigR1, &big1N) // (∑i)2/n
		bigR2.SetInt(&self.totalSquareQueryTime).Sub(&bigR2, &bigR1)
		s2, _ := bigR2.Mul(&bigR2, &big1N1).Float64()
		self.stddevQueryTime = (time.Duration)((int64)(math.Sqrt(s2)))
	}

	if self.minConnTime == math.MaxInt64 {
		self.minConnTime = 0
	}
	if self.minQueryTime == math.MaxInt64 {
		self.minQueryTime = 0
	}
}*/

func msStr(t time.Duration) string {
	return fmt.Sprintf("%0.3f ms", float64(int64(t) / 1000) / 1000.0)
}

type NullLogger struct{}
func (*NullLogger) Print(v ...interface{}) {
}

// mysqlburst -c 2000 -r 30 -d 'mha:M616VoUJBnYFi0L02Y24@tcp(10.200.180.54:3342)/x?timeout=5s&readTimeout=3s&writeTimeout=3s'
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	//go func() {
	//      http.ListenAndServe("localhost:6060", nil)
	//}()

	procs := 0
	rounds := 0
	dsn := ""
	query := ""
	summeryIntervalSec := 0
	flag.IntVar(&procs, "c", 1000, "concurrency")
	flag.IntVar(&rounds, "r", 100, "rounds")
	flag.StringVar(&dsn, "d", "mysql:@tcp(127.0.0.1:3306)/mysql?timeout=5s&readTimeout=5s&writeTimeout=5s", "dsn")
	flag.StringVar(&query, "q", "select 1", "sql")
	flag.IntVar(&summeryIntervalSec, "i", 0, "summery interval (sec)")
	flag.Parse()

	mysql.SetLogger(&NullLogger{})

	colNum, err := getColumnCount(dsn, query)
	if err != nil {
		fmt.Printf("init failed: %s", err)
		os.Exit(2)
	}
	wg := sync.WaitGroup{}
	wg.Add(procs)
	resultChan := make(chan [STAGE_MAX]TestResult, 5000)
	summeryChan := make(chan [STAGE_MAX]SummeryResult, 10)

	go func() {
		for i := 0; i < procs; i++ {
			go func() {
				testRoutine(dsn, query, rounds, colNum, resultChan)
				wg.Done()
			}()
		}
		wg.Wait()
		close(resultChan)
	}()
	go summeryRoutine(resultChan, summeryChan, summeryIntervalSec)

	testBegin := time.Now()
	titles := [STAGE_MAX]string{
		"connect", "query", "read", "total",
	}
	for summery := range summeryChan {
		testEnd := time.Now()
		duration:= testEnd.Sub(testBegin)
		testBegin = testEnd

		fmt.Printf("time: %s\n", duration.String())
		//fmt.Printf("tests: %d\n", summery.count);
		for i, title := range titles {
			fmt.Println(title)
			fmt.Printf("count: %d\n", summery[i].count);
			fmt.Printf("failed: %d\n", summery[i].failCount);
			fmt.Printf("avg time: %s\n", msStr(summery[i].avgTime))
			fmt.Printf("min time: %s\n", msStr(summery[i].minTime))
			fmt.Printf("max time: %s\n", msStr(summery[i].maxTime))
			fmt.Printf("stddev time: %s\n", msStr(summery[i].stddevTime))
		}
		/*
		fmt.Println("connect time")
		fmt.Printf("failed: %d\n", summery.connFailCount);
		fmt.Printf("avg: %s\n", msStr(summery.avgConnTime))
		fmt.Printf("min: %s\n", msStr(summery.minConnTime))
		fmt.Printf("max: %s\n", msStr(summery.maxConnTime))
		fmt.Printf("stddev: %s\n", msStr(summery.stddevConnTime))

		fmt.Println()
		fmt.Println("query time")
		fmt.Printf("failed: %d\n", summery.queryFailCount);
		fmt.Printf("avg: %s\n", msStr(summery.avgQueryTime))
		fmt.Printf("min: %s\n", msStr(summery.minQueryTime))
		fmt.Printf("max: %s\n", msStr(summery.maxQueryTime))
		fmt.Printf("stddev: %s\n", msStr(summery.stddevQueryTime))
		fmt.Println()
		*/
	}

}

<commit_msg>fix summery; more clear result<commit_after>package main

import (
	"github.com/go-sql-driver/mysql"
	"database/sql/driver"
	"fmt"
	"time"
	"sync"
	"runtime"
	"flag"
	"math/big"
	"math"
	"os"
	"io"
)

const (
	STAGE_CONN  byte = 0
	STAGE_QUERY byte = 1
	STAGE_READ  byte = 2
	STAGE_TOTAL byte = 3
	//
	STAGE_MAX   byte = 4
)

type TestResult struct {
	stage                  byte
	ok                     bool
	time                   time.Duration
}

type SummeryResult struct {
	stage             byte
	count             int64

	failCount         int64
	totalTime         time.Duration
	totalSquareTime   big.Int
	maxTime           time.Duration
	minTime           time.Duration
	avgTime           time.Duration
	stddevTime        time.Duration
}

func getColumnCount(dsn, query string) (int, error) {
	db, err := (mysql.MySQLDriver{}).Open(dsn)
	if err != nil {
		return 0, err
	}
	defer db.Close()

	rows, err := db.(driver.Queryer).Query(query, []driver.Value{})
	if err != nil {
		return 0, err
	}
	defer rows.Close()
	return len(rows.Columns()), nil
}

func testOnce(dsn, query string, row []driver.Value, result *[STAGE_MAX]TestResult) {
	result[STAGE_TOTAL].ok = false
	beforeConn := time.Now()
	db, err := (mysql.MySQLDriver{}).Open(dsn)
	if err != nil {
		result[STAGE_CONN].ok = false
		return
	}
	result[STAGE_CONN].ok = true
	afterConn := time.Now()
	result[STAGE_CONN].time = afterConn.Sub(beforeConn)
	defer db.Close()

	rows, err := db.(driver.Queryer).Query(query, []driver.Value{})
	if err != nil {
		result[STAGE_QUERY].ok = false
		return
	}
	afterQuery := time.Now()
	result[STAGE_QUERY].ok = true
	result[STAGE_QUERY].time = afterQuery.Sub(afterConn)
	defer rows.Close()
	for {
		err = rows.Next(row)
		if err != nil {
			break
		}
	}
	if err != io.EOF {
		result[STAGE_QUERY].ok = false
	} else {
		afterRead := time.Now()
		result[STAGE_READ].ok = true
		result[STAGE_TOTAL].ok = true
		result[STAGE_READ].time = afterRead.Sub(afterQuery)
		result[STAGE_TOTAL].time = afterRead.Sub(beforeConn)
	}
}

func testRoutine(dsn, query string, n int, colNum int, outChan chan<- [STAGE_MAX]TestResult) {
	var result [STAGE_MAX]TestResult
	result[STAGE_CONN].stage = STAGE_CONN
	result[STAGE_QUERY].stage = STAGE_QUERY
	result[STAGE_READ].stage = STAGE_READ
	result[STAGE_TOTAL].stage = STAGE_TOTAL

	row := make([]driver.Value, colNum)
	for i := 0; i < n; i++ {
		testOnce(dsn, query, row, &result)
		outChan <-result
	}
}

func summeryRoutine(inChan <-chan [STAGE_MAX]TestResult, outChan chan<- [STAGE_MAX]SummeryResult, summeryIntervalSecond int) {
	var ret   [STAGE_MAX]SummeryResult
	var bigA  big.Int
	var ticker *time.Ticker
	for i := byte(0); i < STAGE_MAX; i++ {
		ret[i].minTime = math.MaxInt64
		ret[i].stage = (byte)(i)
	}

	if summeryIntervalSecond > 0 {
		summeryInterval := time.Second * time.Duration(summeryIntervalSecond)
		ticker = time.NewTicker(summeryInterval)
	}
	for result := range inChan {
		for i := byte(0); i < STAGE_MAX; i++ {
			ret[i].count++
			if result[i].ok {
				if result[i].time > ret[i].maxTime {
					ret[i].maxTime = result[i].time
				}
				if result[i].time < ret[i].minTime {
					ret[i].minTime = result[i].time
				}
				ret[i].totalTime+= result[i].time
				bigA.SetInt64((int64)(result[i].time)).Mul(&bigA, &bigA)
				ret[i].totalSquareTime.Add(&ret[i].totalSquareTime, &bigA)
			} else {
				ret[i].failCount++
			}

		}
		if summeryIntervalSecond > 0 {
			select {
			case <-ticker.C:
				for i := byte(0); i < STAGE_MAX; i++ {
					ret[i].Summery()
				}
				outChan<-ret
				ret = [STAGE_MAX]SummeryResult{}
				for i := byte(0); i < STAGE_MAX; i++ {
					ret[i].minTime = math.MaxInt64
					ret[i].stage = (byte)(i)
				}
                        default:
				//
			}
		}
	}
	for i := byte(0); i < STAGE_MAX; i++ {
		ret[i].Summery()
	}
	outChan<-ret
	close(outChan)
	return
}

func (self *SummeryResult) Summery() {
	var bigA, big2 big.Int
	var bigR1, bigR2, big1N, big1N1 big.Rat
	big2.SetInt64(2)
	//  ∑(i-miu)2 = ∑(i2)-(∑i)2/n
	n := self.count - self.failCount
	if n > 1 {
		self.avgTime = (time.Duration)((int64)(self.totalTime) / n)

		big1N.SetInt64(n).Inv(&big1N) // 1/n
		big1N1.SetInt64(n-1).Inv(&big1N1) // 1/(n-1)
		bigA.SetInt64((int64)(self.totalTime)).Mul(&bigA, &bigA) // (∑i)2
		bigR1.SetInt(&bigA).Mul(&bigR1, &big1N) // (∑i)2/n
		bigR2.SetInt(&self.totalSquareTime).Sub(&bigR2, &bigR1)
		s2, _ := bigR2.Mul(&bigR2, &big1N1).Float64()
		self.stddevTime = (time.Duration)((int64)(math.Sqrt(s2)))
	}
	if self.minTime == math.MaxInt64 {
		self.minTime = 0
	}
}

func msStr(t time.Duration) string {
	return fmt.Sprintf("%0.3f ms", float64(int64(t) / 1000) / 1000.0)
}

type NullLogger struct{}
func (*NullLogger) Print(v ...interface{}) {
}

// mysqlburst -c 2000 -r 30 -d 'mha:M616VoUJBnYFi0L02Y24@tcp(10.200.180.54:3342)/x?timeout=5s&readTimeout=3s&writeTimeout=3s'
func main() {
	runtime.GOMAXPROCS(runtime.NumCPU())
	//go func() {
	//      http.ListenAndServe("localhost:6060", nil)
	//}()

	procs := 0
	rounds := 0
	dsn := ""
	query := ""
	summeryIntervalSec := 0
	flag.IntVar(&procs, "c", 1000, "concurrency")
	flag.IntVar(&rounds, "r", 100, "rounds")
	flag.StringVar(&dsn, "d", "mysql:@tcp(127.0.0.1:3306)/mysql?timeout=5s&readTimeout=5s&writeTimeout=5s", "dsn")
	flag.StringVar(&query, "q", "select 1", "sql")
	flag.IntVar(&summeryIntervalSec, "i", 0, "summery interval (sec)")
	flag.Parse()

	mysql.SetLogger(&NullLogger{})

	colNum, err := getColumnCount(dsn, query)
	if err != nil {
		fmt.Printf("init failed: %s", err)
		os.Exit(2)
	}
	wg := sync.WaitGroup{}
	wg.Add(procs)
	resultChan := make(chan [STAGE_MAX]TestResult, 5000)
	summeryChan := make(chan [STAGE_MAX]SummeryResult, 10)

	go func() {
		for i := 0; i < procs; i++ {
			go func() {
				testRoutine(dsn, query, rounds, colNum, resultChan)
				wg.Done()
			}()
		}
		wg.Wait()
		close(resultChan)
	}()
	go summeryRoutine(resultChan, summeryChan, summeryIntervalSec)

	testBegin := time.Now()
	titles := [STAGE_MAX]string{
		"connect", "query", "read", "total",
	}
	for summery := range summeryChan {
		testEnd := time.Now()
		duration:= testEnd.Sub(testBegin)
		testBegin = testEnd

		fmt.Printf("time: %s\n", duration.String())
		//fmt.Printf("tests: %d\n", summery.count);
		for i, title := range titles {
			fmt.Printf("%-8s count: %-10d failed: %-8d avg: %-14s min: %-14s max: %-14s stddev: %-14s\n",
					title, summery[i].count, summery[i].failCount,
					msStr(summery[i].avgTime), msStr(summery[i].minTime), msStr(summery[i].maxTime), msStr(summery[i].stddevTime))
		}
		fmt.Println()
	}
}

<|endoftext|>


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

package generic

import (
	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/servicelabel"

	"github.com/ligato/cn-infra/logging/logmanager"
	"github.com/ligato/cn-infra/statuscheck"
)

// Flavor glues together multiple plugins that are useful for almost every micro-service
type Flavor struct {
	Logrus       logrus.Plugin
	HTTP         httpmux.Plugin
	LogManager   logmanager.Plugin
	ServiceLabel servicelabel.Plugin
	StatusCheck  statuscheck.Plugin

	injected bool
}

// Inject sets object references
func (f *Flavor) Inject() error {
	if f.injected {
		return nil
	}

	//f.HTTP.LogFactory = &f.Logrus

	f.HTTP.Logger = f.Logrus.LoggerWithPrefix(f.PluginName(&f.HTTP))
	f.HTTP.Config = f.Config.ConfigWithPrefix(f.PluginName(&f.HTTP))

	f.LogManager.ManagedLoggers = &f.Logrus
	f.LogManager.HTTP = &f.HTTP
	f.StatusCheck.HTTP = &f.HTTP

	f.injected = true

	return nil
}

// Plugins combines all Plugins in flavor to the list
func (f *Flavor) Plugins() []*core.NamedPlugin {
	f.Inject()
	return core.ListPluginsInFlavor(f)
}
<commit_msg> ODPM-361 renamed generic flavor (to be prepared for anonymous composi.)<commit_after>// Copyright (c) 2017 Cisco and/or its affiliates.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package generic

import (
	"github.com/ligato/cn-infra/core"
	"github.com/ligato/cn-infra/httpmux"
	"github.com/ligato/cn-infra/logging/logrus"
	"github.com/ligato/cn-infra/servicelabel"

	"github.com/ligato/cn-infra/logging/logmanager"
	"github.com/ligato/cn-infra/statuscheck"
)

// FlavorGeneric glues together multiple plugins that are useful for almost every micro-service
type FlavorGeneric struct {
	Logrus       logrus.Plugin
	HTTP         httpmux.Plugin
	LogManager   logmanager.Plugin
	ServiceLabel servicelabel.Plugin
	StatusCheck  statuscheck.Plugin

	injected bool
}

// Inject sets object references
func (f *FlavorGeneric) Inject() error {
	if f.injected {
		return nil
	}

	f.HTTP.LogFactory = &f.Logrus
	//TODO f.HTTP.Logger = f.Logrus.LoggerWithPrefix(f.PluginName(&f.HTTP))
	//TODO f.HTTP.Config = f.Config.ConfigWithPrefix(f.PluginName(&f.HTTP))
	f.LogManager.ManagedLoggers = &f.Logrus
	f.LogManager.HTTP = &f.HTTP
	f.StatusCheck.HTTP = &f.HTTP

	f.injected = true

	return nil
}

// Plugins combines all Plugins in flavor to the list
func (f *FlavorGeneric) Plugins() []*core.NamedPlugin {
	f.Inject()
	return core.ListPluginsInFlavor(f)
}
<|endoftext|>


<commit_before>package filter

import (
	"fmt"

	con "github.com/Cepave/open-falcon-backend/modules/f2e-api/config"
)

type GrpHosts struct {
	GrpName  string `json:"grp_name";orm:"grp_name"`
	Hostname string `json:"hostname";orm:"hostname"`
}

func HostGroupFilter(filterTxt string, limit int) []GrpHosts {
	db := con.Con()
	sqlbuild := fmt.Sprintf(`select g2.id, g2.grp_name, h2.hostname from host h2 INNER JOIN (select g.id, g.grp_name, h.host_id from grp g INNER JOIN grp_host h
	on g.id = h.grp_id
	where g.grp_name regexp '%s') g2 on g2.host_id = h2.id limit %d`, filterTxt, limit)
	res := []GrpHosts{}
	db.Falcon.Raw(sqlbuild).Scan(&res)
	return res
}
<commit_msg>fix go struct tag formating issue of GrpHosts<commit_after>package filter

import (
	"fmt"

	con "github.com/Cepave/open-falcon-backend/modules/f2e-api/config"
)

type GrpHosts struct {
	GrpName  string `json:"grp_name" orm:"grp_name"`
	Hostname string `json:"hostname" orm:"hostname"`
}

func HostGroupFilter(filterTxt string, limit int) []GrpHosts {
	db := con.Con()
	sqlbuild := fmt.Sprintf(`select g2.id, g2.grp_name, h2.hostname from host h2 INNER JOIN (select g.id, g.grp_name, h.host_id from grp g INNER JOIN grp_host h
	on g.id = h.grp_id
	where g.grp_name regexp '%s') g2 on g2.host_id = h2.id limit %d`, filterTxt, limit)
	res := []GrpHosts{}
	db.Falcon.Raw(sqlbuild).Scan(&res)
	return res
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package blockchain

import (
	"fmt"

	"github.com/ppcsuite/btcutil"
	"github.com/ppcsuite/ppcd/wire"
)

// maybeAcceptBlock potentially accepts a block into the memory block chain.
// It performs several validation checks which depend on its position within
// the block chain before adding it.  The block is expected to have already gone
// through ProcessBlock before calling this function with it.
//
// The flags modify the behavior of this function as follows:
//  - BFFastAdd: The somewhat expensive BIP0034 validation is not performed.
//  - BFDryRun: The memory chain index will not be pruned and no accept
//    notification will be sent since the block is not being accepted.
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, timeSource MedianTimeSource, flags BehaviorFlags) error {

	defer timeTrack(now(), fmt.Sprintf("maybeAcceptBlock(%v)", slice(block.Sha())[0]))

	fastAdd := flags&BFFastAdd == BFFastAdd
	dryRun := flags&BFDryRun == BFDryRun

	// Get a block node for the block previous to this one.  Will be nil
	// if this is the genesis block.
	prevNode, err := b.getPrevNodeFromBlock(block)
	if err != nil {
		log.Errorf("getPrevNodeFromBlock: %v", err)
		return err
	}

	// The height of this block is one more than the referenced previous
	// block.
	blockHeight := int64(0)
	if prevNode != nil {
		blockHeight = prevNode.height + 1
	}
	block.SetHeight(blockHeight)

	blockHeader := &block.MsgBlock().Header
	if !fastAdd {
		// Ensure the difficulty specified in the block header matches
		// the calculated difficulty based on the previous block and
		// difficulty retarget rules.
		expectedDifficulty, err := b.ppcCalcNextRequiredDifficulty(
			prevNode, block.IsProofOfStake())
		if err != nil {
			return err
		}
		blockDifficulty := blockHeader.Bits
		if blockDifficulty != expectedDifficulty {
			log.Infof("maybeAcceptBlock : block %v, prevNode %v(%d)", btcutil.Slice(block.Sha())[0], prevNode.hash, prevNode.bits)
			str := "block difficulty of %d is not the expected value of %d"
			str = fmt.Sprintf(str, blockDifficulty, expectedDifficulty)
			return ruleError(ErrUnexpectedDifficulty, str)
		}

		// Ensure the timestamp for the block header is after the
		// median time of the last several blocks (medianTimeBlocks).
		medianTime, err := b.calcPastMedianTime(prevNode)
		if err != nil {
			log.Errorf("calcPastMedianTime: %v", err)
			return err
		}
		if !blockHeader.Timestamp.After(medianTime) {
			str := "block timestamp of %v is not after expected %v"
			str = fmt.Sprintf(str, blockHeader.Timestamp, medianTime)
			return ruleError(ErrTimeTooOld, str)
		}

		// Ensure all transactions in the block are finalized.
		for _, tx := range block.Transactions() {
			if !IsFinalizedTransaction(tx, blockHeight,
				blockHeader.Timestamp) {
				str := fmt.Sprintf("block contains "+
					"unfinalized transaction %v", tx.Sha())
				return ruleError(ErrUnfinalizedTx, str)
			}
		}

	}

	// Ensure chain matches up to predetermined checkpoints.
	blockHash := block.Sha()
	if !b.verifyCheckpoint(blockHeight, blockHash) {
		str := fmt.Sprintf("block at height %d does not match "+
			"checkpoint hash", blockHeight)
		return ruleError(ErrBadCheckpoint, str)
	}

	// Find the previous checkpoint and prevent blocks which fork the main
	// chain before it.  This prevents storage of new, otherwise valid,
	// blocks which build off of old blocks that are likely at a much easier
	// difficulty and therefore could be used to waste cache and disk space.
	checkpointBlock, err := b.findPreviousCheckpoint()
	if err != nil {
		return err
	}
	if checkpointBlock != nil && blockHeight < checkpointBlock.Height() {
		str := fmt.Sprintf("block at height %d forks the main chain "+
			"before the previous checkpoint at height %d",
			blockHeight, checkpointBlock.Height())
		return ruleError(ErrForkTooOld, str)
	}

	if !fastAdd && b.chainParams.Net != wire.TestNet3 {
		// Reject version 2 blocks once a majority of the network has
		// upgraded.  This is part of BIP0066.
		/* ppc: if blockHeader.Version < 3 && b.isMajorityVersion(3, prevNode,
			b.chainParams.BlockRejectNumRequired) {

			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return ruleError(ErrBlockVersionTooOld, str)
		}*/

		// Reject version 1 blocks once a majority of the network has
		// upgraded.  This is part of BIP0034.
		if blockHeader.Version < 2 && b.isMajorityVersion(2, prevNode,
			b.chainParams.BlockRejectNumRequired) {

			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return ruleError(ErrBlockVersionTooOld, str)
		}

		// Ensure coinbase starts with serialized block heights for
		// blocks whose version is the serializedHeightVersion or
		// newer once a majority of the network has upgraded.  This is
		// part of BIP0034.
		if ShouldHaveSerializedBlockHeight(blockHeader) &&
			b.isMajorityVersion(serializedHeightVersion, prevNode,
				b.chainParams.BlockEnforceNumRequired) {

			expectedHeight := int64(0)
			if prevNode != nil {
				expectedHeight = prevNode.height + 1
			}
			coinbaseTx := block.Transactions()[0]
			err := checkSerializedHeight(coinbaseTx, expectedHeight)
			if err != nil {
				return err
			}
		}
	}

	// ppc: verify hash target and signature of coinstake tx
	// TODO(mably) is it the best place to do that?
	// TODO(mably) a timeSource param is needed to get the AdjustedTime
	err = b.checkBlockProofOfStake(block, timeSource)
	if err != nil {
		str := fmt.Sprintf("Proof of stake check failed for block %v : %v", blockHash, err)
		return ruleError(ErrProofOfStakeCheck, str)
	}

	// ppc: populate all ppcoin specific block meta data
	err = b.addToBlockIndex(block)
	if err != nil {
		return err
	}

	// Prune block nodes which are no longer needed before creating
	// a new node.
	if !dryRun {
		err = b.pruneBlockNodes()
		if err != nil {
			return err
		}
	}

	// ppcoin: populate all ppcoin specific block meta data
	err = b.addToBlockIndex(block)
	if err != nil {
		return err
	}

	// Create a new block node for the block and add it to the in-memory
	// block chain (could be either a side chain or the main chain).
	newNode := ppcNewBlockNode(
		blockHeader, blockHash, blockHeight, block.Meta()) // peercoin
	if prevNode != nil { // Not genesis block
		newNode.parent = prevNode
		newNode.height = blockHeight
		// newNode.workSum has been initialied to block trust in ppcNewBlockNode
		newNode.workSum.Add(prevNode.workSum, newNode.workSum)
	}

	// Connect the passed block to the chain while respecting proper chain
	// selection according to the chain with the most proof of work.  This
	// also handles validation of the transaction scripts.
	err = b.connectBestChain(newNode, block, flags)
	if err != nil {
		return err
	}

	// Notify the caller that the new block was accepted into the block
	// chain.  The caller would typically want to react by relaying the
	// inventory to other peers.
	if !dryRun {
		b.sendNotification(NTBlockAccepted, block)
	}

	return nil
}
<commit_msg>Remove duplicated code<commit_after>// Copyright (c) 2013-2015 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package blockchain

import (
	"fmt"

	"github.com/ppcsuite/btcutil"
	"github.com/ppcsuite/ppcd/wire"
)

// maybeAcceptBlock potentially accepts a block into the memory block chain.
// It performs several validation checks which depend on its position within
// the block chain before adding it.  The block is expected to have already gone
// through ProcessBlock before calling this function with it.
//
// The flags modify the behavior of this function as follows:
//  - BFFastAdd: The somewhat expensive BIP0034 validation is not performed.
//  - BFDryRun: The memory chain index will not be pruned and no accept
//    notification will be sent since the block is not being accepted.
func (b *BlockChain) maybeAcceptBlock(block *btcutil.Block, timeSource MedianTimeSource, flags BehaviorFlags) error {

	defer timeTrack(now(), fmt.Sprintf("maybeAcceptBlock(%v)", slice(block.Sha())[0]))

	fastAdd := flags&BFFastAdd == BFFastAdd
	dryRun := flags&BFDryRun == BFDryRun

	// Get a block node for the block previous to this one.  Will be nil
	// if this is the genesis block.
	prevNode, err := b.getPrevNodeFromBlock(block)
	if err != nil {
		log.Errorf("getPrevNodeFromBlock: %v", err)
		return err
	}

	// The height of this block is one more than the referenced previous
	// block.
	blockHeight := int64(0)
	if prevNode != nil {
		blockHeight = prevNode.height + 1
	}
	block.SetHeight(blockHeight)

	blockHeader := &block.MsgBlock().Header
	if !fastAdd {
		// Ensure the difficulty specified in the block header matches
		// the calculated difficulty based on the previous block and
		// difficulty retarget rules.
		expectedDifficulty, err := b.ppcCalcNextRequiredDifficulty(
			prevNode, block.IsProofOfStake())
		if err != nil {
			return err
		}
		blockDifficulty := blockHeader.Bits
		if blockDifficulty != expectedDifficulty {
			log.Infof("maybeAcceptBlock : block %v, prevNode %v(%d)", btcutil.Slice(block.Sha())[0], prevNode.hash, prevNode.bits)
			str := "block difficulty of %d is not the expected value of %d"
			str = fmt.Sprintf(str, blockDifficulty, expectedDifficulty)
			return ruleError(ErrUnexpectedDifficulty, str)
		}

		// Ensure the timestamp for the block header is after the
		// median time of the last several blocks (medianTimeBlocks).
		medianTime, err := b.calcPastMedianTime(prevNode)
		if err != nil {
			log.Errorf("calcPastMedianTime: %v", err)
			return err
		}
		if !blockHeader.Timestamp.After(medianTime) {
			str := "block timestamp of %v is not after expected %v"
			str = fmt.Sprintf(str, blockHeader.Timestamp, medianTime)
			return ruleError(ErrTimeTooOld, str)
		}

		// Ensure all transactions in the block are finalized.
		for _, tx := range block.Transactions() {
			if !IsFinalizedTransaction(tx, blockHeight,
				blockHeader.Timestamp) {
				str := fmt.Sprintf("block contains "+
					"unfinalized transaction %v", tx.Sha())
				return ruleError(ErrUnfinalizedTx, str)
			}
		}

	}

	// Ensure chain matches up to predetermined checkpoints.
	blockHash := block.Sha()
	if !b.verifyCheckpoint(blockHeight, blockHash) {
		str := fmt.Sprintf("block at height %d does not match "+
			"checkpoint hash", blockHeight)
		return ruleError(ErrBadCheckpoint, str)
	}

	// Find the previous checkpoint and prevent blocks which fork the main
	// chain before it.  This prevents storage of new, otherwise valid,
	// blocks which build off of old blocks that are likely at a much easier
	// difficulty and therefore could be used to waste cache and disk space.
	checkpointBlock, err := b.findPreviousCheckpoint()
	if err != nil {
		return err
	}
	if checkpointBlock != nil && blockHeight < checkpointBlock.Height() {
		str := fmt.Sprintf("block at height %d forks the main chain "+
			"before the previous checkpoint at height %d",
			blockHeight, checkpointBlock.Height())
		return ruleError(ErrForkTooOld, str)
	}

	if !fastAdd && b.chainParams.Net != wire.TestNet3 {
		// Reject version 2 blocks once a majority of the network has
		// upgraded.  This is part of BIP0066.
		/* ppc: if blockHeader.Version < 3 && b.isMajorityVersion(3, prevNode,
			b.chainParams.BlockRejectNumRequired) {

			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return ruleError(ErrBlockVersionTooOld, str)
		}*/

		// Reject version 1 blocks once a majority of the network has
		// upgraded.  This is part of BIP0034.
		if blockHeader.Version < 2 && b.isMajorityVersion(2, prevNode,
			b.chainParams.BlockRejectNumRequired) {

			str := "new blocks with version %d are no longer valid"
			str = fmt.Sprintf(str, blockHeader.Version)
			return ruleError(ErrBlockVersionTooOld, str)
		}

		// Ensure coinbase starts with serialized block heights for
		// blocks whose version is the serializedHeightVersion or
		// newer once a majority of the network has upgraded.  This is
		// part of BIP0034.
		if ShouldHaveSerializedBlockHeight(blockHeader) &&
			b.isMajorityVersion(serializedHeightVersion, prevNode,
				b.chainParams.BlockEnforceNumRequired) {

			expectedHeight := int64(0)
			if prevNode != nil {
				expectedHeight = prevNode.height + 1
			}
			coinbaseTx := block.Transactions()[0]
			err := checkSerializedHeight(coinbaseTx, expectedHeight)
			if err != nil {
				return err
			}
		}
	}

	// ppc: verify hash target and signature of coinstake tx
	// TODO(mably) is it the best place to do that?
	// TODO(mably) a timeSource param is needed to get the AdjustedTime
	err = b.checkBlockProofOfStake(block, timeSource)
	if err != nil {
		str := fmt.Sprintf("Proof of stake check failed for block %v : %v", blockHash, err)
		return ruleError(ErrProofOfStakeCheck, str)
	}

	// ppc: populate all ppcoin specific block meta data
	err = b.addToBlockIndex(block)
	if err != nil {
		return err
	}

	// Prune block nodes which are no longer needed before creating
	// a new node.
	if !dryRun {
		err = b.pruneBlockNodes()
		if err != nil {
			return err
		}
	}

	// Create a new block node for the block and add it to the in-memory
	// block chain (could be either a side chain or the main chain).
	newNode := ppcNewBlockNode(
		blockHeader, blockHash, blockHeight, block.Meta()) // peercoin
	if prevNode != nil { // Not genesis block
		newNode.parent = prevNode
		newNode.height = blockHeight
		// newNode.workSum has been initialied to block trust in ppcNewBlockNode
		newNode.workSum.Add(prevNode.workSum, newNode.workSum)
	}

	// Connect the passed block to the chain while respecting proper chain
	// selection according to the chain with the most proof of work.  This
	// also handles validation of the transaction scripts.
	err = b.connectBestChain(newNode, block, flags)
	if err != nil {
		return err
	}

	// Notify the caller that the new block was accepted into the block
	// chain.  The caller would typically want to react by relaying the
	// inventory to other peers.
	if !dryRun {
		b.sendNotification(NTBlockAccepted, block)
	}

	return nil
}
<|endoftext|>


<commit_before>package dispatcher

//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg impl -path App,Dispatcher,Default

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/stats"
	"v2ray.com/core/proxy"
	"v2ray.com/core/transport/pipe"
)

var (
	errSniffingTimeout = newError("timeout on sniffing")
)

type cachedReader struct {
	reader *pipe.Reader
	cache  buf.MultiBuffer
}

func (r *cachedReader) Cache(b *buf.Buffer) {
	mb, _ := r.reader.ReadMultiBufferWithTimeout(time.Millisecond * 100)
	if !mb.IsEmpty() {
		common.Must(r.cache.WriteMultiBuffer(mb))
	}
	common.Must(b.Reset(func(x []byte) (int, error) {
		return r.cache.Copy(x), nil
	}))
}

func (r *cachedReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	if !r.cache.IsEmpty() {
		mb := r.cache
		r.cache = nil
		return mb, nil
	}

	return r.reader.ReadMultiBuffer()
}

func (r *cachedReader) CloseError() {
	r.cache.Release()
	r.reader.CloseError()
}

// DefaultDispatcher is a default implementation of Dispatcher.
type DefaultDispatcher struct {
	ohm    core.OutboundHandlerManager
	router core.Router
	policy core.PolicyManager
	stats  core.StatManager
}

// NewDefaultDispatcher create a new DefaultDispatcher.
func NewDefaultDispatcher(ctx context.Context, config *Config) (*DefaultDispatcher, error) {
	v := core.MustFromContext(ctx)
	d := &DefaultDispatcher{
		ohm:    v.OutboundHandlerManager(),
		router: v.Router(),
		policy: v.PolicyManager(),
		stats:  v.Stats(),
	}

	if err := v.RegisterFeature((*core.Dispatcher)(nil), d); err != nil {
		return nil, newError("unable to register Dispatcher").Base(err)
	}
	return d, nil
}

// Start implements common.Runnable.
func (*DefaultDispatcher) Start() error {
	return nil
}

// Close implements common.Closable.
func (*DefaultDispatcher) Close() error { return nil }

func (d *DefaultDispatcher) getLink(ctx context.Context) (*core.Link, *core.Link) {
	uplinkReader, uplinkWriter := pipe.New()
	downlinkReader, downlinkWriter := pipe.New()

	inboundLink := &core.Link{
		Reader: downlinkReader,
		Writer: uplinkWriter,
	}

	outboundLink := &core.Link{
		Reader: uplinkReader,
		Writer: downlinkWriter,
	}

	user := protocol.UserFromContext(ctx)
	if user != nil && len(user.Email) > 0 {
		p := d.policy.ForLevel(user.Level)
		if p.Stats.UserUplink {
			name := "user>>>" + user.Email + ">>>traffic>>>uplink"
			if c, _ := core.GetOrRegisterStatCounter(d.stats, name); c != nil {
				inboundLink.Writer = &stats.SizeStatWriter{
					Counter: c,
					Writer:  inboundLink.Writer,
				}
			}
		}
		if p.Stats.UserDownlink {
			name := "user>>>" + user.Email + ">>>traffic>>>downlink"
			if c, _ := core.GetOrRegisterStatCounter(d.stats, name); c != nil {
				outboundLink.Writer = &stats.SizeStatWriter{
					Counter: c,
					Writer:  outboundLink.Writer,
				}
			}
		}
	}

	return inboundLink, outboundLink
}

// Dispatch implements core.Dispatcher.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*core.Link, error) {
	if !destination.IsValid() {
		panic("Dispatcher: Invalid destination.")
	}
	ctx = proxy.ContextWithTarget(ctx, destination)

	inbound, outbound := d.getLink(ctx)
	snifferList := proxyman.ProtocolSniffersFromContext(ctx)
	if destination.Address.Family().IsDomain() || len(snifferList) == 0 {
		go d.routedDispatch(ctx, outbound, destination)
	} else {
		go func() {
			cReader := &cachedReader{
				reader: outbound.Reader.(*pipe.Reader),
			}
			outbound.Reader = cReader
			domain, err := sniffer(ctx, snifferList, cReader)
			if err == nil {
				newError("sniffed domain: ", domain).WithContext(ctx).WriteToLog()
				destination.Address = net.ParseAddress(domain)
				ctx = proxy.ContextWithTarget(ctx, destination)
			}
			d.routedDispatch(ctx, outbound, destination)
		}()
	}
	return inbound, nil
}

func sniffer(ctx context.Context, snifferList []proxyman.KnownProtocols, cReader *cachedReader) (string, error) {
	payload := buf.New()
	defer payload.Release()

	sniffer := NewSniffer(snifferList)
	totalAttempt := 0
	for {
		select {
		case <-ctx.Done():
			return "", ctx.Err()
		default:
			totalAttempt++
			if totalAttempt > 5 {
				return "", errSniffingTimeout
			}

			cReader.Cache(payload)
			if !payload.IsEmpty() {
				domain, err := sniffer.Sniff(payload.Bytes())
				if err != ErrMoreData {
					return domain, err
				}
			}
			if payload.IsFull() {
				return "", ErrInvalidData
			}
			time.Sleep(time.Millisecond * 100)
		}
	}
}

func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *core.Link, destination net.Destination) {
	dispatcher := d.ohm.GetDefaultHandler()
	if d.router != nil {
		if tag, err := d.router.PickRoute(ctx); err == nil {
			if handler := d.ohm.GetHandler(tag); handler != nil {
				newError("taking detour [", tag, "] for [", destination, "]").WithContext(ctx).WriteToLog()
				dispatcher = handler
			} else {
				newError("non existing tag: ", tag).AtWarning().WithContext(ctx).WriteToLog()
			}
		} else {
			newError("default route for ", destination).WithContext(ctx).WriteToLog()
		}
	}
	dispatcher.Dispatch(ctx, link)
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewDefaultDispatcher(ctx, config.(*Config))
	}))
}
<commit_msg>sniff on TCP only<commit_after>package dispatcher

//go:generate go run $GOPATH/src/v2ray.com/core/common/errors/errorgen/main.go -pkg impl -path App,Dispatcher,Default

import (
	"context"
	"time"

	"v2ray.com/core"
	"v2ray.com/core/app/proxyman"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/protocol"
	"v2ray.com/core/common/stats"
	"v2ray.com/core/proxy"
	"v2ray.com/core/transport/pipe"
)

var (
	errSniffingTimeout = newError("timeout on sniffing")
)

type cachedReader struct {
	reader *pipe.Reader
	cache  buf.MultiBuffer
}

func (r *cachedReader) Cache(b *buf.Buffer) {
	mb, _ := r.reader.ReadMultiBufferWithTimeout(time.Millisecond * 100)
	if !mb.IsEmpty() {
		common.Must(r.cache.WriteMultiBuffer(mb))
	}
	common.Must(b.Reset(func(x []byte) (int, error) {
		return r.cache.Copy(x), nil
	}))
}

func (r *cachedReader) ReadMultiBuffer() (buf.MultiBuffer, error) {
	if !r.cache.IsEmpty() {
		mb := r.cache
		r.cache = nil
		return mb, nil
	}

	return r.reader.ReadMultiBuffer()
}

func (r *cachedReader) CloseError() {
	r.cache.Release()
	r.reader.CloseError()
}

// DefaultDispatcher is a default implementation of Dispatcher.
type DefaultDispatcher struct {
	ohm    core.OutboundHandlerManager
	router core.Router
	policy core.PolicyManager
	stats  core.StatManager
}

// NewDefaultDispatcher create a new DefaultDispatcher.
func NewDefaultDispatcher(ctx context.Context, config *Config) (*DefaultDispatcher, error) {
	v := core.MustFromContext(ctx)
	d := &DefaultDispatcher{
		ohm:    v.OutboundHandlerManager(),
		router: v.Router(),
		policy: v.PolicyManager(),
		stats:  v.Stats(),
	}

	if err := v.RegisterFeature((*core.Dispatcher)(nil), d); err != nil {
		return nil, newError("unable to register Dispatcher").Base(err)
	}
	return d, nil
}

// Start implements common.Runnable.
func (*DefaultDispatcher) Start() error {
	return nil
}

// Close implements common.Closable.
func (*DefaultDispatcher) Close() error { return nil }

func (d *DefaultDispatcher) getLink(ctx context.Context) (*core.Link, *core.Link) {
	uplinkReader, uplinkWriter := pipe.New()
	downlinkReader, downlinkWriter := pipe.New()

	inboundLink := &core.Link{
		Reader: downlinkReader,
		Writer: uplinkWriter,
	}

	outboundLink := &core.Link{
		Reader: uplinkReader,
		Writer: downlinkWriter,
	}

	user := protocol.UserFromContext(ctx)
	if user != nil && len(user.Email) > 0 {
		p := d.policy.ForLevel(user.Level)
		if p.Stats.UserUplink {
			name := "user>>>" + user.Email + ">>>traffic>>>uplink"
			if c, _ := core.GetOrRegisterStatCounter(d.stats, name); c != nil {
				inboundLink.Writer = &stats.SizeStatWriter{
					Counter: c,
					Writer:  inboundLink.Writer,
				}
			}
		}
		if p.Stats.UserDownlink {
			name := "user>>>" + user.Email + ">>>traffic>>>downlink"
			if c, _ := core.GetOrRegisterStatCounter(d.stats, name); c != nil {
				outboundLink.Writer = &stats.SizeStatWriter{
					Counter: c,
					Writer:  outboundLink.Writer,
				}
			}
		}
	}

	return inboundLink, outboundLink
}

// Dispatch implements core.Dispatcher.
func (d *DefaultDispatcher) Dispatch(ctx context.Context, destination net.Destination) (*core.Link, error) {
	if !destination.IsValid() {
		panic("Dispatcher: Invalid destination.")
	}
	ctx = proxy.ContextWithTarget(ctx, destination)

	inbound, outbound := d.getLink(ctx)
	snifferList := proxyman.ProtocolSniffersFromContext(ctx)
	if destination.Address.Family().IsDomain() || destination.Network != net.Network_TCP || len(snifferList) == 0 {
		go d.routedDispatch(ctx, outbound, destination)
	} else {
		go func() {
			cReader := &cachedReader{
				reader: outbound.Reader.(*pipe.Reader),
			}
			outbound.Reader = cReader
			domain, err := sniffer(ctx, snifferList, cReader)
			if err == nil {
				newError("sniffed domain: ", domain).WithContext(ctx).WriteToLog()
				destination.Address = net.ParseAddress(domain)
				ctx = proxy.ContextWithTarget(ctx, destination)
			}
			d.routedDispatch(ctx, outbound, destination)
		}()
	}
	return inbound, nil
}

func sniffer(ctx context.Context, snifferList []proxyman.KnownProtocols, cReader *cachedReader) (string, error) {
	payload := buf.New()
	defer payload.Release()

	sniffer := NewSniffer(snifferList)
	totalAttempt := 0
	for {
		select {
		case <-ctx.Done():
			return "", ctx.Err()
		default:
			totalAttempt++
			if totalAttempt > 5 {
				return "", errSniffingTimeout
			}

			cReader.Cache(payload)
			if !payload.IsEmpty() {
				domain, err := sniffer.Sniff(payload.Bytes())
				if err != ErrMoreData {
					return domain, err
				}
			}
			if payload.IsFull() {
				return "", ErrInvalidData
			}
			time.Sleep(time.Millisecond * 100)
		}
	}
}

func (d *DefaultDispatcher) routedDispatch(ctx context.Context, link *core.Link, destination net.Destination) {
	dispatcher := d.ohm.GetDefaultHandler()
	if d.router != nil {
		if tag, err := d.router.PickRoute(ctx); err == nil {
			if handler := d.ohm.GetHandler(tag); handler != nil {
				newError("taking detour [", tag, "] for [", destination, "]").WithContext(ctx).WriteToLog()
				dispatcher = handler
			} else {
				newError("non existing tag: ", tag).AtWarning().WithContext(ctx).WriteToLog()
			}
		} else {
			newError("default route for ", destination).WithContext(ctx).WriteToLog()
		}
	}
	dispatcher.Dispatch(ctx, link)
}

func init() {
	common.Must(common.RegisterConfig((*Config)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewDefaultDispatcher(ctx, config.(*Config))
	}))
}
<|endoftext|>


<commit_before>package azurerm

import (
	"bytes"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/Azure/azure-sdk-for-go/arm/web"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jen20/riviera/azure"
)

func resourceArmAppServicePlan() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmAppServicePlanCreateUpdate,
		Read:   resourceArmAppServicePlanRead,
		Update: resourceArmAppServicePlanCreateUpdate,
		Delete: resourceArmAppServicePlanDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"sku": {
				Type:     schema.TypeSet,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"tier": {
							Type:     schema.TypeString,
							Required: true,
						},
						"size": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
				Set: resourceAzureRMAppServicePlanSkuHash,
			},

			"properties": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"maximum_number_of_workers": {
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"reserved": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
						"per_site_scaling": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
					},
				},
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmAppServicePlanCreateUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).appServicePlansClient

	log.Printf("[INFO] preparing arguments for AzureRM App Service Plan creation.")

	resGroup := d.Get("resource_group_name").(string)
	name := d.Get("name").(string)
	location := d.Get("location").(string)
	tags := d.Get("tags").(map[string]interface{})

	sku := expandAzureRmAppServicePlanSku(d)
	properties := expandAppServicePlanProperties(d)

	appServicePlan := web.AppServicePlan{
		Location:                 &location,
		AppServicePlanProperties: properties,
		Tags: expandTags(tags),
		Sku:  &sku,
	}

	_, createErr := client.CreateOrUpdate(resGroup, name, appServicePlan, make(chan struct{}))
	err := <-createErr
	if err != nil {
		return err
	}

	read, err := client.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read AzureRM App Service Plan %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	// TODO: is this needed?
	log.Printf("[DEBUG] Waiting for App Service Plan (%s) to become available", name)
	stateConf := &resource.StateChangeConf{
		Pending: []string{"Accepted", "Updating"},
		Target:  []string{"Succeeded"},
		Refresh: appServicePlanStateRefreshFunc(client, resGroup, name),
		Timeout: 10 * time.Minute,
	}
	if _, err := stateConf.WaitForState(); err != nil {
		return fmt.Errorf("Error waiting for App Service Plan (%s) to become available: %+v", name, err)
	}

	return resourceArmAppServicePlanRead(d, meta)
}

func resourceArmAppServicePlanRead(d *schema.ResourceData, meta interface{}) error {
	AppServicePlanClient := meta.(*ArmClient).appServicePlansClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Reading Azure App Service Plan %s", id)

	resGroup := id.ResourceGroup
	name := id.Path["serverfarms"]

	resp, err := AppServicePlanClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error making Read request on Azure App Service Plan %s: %+v", name, err)
	}

	d.Set("name", name)
	d.Set("resource_group_name", resGroup)
	d.Set("location", azureRMNormalizeLocation(*resp.Location))

	if props := resp.AppServicePlanProperties; props != nil {
		d.Set("properties", flattenAppServiceProperties(props))
	}

	if sku := resp.Sku; sku != nil {
		d.Set("sku", flattenAzureRmAppServicePlanSku(sku))
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmAppServicePlanDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).appServicePlansClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["serverfarms"]

	log.Printf("[DEBUG] Deleting app service plan %s: %s", resGroup, name)

	_, err = client.Delete(resGroup, name)

	return err
}

func resourceAzureRMAppServicePlanSkuHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	tier := m["tier"].(string)
	size := m["size"].(string)

	buf.WriteString(fmt.Sprintf("%s-", tier))
	buf.WriteString(fmt.Sprintf("%s-", size))

	return hashcode.String(buf.String())
}

func expandAzureRmAppServicePlanSku(d *schema.ResourceData) web.SkuDescription {
	configs := d.Get("sku").(*schema.Set).List()
	config := configs[0].(map[string]interface{})

	tier := config["tier"].(string)
	size := config["size"].(string)

	sku := web.SkuDescription{
		Name: &size,
		Tier: &tier,
		Size: &size,
	}

	return sku
}

func flattenAzureRmAppServicePlanSku(profile *web.SkuDescription) *schema.Set {
	skus := &schema.Set{
		F: resourceAzureRMAppServicePlanSkuHash,
	}

	sku := make(map[string]interface{}, 2)

	sku["tier"] = *profile.Tier
	sku["size"] = *profile.Size

	skus.Add(sku)

	return skus
}

func expandAppServicePlanProperties(d *schema.ResourceData) *web.AppServicePlanProperties {
	configs := d.Get("properties").([]interface{})
	properties := web.AppServicePlanProperties{}
	if len(configs) == 0 {
		return &properties
	}
	config := configs[0].(map[string]interface{})

	perSiteScaling := config["per_site_scaling"].(bool)
	properties.PerSiteScaling = azure.Bool(perSiteScaling)

	reserved := config["reserved"].(bool)
	properties.Reserved = azure.Bool(reserved)

	if v, ok := config["maximum_number_of_workers"]; ok {
		maximumNumberOfWorkers := int32(v.(int))
		properties.MaximumNumberOfWorkers = &maximumNumberOfWorkers
	}

	return &properties
}

func flattenAppServiceProperties(props *web.AppServicePlanProperties) map[string]interface{} {
	properties := make(map[string]interface{}, 0)

	if props.MaximumNumberOfWorkers != nil {
		properties["maximum_number_of_workers"] = int(*props.MaximumNumberOfWorkers)
	}

	if props.PerSiteScaling != nil {
		properties["per_site_scaling"] = *props.PerSiteScaling
	}

	if props.Reserved != nil {
		properties["reserved"] = *props.Reserved
	}

	return properties
}

func appServicePlanStateRefreshFunc(client web.AppServicePlansClient, resourceGroupName string, name string) resource.StateRefreshFunc {
	return func() (interface{}, string, error) {
		res, err := client.Get(resourceGroupName, name)
		if err != nil {
			return nil, "", fmt.Errorf("Error issuing read request in appServicePlanStateRefreshFunc to Azure ARM for App Service Plan '%s' (RG: '%s'): %+v", name, resourceGroupName, err)
		}

		return res, string(res.AppServicePlanProperties.ProvisioningState), nil
	}
}
<commit_msg>Removing an unnecessary poll<commit_after>package azurerm

import (
	"bytes"
	"fmt"
	"log"
	"net/http"

	"github.com/Azure/azure-sdk-for-go/arm/web"
	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
	"github.com/jen20/riviera/azure"
)

func resourceArmAppServicePlan() *schema.Resource {
	return &schema.Resource{
		Create: resourceArmAppServicePlanCreateUpdate,
		Read:   resourceArmAppServicePlanRead,
		Update: resourceArmAppServicePlanCreateUpdate,
		Delete: resourceArmAppServicePlanDelete,
		Importer: &schema.ResourceImporter{
			State: schema.ImportStatePassthrough,
		},

		Schema: map[string]*schema.Schema{
			"name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"resource_group_name": {
				Type:     schema.TypeString,
				Required: true,
				ForceNew: true,
			},

			"location": locationSchema(),

			"sku": {
				Type:     schema.TypeSet,
				Required: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"tier": {
							Type:     schema.TypeString,
							Required: true,
						},
						"size": {
							Type:     schema.TypeString,
							Required: true,
						},
					},
				},
				Set: resourceAzureRMAppServicePlanSkuHash,
			},

			"properties": {
				Type:     schema.TypeList,
				Optional: true,
				MaxItems: 1,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"maximum_number_of_workers": {
							Type:     schema.TypeInt,
							Optional: true,
							Computed: true,
						},
						"reserved": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
						"per_site_scaling": {
							Type:     schema.TypeBool,
							Optional: true,
							Default:  false,
						},
					},
				},
			},

			"tags": tagsSchema(),
		},
	}
}

func resourceArmAppServicePlanCreateUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).appServicePlansClient

	log.Printf("[INFO] preparing arguments for AzureRM App Service Plan creation.")

	resGroup := d.Get("resource_group_name").(string)
	name := d.Get("name").(string)
	location := d.Get("location").(string)
	tags := d.Get("tags").(map[string]interface{})

	sku := expandAzureRmAppServicePlanSku(d)
	properties := expandAppServicePlanProperties(d)

	appServicePlan := web.AppServicePlan{
		Location:                 &location,
		AppServicePlanProperties: properties,
		Tags: expandTags(tags),
		Sku:  &sku,
	}

	_, createErr := client.CreateOrUpdate(resGroup, name, appServicePlan, make(chan struct{}))
	err := <-createErr
	if err != nil {
		return err
	}

	read, err := client.Get(resGroup, name)
	if err != nil {
		return err
	}
	if read.ID == nil {
		return fmt.Errorf("Cannot read AzureRM App Service Plan %s (resource group %s) ID", name, resGroup)
	}

	d.SetId(*read.ID)

	return resourceArmAppServicePlanRead(d, meta)
}

func resourceArmAppServicePlanRead(d *schema.ResourceData, meta interface{}) error {
	AppServicePlanClient := meta.(*ArmClient).appServicePlansClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}

	log.Printf("[DEBUG] Reading Azure App Service Plan %s", id)

	resGroup := id.ResourceGroup
	name := id.Path["serverfarms"]

	resp, err := AppServicePlanClient.Get(resGroup, name)
	if err != nil {
		if resp.StatusCode == http.StatusNotFound {
			d.SetId("")
			return nil
		}

		return fmt.Errorf("Error making Read request on Azure App Service Plan %s: %+v", name, err)
	}

	d.Set("name", name)
	d.Set("resource_group_name", resGroup)
	d.Set("location", azureRMNormalizeLocation(*resp.Location))

	if props := resp.AppServicePlanProperties; props != nil {
		d.Set("properties", flattenAppServiceProperties(props))
	}

	if sku := resp.Sku; sku != nil {
		d.Set("sku", flattenAzureRmAppServicePlanSku(sku))
	}

	flattenAndSetTags(d, resp.Tags)

	return nil
}

func resourceArmAppServicePlanDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*ArmClient).appServicePlansClient

	id, err := parseAzureResourceID(d.Id())
	if err != nil {
		return err
	}
	resGroup := id.ResourceGroup
	name := id.Path["serverfarms"]

	log.Printf("[DEBUG] Deleting app service plan %s: %s", resGroup, name)

	_, err = client.Delete(resGroup, name)

	return err
}

func resourceAzureRMAppServicePlanSkuHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	tier := m["tier"].(string)
	size := m["size"].(string)

	buf.WriteString(fmt.Sprintf("%s-", tier))
	buf.WriteString(fmt.Sprintf("%s-", size))

	return hashcode.String(buf.String())
}

func expandAzureRmAppServicePlanSku(d *schema.ResourceData) web.SkuDescription {
	configs := d.Get("sku").(*schema.Set).List()
	config := configs[0].(map[string]interface{})

	tier := config["tier"].(string)
	size := config["size"].(string)

	sku := web.SkuDescription{
		Name: &size,
		Tier: &tier,
		Size: &size,
	}

	return sku
}

func flattenAzureRmAppServicePlanSku(profile *web.SkuDescription) *schema.Set {
	skus := &schema.Set{
		F: resourceAzureRMAppServicePlanSkuHash,
	}

	sku := make(map[string]interface{}, 2)

	sku["tier"] = *profile.Tier
	sku["size"] = *profile.Size

	skus.Add(sku)

	return skus
}

func expandAppServicePlanProperties(d *schema.ResourceData) *web.AppServicePlanProperties {
	configs := d.Get("properties").([]interface{})
	properties := web.AppServicePlanProperties{}
	if len(configs) == 0 {
		return &properties
	}
	config := configs[0].(map[string]interface{})

	perSiteScaling := config["per_site_scaling"].(bool)
	properties.PerSiteScaling = azure.Bool(perSiteScaling)

	reserved := config["reserved"].(bool)
	properties.Reserved = azure.Bool(reserved)

	if v, ok := config["maximum_number_of_workers"]; ok {
		maximumNumberOfWorkers := int32(v.(int))
		properties.MaximumNumberOfWorkers = &maximumNumberOfWorkers
	}

	return &properties
}

func flattenAppServiceProperties(props *web.AppServicePlanProperties) map[string]interface{} {
	properties := make(map[string]interface{}, 0)

	if props.MaximumNumberOfWorkers != nil {
		properties["maximum_number_of_workers"] = int(*props.MaximumNumberOfWorkers)
	}

	if props.PerSiteScaling != nil {
		properties["per_site_scaling"] = *props.PerSiteScaling
	}

	if props.Reserved != nil {
		properties["reserved"] = *props.Reserved
	}

	return properties
}
<|endoftext|>


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

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

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

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

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

func init() {
	handler.RegisterToGroup(`/server`, func(g echo.RouteRegister) {
		g.Route("GET", `/sysinfo`, Info)
		g.Route("GET", `/netstat`, Connections)
		g.Route("GET", `/process/:pid`, ProcessInfo)
		g.Route("GET", `/procskill/:pid`, ProcessKill)
		g.Route(`GET,POST`, `/service`, Service)
		g.Route(`GET,POST`, `/daemon_index`, DaemonIndex)
		g.Route(`GET,POST`, `/daemon_add`, DaemonAdd)
		g.Route(`GET,POST`, `/daemon_edit`, DaemonEdit)
		g.Route(`GET,POST`, `/daemon_delete`, DaemonDelete)
		g.Route("GET", `/cmd`, Cmd)
		sockjsOpts := sockjsHandler.Options{
			Handle: CmdSendBySockJS,
			Prefix: "/cmdSend",
		}
		//sockjsOpts.Wrapper(g)
		_ = sockjsOpts
		wsOpts := ws.Options{
			Handle: CmdSendByWebsocket,
			Prefix: "/cmdSendWS",
		}
		wsOpts.Wrapper(g)
		//*
		wsOptsDynamicInfo := ws.Options{
			Handle: InfoByWebsocket,
			Prefix: "/dynamic",
		}
		wsOptsDynamicInfo.Wrapper(g)
		//*/
	})
	//ListenRealTimeStatus()
}
<commit_msg>update<commit_after>/*
   Nging is a toolbox for webmasters
   Copyright (C) 2018-present  Wenhui Shen <swh@admpub.com>

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

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

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

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

func init() {
	handler.RegisterToGroup(`/server`, func(g echo.RouteRegister) {
		g.Route("GET", `/sysinfo`, Info)
		g.Route("GET", `/netstat`, Connections)
		g.Route("GET", `/process/:pid`, ProcessInfo)
		g.Route("GET", `/procskill/:pid`, ProcessKill)
		g.Route(`GET,POST`, `/service`, Service)
		g.Route(`GET,POST`, `/daemon_index`, DaemonIndex)
		g.Route(`GET,POST`, `/daemon_add`, DaemonAdd)
		g.Route(`GET,POST`, `/daemon_edit`, DaemonEdit)
		g.Route(`GET,POST`, `/daemon_delete`, DaemonDelete)
		g.Route("GET", `/cmd`, Cmd)
		sockjsOpts := sockjsHandler.Options{
			Handle: CmdSendBySockJS,
			Prefix: "/cmdSend",
		}
		//sockjsOpts.Wrapper(g)
		_ = sockjsOpts
		wsOpts := ws.Options{
			Handle: CmdSendByWebsocket,
			Prefix: "/cmdSendWS",
		}
		wsOpts.Wrapper(g)
		/*
			wsOptsDynamicInfo := ws.Options{
				Handle: InfoByWebsocket,
				Prefix: "/dynamic",
			}
			wsOptsDynamicInfo.Wrapper(g)
		// */
	})
	//ListenRealTimeStatus()
}
<|endoftext|>


<commit_before>package cuckoofilter

import (
	"encoding/json"
	"sync"

	"github.com/seiflotfy/skizze/counters/abstract"
	"github.com/seiflotfy/skizze/counters/wrappers/cuckoofilter/cuckoofilter"
	"github.com/seiflotfy/skizze/storage"
	"github.com/seiflotfy/skizze/utils"
)

var logger = utils.GetLogger()

/*
Domain is the toplevel domain to control the HLL implementation
*/
type Domain struct {
	*abstract.Info
	impl *cuckoofilter.CuckooFilter
	lock sync.RWMutex
}

/*
NewDomain ...
*/
func NewDomain(info *abstract.Info) (*Domain, error) {
	d := &Domain{info, cuckoofilter.NewCuckooFilter(info), sync.RWMutex{}}
	d.Save()
	return d, nil
}

/*
Add ...
*/
func (d *Domain) Add(value []byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := d.impl.InsertUnique(value)
	err := d.Save()
	return ok, err
}

/*
AddMultiple ...
*/
func (d *Domain) AddMultiple(values [][]byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := true
	for _, value := range values {
		okk := d.impl.InsertUnique(value)
		if okk == false {
			ok = okk
		}
	}
	err := d.Save()
	return ok, err
}

/*
Remove ...
*/
func (d *Domain) Remove(value []byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := d.impl.Delete(value)
	err := d.Save()
	return ok, err
}

/*
RemoveMultiple ...
*/
func (d *Domain) RemoveMultiple(values [][]byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := true
	for _, value := range values {
		okk := d.impl.Delete(value)
		if okk == false {
			ok = okk
		}
	}
	err := d.Save()
	return ok, err
}

/*
GetCount ...
*/
func (d *Domain) GetCount() uint {
	return uint(d.impl.GetCount())
}

/*
Clear ...
*/
func (d *Domain) Clear() (bool, error) {
	return true, nil
}

/*
Save ...
*/
func (d *Domain) Save() error {
	count := d.impl.GetCount()
	d.Info.State["count"] = uint64(count)
	infoData, err := json.Marshal(d.Info)
	if err != nil {
		return err
	}
	err = storage.GetManager().SaveInfo(d.Info.ID, infoData)
	return err
}
<commit_msg>minor cleanup<commit_after>package cuckoofilter

import (
	"encoding/json"
	"sync"

	"github.com/seiflotfy/skizze/counters/abstract"
	"github.com/seiflotfy/skizze/counters/wrappers/cuckoofilter/cuckoofilter"
	"github.com/seiflotfy/skizze/storage"
	"github.com/seiflotfy/skizze/utils"
)

var logger = utils.GetLogger()

/*
Domain is the toplevel domain to control the HLL implementation
*/
type Domain struct {
	*abstract.Info
	impl *cuckoofilter.CuckooFilter
	lock sync.RWMutex
}

/*
NewDomain ...
*/
func NewDomain(info *abstract.Info) (*Domain, error) {
	d := &Domain{info, cuckoofilter.NewCuckooFilter(info), sync.RWMutex{}}
	d.Save()
	return d, nil
}

/*
Add ...
*/
func (d *Domain) Add(value []byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := d.impl.InsertUnique(value)
	err := d.Save()
	return ok, err
}

/*
AddMultiple ...
*/
func (d *Domain) AddMultiple(values [][]byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := true
	for _, value := range values {
		okk := d.impl.InsertUnique(value)
		if okk == false {
			ok = okk
		}
	}
	err := d.Save()
	return ok, err
}

/*
Remove ...
*/
func (d *Domain) Remove(value []byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := d.impl.Delete(value)
	err := d.Save()
	return ok, err
}

/*
RemoveMultiple ...
*/
func (d *Domain) RemoveMultiple(values [][]byte) (bool, error) {
	d.lock.Lock()
	defer d.lock.Unlock()
	ok := true
	for _, value := range values {
		okk := d.impl.Delete(value)
		if okk == false {
			ok = okk
		}
	}
	err := d.Save()
	return ok, err
}

/*
GetCount ...
*/
func (d *Domain) GetCount() uint {
	return uint(d.impl.GetCount())
}

/*
Clear ...
*/
func (d *Domain) Clear() (bool, error) {
	return true, nil
}

/*
Save ...
*/
func (d *Domain) Save() error {
	count := d.impl.GetCount()
	d.Info.State["count"] = uint64(count)
	infoData, err := json.Marshal(d.Info)
	if err != nil {
		return err
	}
	return storage.GetManager().SaveInfo(d.Info.ID, infoData)
}
<|endoftext|>


<commit_before>package gcs

import (
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/state/remote"
)

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

	cases := []struct {
		prefix           string
		defaultStateFile string
		name             string
		wantStateFile    string
		wantLockFile     string
	}{
		{"state", "", "default", "state/default.tfstate", "state/default.tflock"},
		{"state", "", "test", "state/test.tfstate", "state/test.tflock"},
		{"state", "legacy.tfstate", "default", "legacy.tfstate", "legacy.tflock"},
		{"state", "legacy.tfstate", "test", "state/test.tfstate", "state/test.tflock"},
		{"state", "legacy.state", "default", "legacy.state", "legacy.state.tflock"},
		{"state", "legacy.state", "test", "state/test.tfstate", "state/test.tflock"},
	}
	for _, c := range cases {
		b := &gcsBackend{
			prefix:           c.prefix,
			defaultStateFile: c.defaultStateFile,
		}

		if got := b.stateFile(c.name); got != c.wantStateFile {
			t.Errorf("stateFile(%q) = %q, want %q", c.name, got, c.wantStateFile)
		}

		if got := b.lockFile(c.name); got != c.wantLockFile {
			t.Errorf("lockFile(%q) = %q, want %q", c.name, got, c.wantLockFile)
		}
	}
}

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

	be := testBackend(t)

	ss, err := be.State(backend.DefaultStateName)
	if err != nil {
		t.Fatalf("be.State(%q) = %v", backend.DefaultStateName, err)
	}

	rs, ok := ss.(*remote.State)
	if !ok {
		t.Fatalf("be.State(): got a %T, want a *remote.State", ss)
	}

	remote.TestClient(t, rs.Client)

	cleanBackend(t, be)
}

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

	be := testBackend(t)

	remoteClient := func() (remote.Client, error) {
		ss, err := be.State(backend.DefaultStateName)
		if err != nil {
			return nil, err
		}

		rs, ok := ss.(*remote.State)
		if !ok {
			return nil, fmt.Errorf("be.State(): got a %T, want a *remote.State", ss)
		}

		return rs.Client, nil
	}

	c0, err := remoteClient()
	if err != nil {
		t.Fatalf("remoteClient(0) = %v", err)
	}
	c1, err := remoteClient()
	if err != nil {
		t.Fatalf("remoteClient(1) = %v", err)
	}

	remote.TestRemoteLocks(t, c0, c1)

	cleanBackend(t, be)
}

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

	be0 := testBackend(t)
	be1 := testBackend(t)

	// clean up all states left behind by previous runs --
	// backend.TestBackend() will complain about any non-default states.
	cleanBackend(t, be0)

	backend.TestBackend(t, be0, be1)

	cleanBackend(t, be0)
}

// testBackend returns a new GCS backend.
func testBackend(t *testing.T) backend.Backend {
	t.Helper()

	projectID := os.Getenv("GOOGLE_PROJECT")
	if projectID == "" || os.Getenv("TF_ACC") == "" {
		t.Skip("This test creates a bucket in GCS and populates it. " +
			"Since this may incur costs, it will only run if " +
			"the TF_ACC and GOOGLE_PROJECT environment variables are set.")
	}

	config := map[string]interface{}{
		"project": projectID,
		"bucket":  strings.ToLower(t.Name()),
		"prefix":  "",
	}

	if creds := os.Getenv("GOOGLE_CREDENTIALS"); creds != "" {
		config["credentials"] = creds
		t.Logf("using credentials from %q", creds)
	} else {
		t.Log("using default credentials; set GOOGLE_CREDENTIALS for custom credentials")
	}

	return backend.TestBackendConfig(t, New(), config)
}

// cleanBackend deletes all states from be except the default state.
func cleanBackend(t *testing.T, be backend.Backend) {
	t.Helper()

	states, err := be.States()
	if err != nil {
		t.Fatalf("be.States() = %v; manual clean-up may be required", err)
	}
	for _, st := range states {
		if st == backend.DefaultStateName {
			continue
		}
		if err := be.DeleteState(st); err != nil {
			t.Fatalf("be.DeleteState(%q) = %v; manual clean-up may be required", st, err)
		}
	}
}
<commit_msg>backend/remote-state/gcs: Delete test buckets after tests complete.<commit_after>package gcs

import (
	"fmt"
	"os"
	"strings"
	"testing"

	"github.com/hashicorp/terraform/backend"
	"github.com/hashicorp/terraform/state/remote"
)

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

	cases := []struct {
		prefix           string
		defaultStateFile string
		name             string
		wantStateFile    string
		wantLockFile     string
	}{
		{"state", "", "default", "state/default.tfstate", "state/default.tflock"},
		{"state", "", "test", "state/test.tfstate", "state/test.tflock"},
		{"state", "legacy.tfstate", "default", "legacy.tfstate", "legacy.tflock"},
		{"state", "legacy.tfstate", "test", "state/test.tfstate", "state/test.tflock"},
		{"state", "legacy.state", "default", "legacy.state", "legacy.state.tflock"},
		{"state", "legacy.state", "test", "state/test.tfstate", "state/test.tflock"},
	}
	for _, c := range cases {
		b := &gcsBackend{
			prefix:           c.prefix,
			defaultStateFile: c.defaultStateFile,
		}

		if got := b.stateFile(c.name); got != c.wantStateFile {
			t.Errorf("stateFile(%q) = %q, want %q", c.name, got, c.wantStateFile)
		}

		if got := b.lockFile(c.name); got != c.wantLockFile {
			t.Errorf("lockFile(%q) = %q, want %q", c.name, got, c.wantLockFile)
		}
	}
}

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

	be := setupBackend(t)
	defer teardownBackend(t, be)

	ss, err := be.State(backend.DefaultStateName)
	if err != nil {
		t.Fatalf("be.State(%q) = %v", backend.DefaultStateName, err)
	}

	rs, ok := ss.(*remote.State)
	if !ok {
		t.Fatalf("be.State(): got a %T, want a *remote.State", ss)
	}

	remote.TestClient(t, rs.Client)
}

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

	be := setupBackend(t)
	defer teardownBackend(t, be)

	remoteClient := func() (remote.Client, error) {
		ss, err := be.State(backend.DefaultStateName)
		if err != nil {
			return nil, err
		}

		rs, ok := ss.(*remote.State)
		if !ok {
			return nil, fmt.Errorf("be.State(): got a %T, want a *remote.State", ss)
		}

		return rs.Client, nil
	}

	c0, err := remoteClient()
	if err != nil {
		t.Fatalf("remoteClient(0) = %v", err)
	}
	c1, err := remoteClient()
	if err != nil {
		t.Fatalf("remoteClient(1) = %v", err)
	}

	remote.TestRemoteLocks(t, c0, c1)
}

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

	be0 := setupBackend(t)
	defer teardownBackend(t, be0)

	be1 := setupBackend(t)

	backend.TestBackend(t, be0, be1)
}

// setupBackend returns a new GCS backend.
func setupBackend(t *testing.T) backend.Backend {
	t.Helper()

	projectID := os.Getenv("GOOGLE_PROJECT")
	if projectID == "" || os.Getenv("TF_ACC") == "" {
		t.Skip("This test creates a bucket in GCS and populates it. " +
			"Since this may incur costs, it will only run if " +
			"the TF_ACC and GOOGLE_PROJECT environment variables are set.")
	}

	config := map[string]interface{}{
		"project": projectID,
		"bucket":  strings.ToLower(t.Name()),
		"prefix":  "",
	}

	if creds := os.Getenv("GOOGLE_CREDENTIALS"); creds != "" {
		config["credentials"] = creds
		t.Logf("using credentials from %q", creds)
	} else {
		t.Log("using default credentials; set GOOGLE_CREDENTIALS for custom credentials")
	}

	return backend.TestBackendConfig(t, New(), config)
}

// teardownBackend deletes all states from be except the default state.
func teardownBackend(t *testing.T, be backend.Backend) {
	t.Helper()

	// Delete all states. The bucket must be empty before it can be deleted.
	states, err := be.States()
	if err != nil {
		t.Fatalf("be.States() = %v; manual clean-up may be required", err)
	}
	for _, st := range states {
		if st == backend.DefaultStateName {
			continue
		}
		if err := be.DeleteState(st); err != nil {
			t.Fatalf("be.DeleteState(%q) = %v; manual clean-up may be required", st, err)
		}
	}

	gcsBE, ok := be.(*gcsBackend)
	if !ok {
		t.Fatalf("be is a %T, want a *gcsBackend", be)
	}
	ctx := gcsBE.storageContext

	// Delete the default state, which DeleteState() will refuse to do.
	// It's okay if this fails, not all tests create a default state.
	if err := gcsBE.storageClient.Bucket(gcsBE.bucketName).Object("default.tfstate").Delete(ctx); err != nil {
		t.Logf("deleting \"default.tfstate\": %v; manual clean-up may be required", err)
	}

	// Delete the bucket itself.
	if err := gcsBE.storageClient.Bucket(gcsBE.bucketName).Delete(ctx); err != nil {
		t.Fatalf("deleting bucket failed: %v; manual cleanup may be required, though later test runs will happily reuse an existing bucket", err)
	}
}
<|endoftext|>


<commit_before>// Package handlers is used by go generate for analizing
// controller package's files and generation of handlers.
package handlers

import (
	"path/filepath"

	"github.com/anonx/sunplate/command"
	"github.com/anonx/sunplate/generation/output"
)

// Start is an entry point of the generate handlers command.
func Start(basePath string, params command.Data) {
	// Generate and save a new package.
	t := output.NewType(
		params.Default("--package", "handlers"), filepath.Join(basePath, "./handlers.go.template"),
	)
	t.CreateDir(params.Default("--output", "./assets/handlers/"))
	t.Extension = ".go" // Save generated file as a .go source.
	t.Context = map[string]interface{}{
		"rootPath": params.Default("--path", "./controllers/"),
	}
	t.Generate()
}
<commit_msg>Starting a work on handlers generation<commit_after>// Package handlers is used by go generate for analizing
// controller package's files and generation of handlers.
package handlers

import (
	"path/filepath"

	"github.com/anonx/sunplate/command"
	"github.com/anonx/sunplate/generation/output"
	"github.com/anonx/sunplate/reflect"
)

const (
	// ActionInterfaceImport is a GOPATH to the Result interface
	// that should be implemented by types returned by actions.
	ActionInterfaceImport = "github.com/anonx/sunplate/action"

	// ActionInterfaceName is an interface that should be implemented
	// by types that are returned from actions.
	ActionInterfaceName = "Result"
)

// Controller is a type that represents application controller,
// a structure that has actions.
type Controller struct {
	Actions reflect.Funcs // Actions are methods that implement action.Result interface.
}

// Start is an entry point of the generate handlers command.
func Start(basePath string, params command.Data) {
	// Generate and save a new package.
	t := output.NewType(
		params.Default("--package", "handlers"), filepath.Join(basePath, "./handlers.go.template"),
	)
	t.CreateDir(params.Default("--output", "./assets/handlers/"))
	t.Extension = ".go" // Save generated file as a .go source.
	t.Context = map[string]interface{}{
		"rootPath": params.Default("--path", "./controllers/"),
	}
	t.Generate()
}

// extractControllers gets a reflect.Package type and returns
// a slice of controllers that are found there.
func extractControllers(pkg *reflect.Package) []Controller {
	return nil
}
<|endoftext|>


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

package types

import (
	"math"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/mysql"
)

// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function.
// RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html
// so rounding use "round half away from zero".
// e.g, 1.5 -> 2, -1.5 -> -2.
func RoundFloat(f float64) float64 {
	if math.Abs(f) < 0.5 {
		return 0
	}

	return math.Trunc(f + math.Copysign(0.5, f))
}

// Round rounds the argument f to dec decimal places.
// dec defaults to 0 if not specified. dec can be negative
// to cause dec digits left of the decimal point of the
// value f to become zero.
func Round(f float64, dec int) float64 {
	shift := math.Pow10(dec)
	f = f * shift
	f = RoundFloat(f)
	return f / shift
}

func getMaxFloat(flen int, decimal int) float64 {
	intPartLen := flen - decimal
	f := math.Pow10(intPartLen)
	f -= math.Pow10(-decimal)
	return f
}

func truncateFloat(f float64, decimal int) float64 {
	pow := math.Pow10(decimal)
	t := (f - math.Floor(f)) * pow

	round := RoundFloat(t)

	f = math.Floor(f) + round/pow
	return f
}

// TruncateFloat tries to truncate f.
// If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed.
func TruncateFloat(f float64, flen int, decimal int) (float64, error) {
	if math.IsNaN(f) {
		// nan returns 0
		return 0, nil
	}

	maxF := getMaxFloat(flen, decimal)

	if !math.IsInf(f, 0) {
		f = truncateFloat(f, decimal)
	}

	if f > maxF {
		f = maxF
	} else if f < -maxF {
		f = -maxF
	}

	return f, nil
}

// CalculateSum adds v to sum.
func CalculateSum(sum Datum, v Datum) (Datum, error) {
	// for avg and sum calculation
	// avg and sum use decimal for integer and decimal type, use float for others
	// see https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
	var (
		data Datum
		err  error
	)

	switch v.Kind() {
	case KindNull:
	case KindInt64, KindUint64:
		var d mysql.Decimal
		d, err = v.ToDecimal()
		if err == nil {
			data = NewDecimalDatum(d)
		}
	case KindMysqlDecimal:
		data = v
	default:
		var f float64
		f, err = v.ToFloat64()
		if err != nil {
			data = NewFloat64Datum(f)
		}
	}

	if err != nil {
		return data, errors.Trace(err)
	}
	if data.IsNull() {
		return sum, nil
	}
	switch sum.Kind() {
	case KindNull:
		return data, nil
	case KindFloat64, KindMysqlDecimal:
		return ComputePlus(sum, data)
	default:
		return data, errors.Errorf("invalid value %v for aggregate", sum.Kind())
	}
}
<commit_msg>types: Fix bug for CalculateSum (#1497)<commit_after>// Copyright 2015 PingCAP, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// See the License for the specific language governing permissions and
// limitations under the License.

package types

import (
	"math"

	"github.com/juju/errors"
	"github.com/pingcap/tidb/mysql"
)

// RoundFloat rounds float val to the nearest integer value with float64 format, like MySQL Round function.
// RoundFloat uses default rounding mode, see https://dev.mysql.com/doc/refman/5.7/en/precision-math-rounding.html
// so rounding use "round half away from zero".
// e.g, 1.5 -> 2, -1.5 -> -2.
func RoundFloat(f float64) float64 {
	if math.Abs(f) < 0.5 {
		return 0
	}

	return math.Trunc(f + math.Copysign(0.5, f))
}

// Round rounds the argument f to dec decimal places.
// dec defaults to 0 if not specified. dec can be negative
// to cause dec digits left of the decimal point of the
// value f to become zero.
func Round(f float64, dec int) float64 {
	shift := math.Pow10(dec)
	f = f * shift
	f = RoundFloat(f)
	return f / shift
}

func getMaxFloat(flen int, decimal int) float64 {
	intPartLen := flen - decimal
	f := math.Pow10(intPartLen)
	f -= math.Pow10(-decimal)
	return f
}

func truncateFloat(f float64, decimal int) float64 {
	pow := math.Pow10(decimal)
	t := (f - math.Floor(f)) * pow

	round := RoundFloat(t)

	f = math.Floor(f) + round/pow
	return f
}

// TruncateFloat tries to truncate f.
// If the result exceeds the max/min float that flen/decimal allowed, returns the max/min float allowed.
func TruncateFloat(f float64, flen int, decimal int) (float64, error) {
	if math.IsNaN(f) {
		// nan returns 0
		return 0, nil
	}

	maxF := getMaxFloat(flen, decimal)

	if !math.IsInf(f, 0) {
		f = truncateFloat(f, decimal)
	}

	if f > maxF {
		f = maxF
	} else if f < -maxF {
		f = -maxF
	}

	return f, nil
}

// CalculateSum adds v to sum.
func CalculateSum(sum Datum, v Datum) (Datum, error) {
	// for avg and sum calculation
	// avg and sum use decimal for integer and decimal type, use float for others
	// see https://dev.mysql.com/doc/refman/5.7/en/group-by-functions.html
	var (
		data Datum
		err  error
	)

	switch v.Kind() {
	case KindNull:
	case KindInt64, KindUint64:
		var d mysql.Decimal
		d, err = v.ToDecimal()
		if err == nil {
			data = NewDecimalDatum(d)
		}
	case KindMysqlDecimal:
		data = v
	default:
		var f float64
		f, err = v.ToFloat64()
		if err == nil {
			data = NewFloat64Datum(f)
		}
	}

	if err != nil {
		return data, errors.Trace(err)
	}
	if data.IsNull() {
		return sum, nil
	}
	switch sum.Kind() {
	case KindNull:
		return data, nil
	case KindFloat64, KindMysqlDecimal:
		return ComputePlus(sum, data)
	default:
		return data, errors.Errorf("invalid value %v for aggregate", sum.Kind())
	}
}
<|endoftext|>