<commit_before>package video

import "github.com/32bitkid/bitreader"

type GroupOfPicturesHeader struct {
	timeCode   uint32 // 25 bslbf
	ClosedGOP  bool   // 1 uimsbf
	BrokenLink bool   // 1 uimsbf
}

// ReadGOPHeader parses a group_of_pictures header from the given bitstream.
func ReadGOPHeader(br bitreader.BitReader) (*GroupOfPicturesHeader, error) {
	if err := GroupStartCode.Assert(br); err != nil {
		return nil, err
	}

	goph := GroupOfPicturesHeader{}

	if time_code, err := br.Read32(25); err != nil {
		return nil, err
	} else {
		goph.timeCode = time_code
	}

	if closed_gop, err := br.ReadBit(); err != nil {
		return nil, err
	} else {
		goph.ClosedGOP = closed_gop
	}

	if broken_link, err := br.ReadBit(); err != nil {
		return nil, err
	} else {
		goph.BrokenLink = broken_link
	}

	return &goph, next_start_code(br)
}

// TimeCode represents the associated time code with the first picture following the
// Group of Pictures header with a TemporalReference = 0. DropFrame will only be true
// if the desired framerate is 29.97Hz.
//
// TimeCode appears in the bitstream as a 25-bit integer that has the following layout:
//
//  ├1b┤
//  ┌──┬──────────────────┬──────────────────────┬──┬──────────────────────┬──────────────────────┐
//  │DF│Hours             │Minutes               │MB│Seconds               │Pictures              │
//  └──┴──────────────────┴──────────────────────┴──┴──────────────────────┴──────────────────────┘
//  ├───────────────────────────────────────────25 bits───────────────────────────────────────────┤
type TimeCode struct {
	DropFrame bool
	Hours     int
	Minutes   int
	Seconds   int
	Pictures  int
}

// Returns a parsed TimeCode from the raw GOP header data.
func (gop *GroupOfPicturesHeader) TimeCode() TimeCode {
	return TimeCode{
		DropFrame: (gop.timeCode >> 24) == 1,
		Hours:     (gop.timeCode >> 19) & 0x1F,
		Minutes:   (gop.timeCode >> 13) & 0x3F,
		Seconds:   (gop.timeCode >> 6) & 0x3F,
		Pictures:  (gop.timeCode) & 0x3F,
	}
}
<commit_msg>updating documentation.<commit_after>package video

import "github.com/32bitkid/bitreader"
import "fmt"

type GroupOfPicturesHeader struct {
	timeCode   int32 // 25 bslbf
	ClosedGOP  bool  // 1 uimsbf
	BrokenLink bool  // 1 uimsbf
}

// ReadGOPHeader parses a group_of_pictures header from the given bitstream.
func ReadGOPHeader(br bitreader.BitReader) (*GroupOfPicturesHeader, error) {
	if err := GroupStartCode.Assert(br); err != nil {
		return nil, err
	}

	goph := GroupOfPicturesHeader{}

	if time_code, err := br.Read32(25); err != nil {
		return nil, err
	} else {
		goph.timeCode = int32(time_code)
	}

	if closed_gop, err := br.ReadBit(); err != nil {
		return nil, err
	} else {
		goph.ClosedGOP = closed_gop
	}

	if broken_link, err := br.ReadBit(); err != nil {
		return nil, err
	} else {
		goph.BrokenLink = broken_link
	}

	return &goph, next_start_code(br)
}

// Returns a parsed TimeCode from the raw GOP header data.
func (gop *GroupOfPicturesHeader) TimeCode() TimeCode {
	return TimeCode{
		DropFrame: (gop.timeCode >> 24) == 1,
		Hours:     (gop.timeCode >> 19) & 0x1F,
		Minutes:   (gop.timeCode >> 13) & 0x3F,
		Seconds:   (gop.timeCode >> 6) & 0x3F,
		Pictures:  (gop.timeCode) & 0x3F,
	}
}

// TimeCode represents the associated time code with the first picture following the
// Group of Pictures header with a TemporalReference = 0. DropFrame will only be true
// if the desired framerate is 29.97Hz.
//
// TimeCode appears in the bitstream as a 25-bit integer that has the following layout:
//
//  ┌──┬──────────────────┬──────────────────────┬──┬──────────────────────┬──────────────────────┐
//  │DF│Hours             │Minutes               │MB│Seconds               │Pictures              │
//  └──┴──────────────────┴──────────────────────┴──┴──────────────────────┴──────────────────────┘
//  ├───────────────────────────────────────────25 bits───────────────────────────────────────────┤
type TimeCode struct {
	DropFrame bool  // 1-bit
	Hours     int32 // 5-bit
	Minutes   int32 // 6-bit
	Seconds   int32 // 6-bit
	Pictures  int32 // 6-bit
}

// String formats the time code as a string in SMPTE format: "HH:MM:SS:FF". If the timecode is
// in drop frame, then the separator between seconds and frames is replaced with a ";" character.
func (tc TimeCode) String() string {
	secondsFramesSep := ":"
	if tc.DropFrame {
		secondsFramesSep = ";"
	}
	return fmt.Sprintf("%d:%02d:%02d%s%02d", tc.Hours, tc.Minutes, tc.Seconds, secondsFramesSep, tc.Pictures)
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/Microsoft/hcsshim/internal/wclayer"
	"github.com/urfave/cli"
)

const (
	dirArgName = "dir"
)

func main() {
	app := cli.NewApp()
	app.Name = "zapdir"
	app.Usage = "Delete a directory"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  dirArgName,
			Value: "",
			Usage: "Directory to delete",
		},
	}

	app.Action = func(c *cli.Context) error {
		dir := c.String(dirArgName)

		if dir == "" {
			return errors.New("dir must be supplied")
		}

		// DestroyLayer requires an absolute path.
		dir, err := filepath.Abs(dir)
		if err != nil {
			return err
		}

		if _, err := os.Stat(dir); err != nil {
			return err
		}

		if err := wclayer.DestroyLayer(dir); err != nil {
			return err
		}

		return nil
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
	}
}
<commit_msg>Improve zapdir error reporting<commit_after>package main

import (
	"errors"
	"fmt"
	"os"
	"path/filepath"

	"github.com/Microsoft/hcsshim/internal/wclayer"
	"github.com/urfave/cli"
)

const (
	dirArgName = "dir"
)

func main() {
	app := cli.NewApp()
	app.Name = "zapdir"
	app.Usage = "Delete a directory"

	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  dirArgName,
			Value: "",
			Usage: "Directory to delete",
		},
	}

	app.Action = func(c *cli.Context) error {
		dir := c.String(dirArgName)

		if dir == "" {
			return errors.New("dir must be supplied")
		}

		// DestroyLayer requires an absolute path.
		dir, err := filepath.Abs(dir)
		if err != nil {
			return err
		}

		if _, err := os.Stat(dir); err != nil {
			return err
		}

		if err := wclayer.DestroyLayer(dir); err != nil {
			return err
		}

		return nil
	}

	err := app.Run(os.Args)
	if err != nil {
		fmt.Fprintln(cli.ErrWriter, err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package ttlstore

import (
	"github.com/Sirupsen/logrus"
	"github.com/orian/utils/ptime"

	"container/heap"
	"io/ioutil"
	"sync"
	"time"
)

type actionTimestamp struct {
	Key           interface{}
	TimestmapNsec int64
}

type ActionTimestmapHeap []*actionTimestamp

func (h ActionTimestmapHeap) Len() int { return len(h) }
func (h ActionTimestmapHeap) Less(i, j int) bool {
	return h[i].TimestmapNsec > h[j].TimestmapNsec
}
func (h ActionTimestmapHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

func (h *ActionTimestmapHeap) Push(x interface{}) {
	// Push and Pop use pointer receivers because they modify the slice's length,
	// not just its contents.
	*h = append(*h, x.(*actionTimestamp))
}

func (h *ActionTimestmapHeap) Pop() interface{} {
	old := *h
	n := len(old) - 1
	x := old[n]
	old[n] = nil
	*h = old[0:n]
	return x
}

type DeleteHook func(key interface{})

type Deleter struct {
	c          chan *actionTimestamp
	DeleteFunc DeleteHook
	Interval   time.Duration
	Name       string

	lastActionTimestamp map[interface{}]int64
	maxAge              time.Duration
	keepNum             int

	m        *sync.Mutex
	end      chan bool
	finished chan bool
	logger   logrus.FieldLogger
}

var _ Janitor = &Deleter{}

func NewDeleter(name string, del DeleteHook, maxAge, runInterval time.Duration, bufSize, keep int,
	logger logrus.FieldLogger) *Deleter {

	if logger == nil {
		logger = logrus.New()
		logger.Out = ioutil.Discard
	}

	return &Deleter{
		make(chan *actionTimestamp, bufSize),
		del,
		runInterval,
		name,
		make(map[interface{}]int64),
		maxAge,
		keep,
		&sync.Mutex{},
		make(chan bool, 1),
		make(chan bool, 2),
		logger,
	}
}

func (d *Deleter) Set(key interface{}, insert time.Time) {
	d.c <- &actionTimestamp{key, insert.UnixNano()}
}

type DeleterProvider func(name string, hook DeleteHook) *Deleter

func NewDeleterProvider(maxAge, interval time.Duration, bufSize, keep int) DeleterProvider {
	return func(name string, del DeleteHook) *Deleter {
		return NewDeleter(name, del, maxAge, interval, bufSize, keep)
	}
}

func (d *Deleter) DeleteTooOld() {
	num := 0
	thresholdUsec := time.Now().Add(-d.maxAge).UnixNano()
	t := ptime.NewTimer()
	d.m.Lock()
	defer d.m.Unlock()
	for k, v := range d.lastActionTimestamp {
		if v < thresholdUsec {
			if d.DeleteFunc != nil {
				d.DeleteFunc(k)
			}
			delete(d.lastActionTimestamp, k)
			num++
		}
	}
	d.logger.Infof("[%s] deleted %d too old (%s) items, kept %d, took: %s",
		d.Name, num, d.maxAge, len(d.lastActionTimestamp), t.Duration())
}

func (d *Deleter) deleteUntilBelowMaxUuid() {
	d.m.Lock()
	defer d.m.Unlock()
	l := len(d.lastActionTimestamp)
	if l < int(float32(d.keepNum)*1.1) {
		return
	}

	t := ptime.NewTimer()
	num := 0
	h := &ActionTimestmapHeap{}
	numToRemove := len(d.lastActionTimestamp) - d.keepNum
	initDone := false
	for k, v := range d.lastActionTimestamp {
		heap.Push(h, &actionTimestamp{k, v})
		if initDone {
			heap.Pop(h)
		} else if h.Len() >= numToRemove {
			heap.Init(h)
			initDone = true
		}
	}

	for i := h.Len(); i > 0; i-- {
		a := heap.Pop(h).(*actionTimestamp)
		if d.DeleteFunc != nil {
			d.DeleteFunc(a.Key)
		}
		delete(d.lastActionTimestamp, a.Key)
		num++
	}
	d.logger.Infof("[%s] deleted %d items because too many, kept: %d, took: %s",
		d.Name, num, len(d.lastActionTimestamp), t.Duration())
}

func (d *Deleter) Process() {
	d.logger.Infof("[%s] process started", d.Name)
	for t := range d.c {
		d.m.Lock()
		if v := d.lastActionTimestamp[t.Key]; v < t.TimestmapNsec {
			d.lastActionTimestamp[t.Key] = t.TimestmapNsec
		}
		d.m.Unlock()
	}
	d.finished <- true
	d.logger.Infof("[%s] process finished", d.Name)
}

func (d *Deleter) Deleting() {
	d.logger.Infof("[%s] deleting started", d.Name)
	tmr := time.NewTicker(d.Interval)
	for {
		select {
		case <-d.end:
			goto end
		case <-tmr.C:
			d.DeleteTooOld()
			d.deleteUntilBelowMaxUuid()
		}
	}
end:
	tmr.Stop()
	d.finished <- true
	d.logger.Infof("[%s] deleting finished", d.Name)
}

func (d *Deleter) Start() {
	go d.Deleting()
	d.Process()
}

func (d *Deleter) Stop() {
	close(d.c)
	d.end <- true
	<-d.finished
	<-d.finished
}
<commit_msg>fix provider and ifc<commit_after>package ttlstore

import (
	"github.com/Sirupsen/logrus"
	"github.com/orian/utils/ptime"

	"container/heap"
	"io/ioutil"
	"sync"
	"time"
)

type actionTimestamp struct {
	Key           interface{}
	TimestmapNsec int64
}

type ActionTimestmapHeap []*actionTimestamp

func (h ActionTimestmapHeap) Len() int { return len(h) }
func (h ActionTimestmapHeap) Less(i, j int) bool {
	return h[i].TimestmapNsec > h[j].TimestmapNsec
}
func (h ActionTimestmapHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }

func (h *ActionTimestmapHeap) Push(x interface{}) {
	// Push and Pop use pointer receivers because they modify the slice's length,
	// not just its contents.
	*h = append(*h, x.(*actionTimestamp))
}

func (h *ActionTimestmapHeap) Pop() interface{} {
	old := *h
	n := len(old) - 1
	x := old[n]
	old[n] = nil
	*h = old[0:n]
	return x
}

type DeleteHook func(key interface{})

type Deleter struct {
	c          chan *actionTimestamp
	DeleteFunc DeleteHook
	Interval   time.Duration
	Name       string

	lastActionTimestamp map[interface{}]int64
	maxAge              time.Duration
	keepNum             int

	m        *sync.Mutex
	end      chan bool
	finished chan bool
	logger   logrus.FieldLogger
}

var _ Janitor = &Deleter{}

func NewDeleter(name string, del DeleteHook, maxAge, runInterval time.Duration, bufSize, keep int,
	logger logrus.FieldLogger) *Deleter {

	if logger == nil {
		l := logrus.New()
		l.Out = ioutil.Discard
		logger = l
	}

	return &Deleter{
		make(chan *actionTimestamp, bufSize),
		del,
		runInterval,
		name,
		make(map[interface{}]int64),
		maxAge,
		keep,
		&sync.Mutex{},
		make(chan bool, 1),
		make(chan bool, 2),
		logger,
	}
}

func (d *Deleter) Set(key interface{}, insert time.Time) {
	d.c <- &actionTimestamp{key, insert.UnixNano()}
}

type DeleterProvider func(name string, hook DeleteHook) *Deleter

func NewDeleterProvider(maxAge, interval time.Duration, bufSize, keep int) DeleterProvider {
	return func(name string, del DeleteHook) *Deleter {
		return NewDeleter(name, del, maxAge, interval, bufSize, keep, nil)
	}
}

func (d *Deleter) DeleteTooOld() {
	num := 0
	thresholdUsec := time.Now().Add(-d.maxAge).UnixNano()
	t := ptime.NewTimer()
	d.m.Lock()
	defer d.m.Unlock()
	for k, v := range d.lastActionTimestamp {
		if v < thresholdUsec {
			if d.DeleteFunc != nil {
				d.DeleteFunc(k)
			}
			delete(d.lastActionTimestamp, k)
			num++
		}
	}
	d.logger.Infof("[%s] deleted %d too old (%s) items, kept %d, took: %s",
		d.Name, num, d.maxAge, len(d.lastActionTimestamp), t.Duration())
}

func (d *Deleter) deleteUntilBelowMaxUuid() {
	d.m.Lock()
	defer d.m.Unlock()
	l := len(d.lastActionTimestamp)
	if l < int(float32(d.keepNum)*1.1) {
		return
	}

	t := ptime.NewTimer()
	num := 0
	h := &ActionTimestmapHeap{}
	numToRemove := len(d.lastActionTimestamp) - d.keepNum
	initDone := false
	for k, v := range d.lastActionTimestamp {
		heap.Push(h, &actionTimestamp{k, v})
		if initDone {
			heap.Pop(h)
		} else if h.Len() >= numToRemove {
			heap.Init(h)
			initDone = true
		}
	}

	for i := h.Len(); i > 0; i-- {
		a := heap.Pop(h).(*actionTimestamp)
		if d.DeleteFunc != nil {
			d.DeleteFunc(a.Key)
		}
		delete(d.lastActionTimestamp, a.Key)
		num++
	}
	d.logger.Infof("[%s] deleted %d items because too many, kept: %d, took: %s",
		d.Name, num, len(d.lastActionTimestamp), t.Duration())
}

func (d *Deleter) Process() {
	d.logger.Infof("[%s] process started", d.Name)
	for t := range d.c {
		d.m.Lock()
		if v := d.lastActionTimestamp[t.Key]; v < t.TimestmapNsec {
			d.lastActionTimestamp[t.Key] = t.TimestmapNsec
		}
		d.m.Unlock()
	}
	d.finished <- true
	d.logger.Infof("[%s] process finished", d.Name)
}

func (d *Deleter) Deleting() {
	d.logger.Infof("[%s] deleting started", d.Name)
	tmr := time.NewTicker(d.Interval)
	for {
		select {
		case <-d.end:
			goto end
		case <-tmr.C:
			d.DeleteTooOld()
			d.deleteUntilBelowMaxUuid()
		}
	}
end:
	tmr.Stop()
	d.finished <- true
	d.logger.Infof("[%s] deleting finished", d.Name)
}

func (d *Deleter) Start() {
	go d.Deleting()
	d.Process()
}

func (d *Deleter) Stop() {
	close(d.c)
	d.end <- true
	<-d.finished
	<-d.finished
}
<|endoftext|>


<commit_before>package manager

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"
)

type requestLog struct {
	data      []string
	logData   []string
	startTime time.Time
	req       *http.Request
	logId     int64
}

func NewRequestLog(req *http.Request) *requestLog {
	rlog := &requestLog{req: req}
	rlog.reset()
	return rlog
}

func (rlog *requestLog) print() {
	if len(rlog.logData) == 0 {
		return
	}
	used := time.Now().Sub(rlog.startTime)
	log.Println("logid:", rlog.logId,
		rlog.req.Method, rlog.req.URL.String(),
		strings.Join(rlog.data, " "),
		strings.Join(rlog.logData, " "),
		"used:", used.String())
	rlog.reset()
}

func (rlog *requestLog) setLog(arg ...interface{}) {
	rlog.data = append(rlog.logData, fmt.Sprint(arg))
}
func (rlog *requestLog) addLog(arg ...interface{}) {
	rlog.logData = append(rlog.logData, fmt.Sprint(arg))
}
func (rlog *requestLog) reset() {
	rlog.startTime = time.Now()
	rlog.logData = []string{}
}

type HttpClient struct {
	ProxyManager *ProxyManager
}

func NewHttpClient(manager *ProxyManager) *HttpClient {
	log.Println("loading http client...")
	proxy := new(HttpClient)
	proxy.ProxyManager = manager

	return proxy
}

func (httpClient *HttpClient) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	rlog := NewRequestLog(req)

	rlog.logId = httpClient.ProxyManager.reqNum + time.Now().Unix()

	defer rlog.print()
	user := getAuthorInfo(req)
	rlog.setLog("uname", user.Name)

	if PROXY_DEBUG {
		dump, _ := httputil.DumpRequest(req, true)
		log.Println("req dump:\n", string(dump))
	}

	if !httpClient.ProxyManager.checkHttpAuth(user) {
		rlog.addLog("auth", "failed")
		w.Header().Set("Proxy-Authenticate", "Basic realm=auth need")
		w.WriteHeader(407)
		w.Write([]byte("auth failed"))
		return
	}

	req.RequestURI = ""
	req.Header.Del("Connection")
	req.Header.Del("Proxy-Connection")

	_statusOk := strings.Split(req.Header.Get("X-Man-Status-Ok"), ",")
	statusOk := make(map[int]int)
	for _, v := range _statusOk {
		_code := int(getInt64(v))
		if _code > 0 {
			statusOk[_code] = 1
		}
	}
	_clientReTry := -1
	x_man_retry := req.Header.Get("X-Man-ReTry")
	if x_man_retry != "" {
		_clientReTry = int(getInt64(x_man_retry))
	}

	for k := range req.Header {
		if strings.HasPrefix(strings.ToLower(k), "x-man") {
			req.Header.Del(k)
		}
	}

	var resp *http.Response
	var err error

	max_re_try := httpClient.ProxyManager.config.reTry + 1
	if _clientReTry >= 0 && _clientReTry <= httpClient.ProxyManager.config.reTryMax {
		max_re_try = _clientReTry + 1
	}
	no := 1
	for ; no <= max_re_try; no++ {
		rlog.addLog("try", fmt.Sprintf("%d/%d", no, max_re_try))
		proxy, err := httpClient.ProxyManager.proxyPool.GetOneProxy(user.Name)
		if err != nil {
			rlog.addLog("get_proxy_faield", err)
			rlog.print()
			break
		}
		rlog.addLog("proxy", proxy.proxy)
		rlog.addLog("proxyUsed", proxy.Used)
		client, err := NewClient(proxy.URL, httpClient.ProxyManager.config.timeout)
		if err != nil {
			rlog.addLog("get http client failed", err)
			continue
		}
		resp, err = client.Do(req)
		if err == nil {
			if len(statusOk) != 0 {
				if _, has := statusOk[resp.StatusCode]; !has {
					rlog.addLog("statusCode wrong", resp.StatusCode)
					goto failed
				}
			}
			httpClient.ProxyManager.proxyPool.MarkProxyStatus(proxy, PROXY_USED_SUC)
			break
		} else {
			rlog.addLog("resErr", err.Error())
		}

	failed:
		{
			httpClient.ProxyManager.proxyPool.MarkProxyStatus(proxy, PROXY_USED_FAILED)
			rlog.addLog("failed")
			if no == max_re_try {
				rlog.addLog("all failed")
			}
			rlog.print()
		}
	}

	w.Header().Set("x-man-try", fmt.Sprintf("%d/%d", no, max_re_try))
	w.Header().Set("x-man-id", fmt.Sprintf("%d", rlog.logId))

	if err != nil || resp == nil {
		w.WriteHeader(550)
		w.Write([]byte("all failed," + fmt.Sprintf("try:%d", no)))
		return
	}

	resp.Header.Del("Content-Length")
	resp.Header.Del("Connection")

	copyHeaders(w.Header(), resp.Header)
	rlog.addLog("status:", resp.StatusCode)

	w.WriteHeader(resp.StatusCode)

	n, err := io.Copy(w, resp.Body)
	rlog.addLog("res_len:", n)
	if err != nil {
		//client may be not read the body
		rlog.addLog("io.copy_err:", err)
	}

	if err := resp.Body.Close(); err != nil {
		rlog.addLog("close response body err:", err)
	}
	rlog.addLog("OK")
}

func copyHeaders(dst, src http.Header) {
	for k, vs := range src {
		if len(k) > 5 && k[:6] == "Proxy-" {
			continue
		}
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}
<commit_msg>clean header<commit_after>package manager

import (
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httputil"
	"strings"
	"time"
)

type requestLog struct {
	data      []string
	logData   []string
	startTime time.Time
	req       *http.Request
	logId     int64
}

func NewRequestLog(req *http.Request) *requestLog {
	rlog := &requestLog{req: req}
	rlog.reset()
	return rlog
}

func (rlog *requestLog) print() {
	if len(rlog.logData) == 0 {
		return
	}
	used := time.Now().Sub(rlog.startTime)
	log.Println("logid:", rlog.logId,
		rlog.req.Method, rlog.req.URL.String(),
		strings.Join(rlog.data, " "),
		strings.Join(rlog.logData, " "),
		"used:", used.String())
	rlog.reset()
}

func (rlog *requestLog) setLog(arg ...interface{}) {
	rlog.data = append(rlog.logData, fmt.Sprint(arg))
}
func (rlog *requestLog) addLog(arg ...interface{}) {
	rlog.logData = append(rlog.logData, fmt.Sprint(arg))
}
func (rlog *requestLog) reset() {
	rlog.startTime = time.Now()
	rlog.logData = []string{}
}

type HttpClient struct {
	ProxyManager *ProxyManager
}

func NewHttpClient(manager *ProxyManager) *HttpClient {
	log.Println("loading http client...")
	proxy := new(HttpClient)
	proxy.ProxyManager = manager

	return proxy
}

func (httpClient *HttpClient) ServeHTTP(w http.ResponseWriter, req *http.Request) {
	rlog := NewRequestLog(req)

	rlog.logId = httpClient.ProxyManager.reqNum + time.Now().Unix()

	defer rlog.print()
	user := getAuthorInfo(req)
	rlog.setLog("uname", user.Name)

	if PROXY_DEBUG {
		dump, _ := httputil.DumpRequest(req, true)
		log.Println("req dump:\n", string(dump))
	}

	if !httpClient.ProxyManager.checkHttpAuth(user) {
		rlog.addLog("auth", "failed")
		w.Header().Set("Proxy-Authenticate", "Basic realm=auth need")
		w.WriteHeader(407)
		w.Write([]byte("auth failed"))
		return
	}

	req.RequestURI = ""
	req.Header.Del("Connection")
	req.Header.Del("Proxy-Connection")

	_statusOk := strings.Split(req.Header.Get("X-Man-Status-Ok"), ",")
	statusOk := make(map[int]int)
	for _, v := range _statusOk {
		_code := int(getInt64(v))
		if _code > 0 {
			statusOk[_code] = 1
		}
	}
	_clientReTry := -1
	x_man_retry := req.Header.Get("X-Man-ReTry")
	if x_man_retry != "" {
		_clientReTry = int(getInt64(x_man_retry))
	}

	for k := range req.Header {
		k=strings.ToLower(k)
		if strings.HasPrefix(k, "x-man") ||strings.HasPrefix(k,"proxy-"){
			req.Header.Del(k)
		}
	}

	var resp *http.Response
	var err error

	max_re_try := httpClient.ProxyManager.config.reTry + 1
	if _clientReTry >= 0 && _clientReTry <= httpClient.ProxyManager.config.reTryMax {
		max_re_try = _clientReTry + 1
	}
	no := 1
	for ; no <= max_re_try; no++ {
		rlog.addLog("try", fmt.Sprintf("%d/%d", no, max_re_try))
		proxy, err := httpClient.ProxyManager.proxyPool.GetOneProxy(user.Name)
		if err != nil {
			rlog.addLog("get_proxy_faield", err)
			rlog.print()
			break
		}
		rlog.addLog("proxy", proxy.proxy)
		rlog.addLog("proxyUsed", proxy.Used)
		client, err := NewClient(proxy.URL, httpClient.ProxyManager.config.timeout)
		if err != nil {
			rlog.addLog("get http client failed", err)
			continue
		}
		resp, err = client.Do(req)
		if err == nil {
			if len(statusOk) != 0 {
				if _, has := statusOk[resp.StatusCode]; !has {
					rlog.addLog("statusCode wrong", resp.StatusCode)
					goto failed
				}
			}
			httpClient.ProxyManager.proxyPool.MarkProxyStatus(proxy, PROXY_USED_SUC)
			break
		} else {
			rlog.addLog("resErr", err.Error())
		}

	failed:
		{
			httpClient.ProxyManager.proxyPool.MarkProxyStatus(proxy, PROXY_USED_FAILED)
			rlog.addLog("failed")
			if no == max_re_try {
				rlog.addLog("all failed")
			}
			rlog.print()
		}
	}

	w.Header().Set("x-man-try", fmt.Sprintf("%d/%d", no, max_re_try))
	w.Header().Set("x-man-id", fmt.Sprintf("%d", rlog.logId))

	if err != nil || resp == nil {
		w.WriteHeader(550)
		w.Write([]byte("all failed," + fmt.Sprintf("try:%d", no)))
		return
	}

	resp.Header.Del("Content-Length")
	resp.Header.Del("Connection")

	copyHeaders(w.Header(), resp.Header)
	rlog.addLog("status:", resp.StatusCode)

	w.WriteHeader(resp.StatusCode)

	n, err := io.Copy(w, resp.Body)
	rlog.addLog("res_len:", n)
	if err != nil {
		//client may be not read the body
		rlog.addLog("io.copy_err:", err)
	}

	if err := resp.Body.Close(); err != nil {
		rlog.addLog("close response body err:", err)
	}
	rlog.addLog("OK")
}

func copyHeaders(dst, src http.Header) {
	for k, vs := range src {
		if len(k) > 5 && k[:6] == "Proxy-" {
			continue
		}
		for _, v := range vs {
			dst.Add(k, v)
		}
	}
}
<|endoftext|>


<commit_before>package jserver

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestListPath(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"},{"age":15,"id":"2","name":"serval"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestIDPath(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test/1")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `{"age":14,"id":"1","name":"kaban"}` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterString(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?name=kaban")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterNumber(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?age=14")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterNotExistsKey(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?invalid=14")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"},{"age":15,"id":"2","name":"serval"}]` {
		t.Error("response body invalid")
		return
	}
}
<commit_msg>add test case.<commit_after>package jserver

import (
	"io/ioutil"
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestListPath(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"},{"age":15,"id":"2","name":"serval"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestIDPath(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test/1")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `{"age":14,"id":"1","name":"kaban"}` {
		t.Error("response body invalid")
		return
	}
}

func TestIDPathNotFound(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test/9999")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `{"error":"Not Found."}` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterString(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?name=kaban")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterStringNoRecord(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?name=invalid")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterNumber(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?age=14")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"}]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterNumberInvalid(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?age=invalid")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[]` {
		t.Error("response body invalid")
		return
	}
}

func TestFilterNotExistsKey(t *testing.T) {
	jsonRouter := NewJsonRouter()
	jsonRouter.Add("/test", "./test.json")

	ts := httptest.NewServer(jsonRouter)
	defer ts.Close()

	res, err := http.Get(ts.URL + "/test?invalid=14")
	if err != nil {
		t.Error("unexpected")
		return
	}

	body, err := ioutil.ReadAll(res.Body)
	if err != nil {
		t.Error("unexpected")
		return
	}

	if string(body) != `[{"age":14,"id":"1","name":"kaban"},{"age":15,"id":"2","name":"serval"}]` {
		t.Error("response body invalid")
		return
	}
}
<|endoftext|>


<commit_before>package glfw3

//#include <GLFW/glfw3.h>
//void glfwSetErrorCallbackCB();
import "C"

import (
	"fmt"
)

//ErrorCode corresponds to an error code.
type ErrorCode int

//Error codes.
const (
	NotInitialized     ErrorCode = C.GLFW_NOT_INITIALIZED     //GLFW has not been initialized.
	NoCurrentContext   ErrorCode = C.GLFW_NO_CURRENT_CONTEXT  //No context is current.
	InvalidEnum        ErrorCode = C.GLFW_INVALID_ENUM        //One of the enum parameters for the function was given an invalid enum.
	InvalidValue       ErrorCode = C.GLFW_INVALID_VALUE       //One of the parameters for the function was given an invalid value.
	OutOfMemory        ErrorCode = C.GLFW_OUT_OF_MEMORY       //A memory allocation failed.
	ApiUnavailable     ErrorCode = C.GLFW_API_UNAVAILABLE     //GLFW could not find support for the requested client API on the system.
	VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE //The requested client API version is not available.
	PlatformError      ErrorCode = C.GLFW_PLATFORM_ERROR      //A platform-specific error occurred that does not match any of the more specific categories.
	FormatUnavailable  ErrorCode = C.GLFW_FORMAT_UNAVAILABLE  //The clipboard did not contain data in the requested format.
)

//GlfwError holds error code and description.
type GlfwError struct {
	Code ErrorCode
	Desc string
}

//Holds the value of the last error
var lastError = make(chan *GlfwError, 1)

//Function that will be called back when there is an error. Updates lastError.
var fErrorHolder = func(code ErrorCode, desc string) {
	lastError <- &GlfwError{code, desc}
}

//export goErrorCB
func goErrorCB(code C.int, desc *C.char) {
	fErrorHolder(ErrorCode(code), C.GoString(desc))
}

//Error prints the error code and description in a readable format.
func (e *GlfwError) Error() string {
	return fmt.Sprintf("Error %d: %s", e.Code, e.Desc)
}

//Set the glfw callback internally
func init() {
	C.glfwSetErrorCallbackCB()
}
<commit_msg>Remove extra function call<commit_after>package glfw3

//#include <GLFW/glfw3.h>
//void glfwSetErrorCallbackCB();
import "C"

import (
	"fmt"
)

//ErrorCode corresponds to an error code.
type ErrorCode int

//Error codes.
const (
	NotInitialized     ErrorCode = C.GLFW_NOT_INITIALIZED     //GLFW has not been initialized.
	NoCurrentContext   ErrorCode = C.GLFW_NO_CURRENT_CONTEXT  //No context is current.
	InvalidEnum        ErrorCode = C.GLFW_INVALID_ENUM        //One of the enum parameters for the function was given an invalid enum.
	InvalidValue       ErrorCode = C.GLFW_INVALID_VALUE       //One of the parameters for the function was given an invalid value.
	OutOfMemory        ErrorCode = C.GLFW_OUT_OF_MEMORY       //A memory allocation failed.
	ApiUnavailable     ErrorCode = C.GLFW_API_UNAVAILABLE     //GLFW could not find support for the requested client API on the system.
	VersionUnavailable ErrorCode = C.GLFW_VERSION_UNAVAILABLE //The requested client API version is not available.
	PlatformError      ErrorCode = C.GLFW_PLATFORM_ERROR      //A platform-specific error occurred that does not match any of the more specific categories.
	FormatUnavailable  ErrorCode = C.GLFW_FORMAT_UNAVAILABLE  //The clipboard did not contain data in the requested format.
)

//GlfwError holds error code and description.
type GlfwError struct {
	Code ErrorCode
	Desc string
}

//Holds the value of the last error
var lastError = make(chan *GlfwError, 1)

//export goErrorCB
func goErrorCB(code C.int, desc *C.char) {
	lastError <- &GlfwError{ErrorCode(code), C.GoString(desc)}
}

//Error prints the error code and description in a readable format.
func (e *GlfwError) Error() string {
	return fmt.Sprintf("Error %d: %s", e.Code, e.Desc)
}

//Set the glfw callback internally
func init() {
	C.glfwSetErrorCallbackCB()
}
<|endoftext|>


<commit_before>package heroku

import (
	"fmt"
	"testing"

	"github.com/bgentry/heroku-go"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccHerokuApp_Basic(t *testing.T) {
	var app heroku.App

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", "terraform-test-app"),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.foo", "bar"),
				),
			},
		},
	})
}

func testAccCheckHerokuAppDestroy(s *terraform.State) error {
	client := testAccProvider.client

	for _, rs := range s.Resources {
		if rs.Type != "heroku_app" {
			continue
		}

		_, err := client.AppInfo(rs.ID)

		if err == nil {
			return fmt.Errorf("App still exists")
		}
	}

	return nil
}

func testAccCheckHerokuAppAttributes(app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.client

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != "terraform-test-app" {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["foo"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.Resources[n]
		fmt.Printf("resources %#v", s.Resources)
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.client

		foundApp, err := client.AppInfo(rs.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

const testAccCheckHerokuAppConfig_basic = `
resource "heroku_app" "foobar" {
    name = "terraform-test-app"

    config_vars = {
    	FOO = bar
    }
}`
<commit_msg>providers/heroku: handle case sensitivity<commit_after>package heroku

import (
	"fmt"
	"testing"

	"github.com/bgentry/heroku-go"
	"github.com/hashicorp/terraform/helper/resource"
	"github.com/hashicorp/terraform/terraform"
)

func TestAccHerokuApp_Basic(t *testing.T) {
	var app heroku.App

	resource.Test(t, resource.TestCase{
		PreCheck:     func() { testAccPreCheck(t) },
		Providers:    testAccProviders,
		CheckDestroy: testAccCheckHerokuAppDestroy,
		Steps: []resource.TestStep{
			resource.TestStep{
				Config: testAccCheckHerokuAppConfig_basic,
				Check: resource.ComposeTestCheckFunc(
					testAccCheckHerokuAppExists("heroku_app.foobar", &app),
					testAccCheckHerokuAppAttributes(&app),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "name", "terraform-test-app"),
					resource.TestCheckResourceAttr(
						"heroku_app.foobar", "config_vars.0.FOO", "bar"),
				),
			},
		},
	})
}

func testAccCheckHerokuAppDestroy(s *terraform.State) error {
	client := testAccProvider.client

	for _, rs := range s.Resources {
		if rs.Type != "heroku_app" {
			continue
		}

		_, err := client.AppInfo(rs.ID)

		if err == nil {
			return fmt.Errorf("App still exists")
		}
	}

	return nil
}

func testAccCheckHerokuAppAttributes(app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		client := testAccProvider.client

		if app.Region.Name != "us" {
			return fmt.Errorf("Bad region: %s", app.Region.Name)
		}

		if app.Stack.Name != "cedar" {
			return fmt.Errorf("Bad stack: %s", app.Stack.Name)
		}

		if app.Name != "terraform-test-app" {
			return fmt.Errorf("Bad name: %s", app.Name)
		}

		vars, err := client.ConfigVarInfo(app.Name)
		if err != nil {
			return err
		}

		if vars["FOO"] != "bar" {
			return fmt.Errorf("Bad config vars: %v", vars)
		}

		return nil
	}
}

func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc {
	return func(s *terraform.State) error {
		rs, ok := s.Resources[n]
		fmt.Printf("resources %#v", s.Resources)
		if !ok {
			return fmt.Errorf("Not found: %s", n)
		}

		if rs.ID == "" {
			return fmt.Errorf("No App Name is set")
		}

		client := testAccProvider.client

		foundApp, err := client.AppInfo(rs.ID)

		if err != nil {
			return err
		}

		if foundApp.Name != rs.ID {
			return fmt.Errorf("App not found")
		}

		*app = *foundApp

		return nil
	}
}

const testAccCheckHerokuAppConfig_basic = `
resource "heroku_app" "foobar" {
    name = "terraform-test-app"

    config_vars = {
    	FOO = bar
    }
}`
<|endoftext|>


<commit_before><commit_msg>Add `Update` for renaming an existing `DocAction`<commit_after><|endoftext|>


<commit_before>package main

import (
	"errors"
	"fmt"
)

func throw(f string, a ...interface{}) {
	panic(errors.New(fmt.Sprintf(f, a...)))
}

func catch() {
	if err := recover(); err != nil {
		fmt.Println(err)
	}
}

func rethrow(f string, a ...interface{}) {
	if err := recover(); err != nil {
		throw(fmt.Sprint(err)+": "+f, a...)
	}
}
<commit_msg>Переработана подсистема исключений<commit_after>package main

import (
	"fmt"
	"log"
	"os"
)

// throw вызывает panic с указанным сообщением, помещенным в error.
func throw(f string, a ...interface{}) {
	panic(fmt.Errorf(f, a...))
}

// rethrow прекращает panic, извлекает сообщение, добавляет к нему префикс
// и снова вызывает panic(). Функция должна вызываться только с помощью defer.
func rethrow(f string, a ...interface{}) {
	if err := recover(); err != nil {
		throw(f+": "+fmt.Sprint(err), a...)
	}
}

// exit отлавливает panic, выводит сообщение в stdout и stderr? и завершает
// работу программы с кодом 1. Если не было panic, то ничего не делает.
// Должна вызываться только с помощью defer и из main().
func exit() {
	if err := recover(); err != nil {
		log.Println(err)
		fmt.Println(err)
		os.Exit(1)
	}
}
<|endoftext|>


<commit_before>package state

import (
	"sync"
	"time"

	"github.com/docker/swarm-v2/api"

	"golang.org/x/net/context"
	"google.golang.org/grpc"
	"google.golang.org/grpc/transport"
)

// Raft represents a connection to a raft member
type Raft struct {
	api.RaftClient
	Conn *grpc.ClientConn
}

// GetRaftClient returns a raft client object to communicate
// with other raft members
func GetRaftClient(addr string, timeout time.Duration) (*Raft, error) {
	conn, err := dial(addr, "tcp", timeout)
	if err != nil {
		return nil, err
	}

	return &Raft{
		RaftClient: api.NewRaftClient(conn),
		Conn:       conn,
	}, nil
}

// dial returns a grpc client connection
func dial(addr string, protocol string, timeout time.Duration) (*grpc.ClientConn, error) {
	grpcOptions := []grpc.DialOption{grpc.WithInsecure(), grpc.WithPicker(&reconnectPicker{target: addr})}
	if timeout != 0 {
		grpcOptions = append(grpcOptions, grpc.WithTimeout(timeout))
	}
	return grpc.Dial(addr, grpcOptions...)
}

// Register registers the node raft server
func Register(server *grpc.Server, node *Node) {
	api.RegisterRaftServer(server, node)
}

// reconnectPicker is a Picker which attempts a new connection if necessary
// before each request. It's used to work around GRPC's exponential backoff,
// which is undesired for raft.
type reconnectPicker struct {
	target string
	conn   *grpc.Conn
	cc     *grpc.ClientConn

	mu sync.Mutex
}

func (p *reconnectPicker) Init(cc *grpc.ClientConn) error {
	// Init does not need to hold the mutex, because it's either being
	// called from Dial before anything else can use the picker, or from
	// Pick, which holds the mutex.

	p.cc = cc
	c, err := grpc.NewConn(cc)
	if err != nil {
		return err
	}
	p.conn = c
	return nil
}

func (p *reconnectPicker) Pick(ctx context.Context) (transport.ClientTransport, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	// TODO(aaronl): This is a very poor way of triggering a new connection
	// attempt. We really need some way of telling the existing p.conn to
	// try again. Unfortunately, NotifyReset doesn't seem to do anything
	// immediate when a connection is in its retry cycle.
	if p.conn.State() != grpc.Ready {
		_ = p.conn.Close()
		if err := p.Init(p.cc); err != nil {
			return nil, err
		}
	}
	return p.conn.Wait(ctx)
}

func (p *reconnectPicker) PickAddr() (string, error) {
	return p.target, nil
}

func (p *reconnectPicker) State() (grpc.ConnectivityState, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	return p.conn.State(), nil
}

func (p *reconnectPicker) WaitForStateChange(ctx context.Context, sourceState grpc.ConnectivityState) (grpc.ConnectivityState, error) {
	p.mu.Lock()
	defer p.mu.Unlock()

	return p.conn.WaitForStateChange(ctx, sourceState)
}

func (p *reconnectPicker) Close() error {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.conn != nil {
		return p.conn.Close()
	}
	return nil
}
<commit_msg>Use configrable GRPC backoff for raft<commit_after>package state

import (
	"time"

	"github.com/docker/swarm-v2/api"
	"google.golang.org/grpc"
)

// Raft represents a connection to a raft member
type Raft struct {
	api.RaftClient
	Conn *grpc.ClientConn
}

// GetRaftClient returns a raft client object to communicate
// with other raft members
func GetRaftClient(addr string, timeout time.Duration) (*Raft, error) {
	conn, err := dial(addr, "tcp", timeout)
	if err != nil {
		return nil, err
	}

	return &Raft{
		RaftClient: api.NewRaftClient(conn),
		Conn:       conn,
	}, nil
}

// dial returns a grpc client connection
func dial(addr string, protocol string, timeout time.Duration) (*grpc.ClientConn, error) {
	backoffConfig := *grpc.DefaultBackoffConfig
	backoffConfig.MaxDelay = 2 * time.Second

	grpcOptions := []grpc.DialOption{
		grpc.WithInsecure(),
		grpc.WithBackoffConfig(&backoffConfig),
	}
	if timeout != 0 {
		grpcOptions = append(grpcOptions, grpc.WithTimeout(timeout))
	}
	return grpc.Dial(addr, grpcOptions...)
}

// Register registers the node raft server
func Register(server *grpc.Server, node *Node) {
	api.RegisterRaftServer(server, node)
}
<|endoftext|>


<commit_before>package flags

import (
	"fmt"
	"reflect"
)

// ErrorType represents the type of error.
type ErrorType uint

const (
	// ErrUnknown indicates a generic error.
	ErrUnknown ErrorType = iota

	// ErrExpectedArgument indicates that an argument was expected.
	ErrExpectedArgument

	// ErrUnknownFlag indicates an unknown flag.
	ErrUnknownFlag

	// ErrUnknownGroup indicates an unknown group.
	ErrUnknownGroup

	// ErrMarshal indicates a marshalling error while converting values.
	ErrMarshal

	// ErrHelp indicates that the built-in help was shown (the error
	// contains the help message).
	ErrHelp

	// ErrNoArgumentForBool indicates that an argument was given for a
	// boolean flag (which don't not take any arguments).
	ErrNoArgumentForBool

	// ErrRequired indicates that a required flag was not provided.
	ErrRequired

	// ErrShortNameTooLong indicates that a short flag name was specified,
	// longer than one character.
	ErrShortNameTooLong

	// ErrDuplicatedFlag indicates that a short or long flag has been
	// defined more than once
	ErrDuplicatedFlag

	// ErrTag indicates an error while parsing flag tags.
	ErrTag

	// ErrCommandRequired indicates that a command was required but not
	// specified
	ErrCommandRequired

	// ErrUnknownCommand indicates that an unknown command was specified.
	ErrUnknownCommand
)

func (e ErrorType) String() string {
	return reflect.TypeOf(e).Name()
}

// Error represents a parser error. The error returned from Parse is of this
// type. The error contains both a Type and Message.
type Error struct {
	// The type of error
	Type ErrorType

	// The error message
	Message string
}

// Error returns the error's message
func (e *Error) Error() string {
	return e.Message
}

func newError(tp ErrorType, message string) *Error {
	return &Error{
		Type:    tp,
		Message: message,
	}
}

func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
	return newError(tp, fmt.Sprintf(format, args...))
}

func wrapError(err error) *Error {
	ret, ok := err.(*Error)

	if !ok {
		return newError(ErrUnknown, err.Error())
	}

	return ret
}
<commit_msg>Fix error type to string<commit_after>package flags

import (
	"fmt"
)

// ErrorType represents the type of error.
type ErrorType uint

const (
	// ErrUnknown indicates a generic error.
	ErrUnknown ErrorType = iota

	// ErrExpectedArgument indicates that an argument was expected.
	ErrExpectedArgument

	// ErrUnknownFlag indicates an unknown flag.
	ErrUnknownFlag

	// ErrUnknownGroup indicates an unknown group.
	ErrUnknownGroup

	// ErrMarshal indicates a marshalling error while converting values.
	ErrMarshal

	// ErrHelp indicates that the built-in help was shown (the error
	// contains the help message).
	ErrHelp

	// ErrNoArgumentForBool indicates that an argument was given for a
	// boolean flag (which don't not take any arguments).
	ErrNoArgumentForBool

	// ErrRequired indicates that a required flag was not provided.
	ErrRequired

	// ErrShortNameTooLong indicates that a short flag name was specified,
	// longer than one character.
	ErrShortNameTooLong

	// ErrDuplicatedFlag indicates that a short or long flag has been
	// defined more than once
	ErrDuplicatedFlag

	// ErrTag indicates an error while parsing flag tags.
	ErrTag

	// ErrCommandRequired indicates that a command was required but not
	// specified
	ErrCommandRequired

	// ErrUnknownCommand indicates that an unknown command was specified.
	ErrUnknownCommand
)

func (e ErrorType) String() string {
	switch e {
	case ErrUnknown:
		return "unknown"
	case ErrExpectedArgument:
		return "expected argument"
	case ErrUnknownFlag:
		return "unknown flag"
	case ErrUnknownGroup:
		return "unknown group"
	case ErrMarshal:
		return "marshal"
	case ErrHelp:
		return "help"
	case ErrNoArgumentForBool:
		return "no argument for bool"
	case ErrRequired:
		return "required"
	case ErrShortNameTooLong:
		return "short name too long"
	case ErrDuplicatedFlag:
		return "duplicated flag"
	case ErrTag:
		return "tag"
	case ErrCommandRequired:
		return "command required"
	case ErrUnknownCommand:
		return "unknown command"
	}

	return "unrecognized error type"
}

// Error represents a parser error. The error returned from Parse is of this
// type. The error contains both a Type and Message.
type Error struct {
	// The type of error
	Type ErrorType

	// The error message
	Message string
}

// Error returns the error's message
func (e *Error) Error() string {
	return e.Message
}

func newError(tp ErrorType, message string) *Error {
	return &Error{
		Type:    tp,
		Message: message,
	}
}

func newErrorf(tp ErrorType, format string, args ...interface{}) *Error {
	return newError(tp, fmt.Sprintf(format, args...))
}

func wrapError(err error) *Error {
	ret, ok := err.(*Error)

	if !ok {
		return newError(ErrUnknown, err.Error())
	}

	return ret
}
<|endoftext|>


<commit_before>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// EpicsService handles communication with the epic related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
type EpicsService struct {
	client *Client
}

// EpicAuthor represents a author of the epic.
type EpicAuthor struct {
	ID        int    `json:"id"`
	State     string `json:"state"`
	WebURL    string `json:"web_url"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar_url"`
	Username  string `json:"username"`
}

// Epic represents a GitLab epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
type Epic struct {
	ID                      int         `json:"id"`
	IID                     int         `json:"iid"`
	GroupID                 int         `json:"group_id"`
	ParentID                int         `json:"parent_id"`
	Title                   string      `json:"title"`
	Description             string      `json:"description"`
	State                   string      `json:"state"`
	WebURL                  string      `json:"web_url"`
	Author                  *EpicAuthor `json:"author"`
	StartDate               *ISOTime    `json:"start_date"`
	StartDateIsFixed        bool        `json:"start_date_is_fixed"`
	StartDateFixed          *ISOTime    `json:"start_date_fixed"`
	StartDateFromMilestones *ISOTime    `json:"start_date_from_milestones"`
	DueDate                 *ISOTime    `json:"due_date"`
	DueDateIsFixed          bool        `json:"due_date_is_fixed"`
	DueDateFixed            *ISOTime    `json:"due_date_fixed"`
	DueDateFromMilestones   *ISOTime    `json:"due_date_from_milestones"`
	CreatedAt               *time.Time  `json:"created_at"`
	UpdatedAt               *time.Time  `json:"updated_at"`
	ClosedAt                *time.Time  `json:"closed_at"`
	Labels                  []string    `json:"labels"`
	Upvotes                 int         `json:"upvotes"`
	Downvotes               int         `json:"downvotes"`
	UserNotesCount          int         `json:"user_notes_count"`
	URL                     string      `json:"url"`
}

func (e Epic) String() string {
	return Stringify(e)
}

// ListGroupEpicsOptions represents the available ListGroupEpics() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
type ListGroupEpicsOptions struct {
	ListOptions
	AuthorID                *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
	Labels                  *Labels    `url:"labels,comma,omitempty" json:"labels,omitempty"`
	WithLabelDetails        *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
	OrderBy                 *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
	Sort                    *string    `url:"sort,omitempty" json:"sort,omitempty"`
	Search                  *string    `url:"search,omitempty" json:"search,omitempty"`
	State                   *string    `url:"state,omitempty" json:"state,omitempty"`
	CreatedAfter            *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
	CreatedBefore           *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
	UpdatedAfter            *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
	UpdatedBefore           *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
	IncludeAncestorGroups   *bool      `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"`
	IncludeDescendantGroups *bool      `url:"include_descendant_groups,omitempty" json:"include_descendant_groups,omitempty"`
	MyReactionEmoji         *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
}

// ListGroupEpics gets a list of group epics. This function accepts pagination
// parameters page and per_page to return the list of group epics.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
func (s *EpicsService) ListGroupEpics(gid interface{}, opt *ListGroupEpicsOptions, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics", PathEscape(group))

	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var es []*Epic
	resp, err := s.client.Do(req, &es)
	if err != nil {
		return nil, resp, err
	}

	return es, resp, err
}

// GetEpic gets a single group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#single-epic
func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// GetEpicLinks gets all child epics of an epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_links.html
func (s *EpicsService) GetEpicLinks(gid interface{}, epic int, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d/epics", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var e []*Epic
	resp, err := s.client.Do(req, &e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// CreateEpicOptions represents the available CreateEpic() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
type CreateEpicOptions struct {
	Title            *string  `url:"title,omitempty" json:"title,omitempty"`
	Description      *string  `url:"description,omitempty" json:"description,omitempty"`
	Labels           *Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
	StartDateIsFixed *bool    `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
	StartDateFixed   *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
	DueDateIsFixed   *bool    `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
	DueDateFixed     *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
}

// CreateEpic creates a new group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics", PathEscape(group))

	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// UpdateEpicOptions represents the available UpdateEpic() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
type UpdateEpicOptions struct {
	Title            *string  `url:"title,omitempty" json:"title,omitempty"`
	Description      *string  `url:"description,omitempty" json:"description,omitempty"`
	Labels           *Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
	StartDateIsFixed *bool    `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
	StartDateFixed   *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
	DueDateIsFixed   *bool    `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
	DueDateFixed     *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
	StateEvent       *string  `url:"state_event,omitempty" json:"state_event,omitempty"`
}

// UpdateEpic updates an existing group epic. This function is also used
// to mark an epic as closed.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
func (s *EpicsService) UpdateEpic(gid interface{}, epic int, opt *UpdateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// DeleteEpic deletes a single group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#delete-epic
func (s *EpicsService) DeleteEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<commit_msg>feat: Add attribute Confidential to UpdateEpicOptions<commit_after>//
// Copyright 2021, Sander van Harmelen
//
// 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 gitlab

import (
	"fmt"
	"net/http"
	"time"
)

// EpicsService handles communication with the epic related methods
// of the GitLab API.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
type EpicsService struct {
	client *Client
}

// EpicAuthor represents a author of the epic.
type EpicAuthor struct {
	ID        int    `json:"id"`
	State     string `json:"state"`
	WebURL    string `json:"web_url"`
	Name      string `json:"name"`
	AvatarURL string `json:"avatar_url"`
	Username  string `json:"username"`
}

// Epic represents a GitLab epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html
type Epic struct {
	ID                      int         `json:"id"`
	IID                     int         `json:"iid"`
	GroupID                 int         `json:"group_id"`
	ParentID                int         `json:"parent_id"`
	Title                   string      `json:"title"`
	Description             string      `json:"description"`
	State                   string      `json:"state"`
	WebURL                  string      `json:"web_url"`
	Author                  *EpicAuthor `json:"author"`
	StartDate               *ISOTime    `json:"start_date"`
	StartDateIsFixed        bool        `json:"start_date_is_fixed"`
	StartDateFixed          *ISOTime    `json:"start_date_fixed"`
	StartDateFromMilestones *ISOTime    `json:"start_date_from_milestones"`
	DueDate                 *ISOTime    `json:"due_date"`
	DueDateIsFixed          bool        `json:"due_date_is_fixed"`
	DueDateFixed            *ISOTime    `json:"due_date_fixed"`
	DueDateFromMilestones   *ISOTime    `json:"due_date_from_milestones"`
	CreatedAt               *time.Time  `json:"created_at"`
	UpdatedAt               *time.Time  `json:"updated_at"`
	ClosedAt                *time.Time  `json:"closed_at"`
	Labels                  []string    `json:"labels"`
	Upvotes                 int         `json:"upvotes"`
	Downvotes               int         `json:"downvotes"`
	UserNotesCount          int         `json:"user_notes_count"`
	URL                     string      `json:"url"`
}

func (e Epic) String() string {
	return Stringify(e)
}

// ListGroupEpicsOptions represents the available ListGroupEpics() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
type ListGroupEpicsOptions struct {
	ListOptions
	AuthorID                *int       `url:"author_id,omitempty" json:"author_id,omitempty"`
	Labels                  *Labels    `url:"labels,comma,omitempty" json:"labels,omitempty"`
	WithLabelDetails        *bool      `url:"with_labels_details,omitempty" json:"with_labels_details,omitempty"`
	OrderBy                 *string    `url:"order_by,omitempty" json:"order_by,omitempty"`
	Sort                    *string    `url:"sort,omitempty" json:"sort,omitempty"`
	Search                  *string    `url:"search,omitempty" json:"search,omitempty"`
	State                   *string    `url:"state,omitempty" json:"state,omitempty"`
	CreatedAfter            *time.Time `url:"created_after,omitempty" json:"created_after,omitempty"`
	CreatedBefore           *time.Time `url:"created_before,omitempty" json:"created_before,omitempty"`
	UpdatedAfter            *time.Time `url:"updated_after,omitempty" json:"updated_after,omitempty"`
	UpdatedBefore           *time.Time `url:"updated_before,omitempty" json:"updated_before,omitempty"`
	IncludeAncestorGroups   *bool      `url:"include_ancestor_groups,omitempty" json:"include_ancestor_groups,omitempty"`
	IncludeDescendantGroups *bool      `url:"include_descendant_groups,omitempty" json:"include_descendant_groups,omitempty"`
	MyReactionEmoji         *string    `url:"my_reaction_emoji,omitempty" json:"my_reaction_emoji,omitempty"`
}

// ListGroupEpics gets a list of group epics. This function accepts pagination
// parameters page and per_page to return the list of group epics.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#list-epics-for-a-group
func (s *EpicsService) ListGroupEpics(gid interface{}, opt *ListGroupEpicsOptions, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics", PathEscape(group))

	req, err := s.client.NewRequest(http.MethodGet, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	var es []*Epic
	resp, err := s.client.Do(req, &es)
	if err != nil {
		return nil, resp, err
	}

	return es, resp, err
}

// GetEpic gets a single group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#single-epic
func (s *EpicsService) GetEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// GetEpicLinks gets all child epics of an epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epic_links.html
func (s *EpicsService) GetEpicLinks(gid interface{}, epic int, options ...RequestOptionFunc) ([]*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d/epics", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodGet, u, nil, options)
	if err != nil {
		return nil, nil, err
	}

	var e []*Epic
	resp, err := s.client.Do(req, &e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// CreateEpicOptions represents the available CreateEpic() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
type CreateEpicOptions struct {
	Title            *string  `url:"title,omitempty" json:"title,omitempty"`
	Description      *string  `url:"description,omitempty" json:"description,omitempty"`
	Labels           *Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
	StartDateIsFixed *bool    `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
	StartDateFixed   *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
	DueDateIsFixed   *bool    `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
	DueDateFixed     *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
}

// CreateEpic creates a new group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#new-epic
func (s *EpicsService) CreateEpic(gid interface{}, opt *CreateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics", PathEscape(group))

	req, err := s.client.NewRequest(http.MethodPost, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// UpdateEpicOptions represents the available UpdateEpic() options.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
type UpdateEpicOptions struct {
	Title            *string  `url:"title,omitempty" json:"title,omitempty"`
	Description      *string  `url:"description,omitempty" json:"description,omitempty"`
	Labels           *Labels  `url:"labels,comma,omitempty" json:"labels,omitempty"`
	StartDateIsFixed *bool    `url:"start_date_is_fixed,omitempty" json:"start_date_is_fixed,omitempty"`
	StartDateFixed   *ISOTime `url:"start_date_fixed,omitempty" json:"start_date_fixed,omitempty"`
	DueDateIsFixed   *bool    `url:"due_date_is_fixed,omitempty" json:"due_date_is_fixed,omitempty"`
	DueDateFixed     *ISOTime `url:"due_date_fixed,omitempty" json:"due_date_fixed,omitempty"`
	StateEvent       *string  `url:"state_event,omitempty" json:"state_event,omitempty"`
	Confidential     *bool    `url:"confidential" json:"confidential"`
}

// UpdateEpic updates an existing group epic. This function is also used
// to mark an epic as closed.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#update-epic
func (s *EpicsService) UpdateEpic(gid interface{}, epic int, opt *UpdateEpicOptions, options ...RequestOptionFunc) (*Epic, *Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodPut, u, opt, options)
	if err != nil {
		return nil, nil, err
	}

	e := new(Epic)
	resp, err := s.client.Do(req, e)
	if err != nil {
		return nil, resp, err
	}

	return e, resp, err
}

// DeleteEpic deletes a single group epic.
//
// GitLab API docs: https://docs.gitlab.com/ee/api/epics.html#delete-epic
func (s *EpicsService) DeleteEpic(gid interface{}, epic int, options ...RequestOptionFunc) (*Response, error) {
	group, err := parseID(gid)
	if err != nil {
		return nil, err
	}
	u := fmt.Sprintf("groups/%s/epics/%d", PathEscape(group), epic)

	req, err := s.client.NewRequest(http.MethodDelete, u, nil, options)
	if err != nil {
		return nil, err
	}

	return s.client.Do(req, nil)
}
<|endoftext|>


<commit_before>package finder

import (
	"bytes"
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/go-graphite/carbonapi/pkg/parser"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type taggedTermOp int

const (
	taggedTermEq       taggedTermOp = 1
	taggedTermMatch    taggedTermOp = 2
	taggedTermNe       taggedTermOp = 3
	taggedTermNotMatch taggedTermOp = 4
)

type taggedTerm struct {
	key   string
	op    taggedTermOp
	value string
}

type taggedTermList []taggedTerm

func (s taggedTermList) Len() int {
	return len(s)
}
func (s taggedTermList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s taggedTermList) Less(i, j int) bool {
	return s[i].op < s[j].op
}

type TaggedFinder struct {
	wrapped        Finder
	ctx            context.Context // for clickhouse.Query
	url            string          // clickhouse dsn
	table          string          // graphite_tag table
	timeout        time.Duration   // clickhouse query timeout
	body           []byte          // clickhouse response
	fromTimestamp  int64
	untilTimestamp int64
	isSeriesByTag  bool
}

func WrapTagged(f Finder, ctx context.Context, url string, table string, timeout time.Duration, fromTimestamp int64, untilTimestamp int64) *TaggedFinder {
	return &TaggedFinder{
		wrapped:        f,
		ctx:            ctx,
		url:            url,
		table:          table,
		timeout:        timeout,
		fromTimestamp:  fromTimestamp,
		untilTimestamp: untilTimestamp,
	}
}

func taggedTermWhere1(term *taggedTerm) string {
	switch term.op {
	case taggedTermEq:
		return fmt.Sprintf("Tag1=%s", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermNe:
		return fmt.Sprintf("Tag1!=%s", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermMatch:
		return fmt.Sprintf(
			"(Tag1 LIKE %s) AND (match(Tag1, %s))",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)

	case taggedTermNotMatch:
		return fmt.Sprintf(
			"NOT ((Tag1 LIKE %s) AND (match(Tag1, %s)))",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)
	default:
		return ""
	}
}

func taggedTermWhereN(term *taggedTerm) string {
	// arrayExists((x) -> %s, Tags)
	switch term.op {
	case taggedTermEq:
		return fmt.Sprintf("arrayExists((x) -> x=%s, Tags)", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermNe:
		return fmt.Sprintf("NOT arrayExists((x) -> x=%s, Tags)", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermMatch:
		return fmt.Sprintf(
			"arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)

	case taggedTermNotMatch:
		return fmt.Sprintf(
			"NOT arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)
	default:
		return ""
	}
}

func (t *TaggedFinder) makeWhere(query string) (string, error) {
	expr, _, err := parser.ParseExpr(query)
	if err != nil {
		return "", err
	}

	validationError := fmt.Errorf("wrong seriesByTag call: %#v", query)

	// check
	if !expr.IsFunc() {
		return "", validationError
	}
	if expr.Target() != "seriesByTag" {
		return "", validationError
	}

	args := expr.Args()
	if len(args) < 1 {
		return "", validationError
	}

	for i := 0; i < len(args); i++ {
		if !args[i].IsString() {
			return "", validationError
		}
	}

	terms := make([]taggedTerm, len(args))

	for i := 0; i < len(args); i++ {
		s := args[i].StringValue()
		a := strings.SplitN(s, "=", 2)
		if len(a) != 2 {
			return "", validationError
		}

		a[0] = strings.TrimSpace(a[0])
		a[1] = strings.TrimSpace(a[1])

		op := "="

		if len(a[0]) > 0 && a[0][len(a[0])-1] == '!' {
			op = "!" + op
			a[0] = strings.TrimSpace(a[0][:len(a[0])-1])
		}

		if len(a[1]) > 0 && a[1][0] == '~' {
			op = op + "~"
			a[1] = strings.TrimSpace(a[1][1:])
		}

		terms[i].key = a[0]
		terms[i].value = a[1]

		if terms[i].key == "name" {
			terms[i].key = "__name__"
		}

		switch op {
		case "=":
			terms[i].op = taggedTermEq
		case "!=":
			terms[i].op = taggedTermNe
		case "=~":
			terms[i].op = taggedTermMatch
		case "!=~":
			terms[i].op = taggedTermNotMatch
		default:
			return "", validationError
		}
	}

	sort.Sort(taggedTermList(terms))

	w := NewWhere()
	w.And(taggedTermWhere1(&terms[0]))

	for i := 1; i < len(terms); i++ {
		w.And(taggedTermWhereN(&terms[i]))
	}

	return w.String(), nil

}

func (t *TaggedFinder) Execute(query string) error {
	if !strings.HasPrefix(strings.TrimSpace(query), "seriesByTag") {
		return t.wrapped.Execute(query)
	}

	t.isSeriesByTag = true

	w, err := t.makeWhere(query)
	if err != nil {
		return err
	}

	sql := fmt.Sprintf("SELECT Path FROM %s WHERE %s GROUP BY Path", t.table, w)
	t.body, err = clickhouse.Query(t.ctx, t.url, sql, t.timeout)
	return err
}

func (t *TaggedFinder) List() [][]byte {
	if !t.isSeriesByTag {
		return t.wrapped.List()
	}

	if t.body == nil {
		return [][]byte{}
	}

	rows := bytes.Split(t.body, []byte{'\n'})

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	rows = rows[:len(rows)-skip]

	return rows
}

func (t *TaggedFinder) Series() [][]byte {
	if !t.isSeriesByTag {
		return t.wrapped.Series()
	}

	return t.List()
}

func (t *TaggedFinder) Abs(v []byte) []byte {
	if !t.isSeriesByTag {
		return t.wrapped.Abs(v)
	}

	u, err := url.Parse(string(v))
	if err != nil {
		return v
	}

	tags := make([]string, 0, len(u.Query()))
	for k, v := range u.Query() {
		tags = append(tags, fmt.Sprintf("%s=%s", k, v[0]))
	}

	sort.Strings(tags)
	if len(tags) == 0 {
		return []byte(u.Path)
	}

	return []byte(fmt.Sprintf("%s;%s", u.Path, strings.Join(tags, ";")))
}
<commit_msg>deleted<commit_after>package finder

import (
	"bytes"
	"context"
	"fmt"
	"net/url"
	"sort"
	"strings"
	"time"

	"github.com/go-graphite/carbonapi/pkg/parser"
	"github.com/lomik/graphite-clickhouse/helper/clickhouse"
)

type taggedTermOp int

const (
	taggedTermEq       taggedTermOp = 1
	taggedTermMatch    taggedTermOp = 2
	taggedTermNe       taggedTermOp = 3
	taggedTermNotMatch taggedTermOp = 4
)

type taggedTerm struct {
	key   string
	op    taggedTermOp
	value string
}

type taggedTermList []taggedTerm

func (s taggedTermList) Len() int {
	return len(s)
}
func (s taggedTermList) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s taggedTermList) Less(i, j int) bool {
	return s[i].op < s[j].op
}

type TaggedFinder struct {
	wrapped        Finder
	ctx            context.Context // for clickhouse.Query
	url            string          // clickhouse dsn
	table          string          // graphite_tag table
	timeout        time.Duration   // clickhouse query timeout
	body           []byte          // clickhouse response
	fromTimestamp  int64
	untilTimestamp int64
	isSeriesByTag  bool
}

func WrapTagged(f Finder, ctx context.Context, url string, table string, timeout time.Duration, fromTimestamp int64, untilTimestamp int64) *TaggedFinder {
	return &TaggedFinder{
		wrapped:        f,
		ctx:            ctx,
		url:            url,
		table:          table,
		timeout:        timeout,
		fromTimestamp:  fromTimestamp,
		untilTimestamp: untilTimestamp,
	}
}

func taggedTermWhere1(term *taggedTerm) string {
	switch term.op {
	case taggedTermEq:
		return fmt.Sprintf("Tag1=%s", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermNe:
		return fmt.Sprintf("Tag1!=%s", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermMatch:
		return fmt.Sprintf(
			"(Tag1 LIKE %s) AND (match(Tag1, %s))",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)

	case taggedTermNotMatch:
		return fmt.Sprintf(
			"NOT ((Tag1 LIKE %s) AND (match(Tag1, %s)))",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)
	default:
		return ""
	}
}

func taggedTermWhereN(term *taggedTerm) string {
	// arrayExists((x) -> %s, Tags)
	switch term.op {
	case taggedTermEq:
		return fmt.Sprintf("arrayExists((x) -> x=%s, Tags)", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermNe:
		return fmt.Sprintf("NOT arrayExists((x) -> x=%s, Tags)", Q(fmt.Sprintf("%s=%s", term.key, term.value)))
	case taggedTermMatch:
		return fmt.Sprintf(
			"arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)

	case taggedTermNotMatch:
		return fmt.Sprintf(
			"NOT arrayExists((x) -> (x LIKE %s) AND (match(x, %s)), Tags)",
			Q(fmt.Sprintf("%s=%%", term.key)),
			Q(fmt.Sprintf("%s=%s", term.key, term.value)),
		)
	default:
		return ""
	}
}

func (t *TaggedFinder) makeWhere(query string) (string, error) {
	expr, _, err := parser.ParseExpr(query)
	if err != nil {
		return "", err
	}

	validationError := fmt.Errorf("wrong seriesByTag call: %#v", query)

	// check
	if !expr.IsFunc() {
		return "", validationError
	}
	if expr.Target() != "seriesByTag" {
		return "", validationError
	}

	args := expr.Args()
	if len(args) < 1 {
		return "", validationError
	}

	for i := 0; i < len(args); i++ {
		if !args[i].IsString() {
			return "", validationError
		}
	}

	terms := make([]taggedTerm, len(args))

	for i := 0; i < len(args); i++ {
		s := args[i].StringValue()
		a := strings.SplitN(s, "=", 2)
		if len(a) != 2 {
			return "", validationError
		}

		a[0] = strings.TrimSpace(a[0])
		a[1] = strings.TrimSpace(a[1])

		op := "="

		if len(a[0]) > 0 && a[0][len(a[0])-1] == '!' {
			op = "!" + op
			a[0] = strings.TrimSpace(a[0][:len(a[0])-1])
		}

		if len(a[1]) > 0 && a[1][0] == '~' {
			op = op + "~"
			a[1] = strings.TrimSpace(a[1][1:])
		}

		terms[i].key = a[0]
		terms[i].value = a[1]

		if terms[i].key == "name" {
			terms[i].key = "__name__"
		}

		switch op {
		case "=":
			terms[i].op = taggedTermEq
		case "!=":
			terms[i].op = taggedTermNe
		case "=~":
			terms[i].op = taggedTermMatch
		case "!=~":
			terms[i].op = taggedTermNotMatch
		default:
			return "", validationError
		}
	}

	sort.Sort(taggedTermList(terms))

	w := NewWhere()
	w.And(taggedTermWhere1(&terms[0]))

	for i := 1; i < len(terms); i++ {
		w.And(taggedTermWhereN(&terms[i]))
	}

	return w.String(), nil

}

func (t *TaggedFinder) Execute(query string) error {
	if !strings.HasPrefix(strings.TrimSpace(query), "seriesByTag") {
		return t.wrapped.Execute(query)
	}

	t.isSeriesByTag = true

	w, err := t.makeWhere(query)
	if err != nil {
		return err
	}

	sql := fmt.Sprintf("SELECT Path FROM %s WHERE %s GROUP BY Path HAVING argMax(Deleted, Version)==0", t.table, w)
	t.body, err = clickhouse.Query(t.ctx, t.url, sql, t.timeout)
	return err
}

func (t *TaggedFinder) List() [][]byte {
	if !t.isSeriesByTag {
		return t.wrapped.List()
	}

	if t.body == nil {
		return [][]byte{}
	}

	rows := bytes.Split(t.body, []byte{'\n'})

	skip := 0
	for i := 0; i < len(rows); i++ {
		if len(rows[i]) == 0 {
			skip++
			continue
		}
		if skip > 0 {
			rows[i-skip] = rows[i]
		}
	}

	rows = rows[:len(rows)-skip]

	return rows
}

func (t *TaggedFinder) Series() [][]byte {
	if !t.isSeriesByTag {
		return t.wrapped.Series()
	}

	return t.List()
}

func (t *TaggedFinder) Abs(v []byte) []byte {
	if !t.isSeriesByTag {
		return t.wrapped.Abs(v)
	}

	u, err := url.Parse(string(v))
	if err != nil {
		return v
	}

	tags := make([]string, 0, len(u.Query()))
	for k, v := range u.Query() {
		tags = append(tags, fmt.Sprintf("%s=%s", k, v[0]))
	}

	sort.Strings(tags)
	if len(tags) == 0 {
		return []byte(u.Path)
	}

	return []byte(fmt.Sprintf("%s;%s", u.Path, strings.Join(tags, ";")))
}
<|endoftext|>


<commit_before>package main

import (
	"fmt"
	"os"
	"reflect"

	"github.com/ovn-org/libovsdb"
)

// Silly game that detects creation of Bridge named "stop" and exits
// Just a demonstration of how an app can use libovsdb library to configure and manage OVS
const (
	bridgeTable = "Bridge"
	ovsDb       = "Open_vSwitch"
	ovsTable    = ovsDb
)

var quit chan bool
var update chan *libovsdb.TableUpdates
var cache map[string]map[string]libovsdb.Row

func play(ovs *libovsdb.OvsdbClient) {
	go processInput(ovs)
	for currUpdate := range update {
		for table, tableUpdate := range currUpdate.Updates {
			if table == bridgeTable {
				for uuid, row := range tableUpdate.Rows {
					rowData, err := ovs.API.GetRowData(bridgeTable, &row.New)
					if err != nil {
						fmt.Println("ERROR getting Bridge Data", err)
					}
					if _, ok := rowData["name"]; ok {
						name := rowData["name"].(string)
						if name == "stop" {
							fmt.Println("Bridge stop detected : ", uuid)
							ovs.Disconnect()
							quit <- true
						}
					}
				}
			}
		}
	}
}

func createBridge(ovs *libovsdb.OvsdbClient, bridgeName string) {
	namedUUID := "gopher"
	// bridge row to insert
	bridge := make(map[string]interface{})
	bridge["name"] = bridgeName
	bridge["external_ids"] = map[string]string{"purpose": "fun"}

	brow, err := ovs.API.NewRow(bridgeTable, bridge)
	if err != nil {
		fmt.Printf("Row Error: %s", err.Error())
		os.Exit(1)

	}
	// simple insert operation
	insertOp := libovsdb.Operation{
		Op:       "insert",
		Table:    bridgeTable,
		Row:      brow,
		UUIDName: namedUUID,
	}

	// Inserting a Bridge row in Bridge table requires mutating the open_vswitch table.
	mutation, err := ovs.API.NewMutation(ovsTable, "bridges", "insert", []string{namedUUID})
	if err != nil {
		fmt.Printf("Mutation Error: %s", err.Error())
		os.Exit(1)
	}
	condition, err := ovs.API.NewCondition(ovsTable, "_uuid", "==", getRootUUID())
	if err != nil {
		fmt.Printf("Condition Error: %s", err.Error())
		os.Exit(1)
	}

	// simple mutate operation
	mutateOp := libovsdb.Operation{
		Op:        "mutate",
		Table:     "ovsTable",
		Mutations: []interface{}{mutation},
		Where:     []interface{}{condition},
	}

	operations := []libovsdb.Operation{insertOp, mutateOp}
	reply, _ := ovs.Transact(operations...)

	if len(reply) < len(operations) {
		fmt.Println("Number of Replies should be atleast equal to number of Operations")
	}
	ok := true
	for i, o := range reply {
		if o.Error != "" && i < len(operations) {
			fmt.Println("Transaction Failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i])
			ok = false
		} else if o.Error != "" {
			fmt.Println("Transaction Failed due to an error :", o.Error)
			ok = false
		}
	}
	if ok {
		fmt.Println("Bridge Addition Successful : ", reply[0].UUID.GoUUID)
	}
}

func processInput(ovs *libovsdb.OvsdbClient) {
	for {
		fmt.Printf("\n Enter a Bridge Name : ")
		var bridgeName string
		fmt.Scanf("%s", &bridgeName)
		createBridge(ovs, bridgeName)
	}
}

func getRootUUID() string {
	for uuid := range cache[ovsTable] {
		return uuid
	}
	return ""
}

func populateCache(updates libovsdb.TableUpdates) {
	for table, tableUpdate := range updates.Updates {
		if _, ok := cache[table]; !ok {
			cache[table] = make(map[string]libovsdb.Row)

		}
		for uuid, row := range tableUpdate.Rows {
			empty := libovsdb.Row{}
			if !reflect.DeepEqual(row.New, empty) {
				cache[table][uuid] = row.New
			} else {
				delete(cache[table], uuid)
			}
		}
	}
}

func main() {
	quit = make(chan bool)
	update = make(chan *libovsdb.TableUpdates)
	cache = make(map[string]map[string]libovsdb.Row)

	// By default libovsdb connects to 127.0.0.0:6400.
	ovs, err := libovsdb.Connect("tcp:", "Open_vSwitch", nil)

	// If you prefer to connect to OVS in a specific location :
	// ovs, err := libovsdb.Connect("tcp:192.168.56.101:6640", nil)

	if err != nil {
		fmt.Println("Unable to Connect ", err)
		os.Exit(1)
	}
	var notifier myNotifier
	ovs.Register(notifier)

	initial, _ := ovs.MonitorAll("")
	populateCache(*initial)

	fmt.Println(`Silly game of stopping this app when a Bridge with name "stop" is monitored !`)
	go play(ovs)
	<-quit
}

type myNotifier struct {
}

func (n myNotifier) Update(context interface{}, tableUpdates libovsdb.TableUpdates) {
	populateCache(tableUpdates)
	update <- &tableUpdates
}
func (n myNotifier) Locked([]interface{}) {
}
func (n myNotifier) Stolen([]interface{}) {
}
func (n myNotifier) Echo([]interface{}) {
}
func (n myNotifier) Disconnected() {
}
<commit_msg>play_with_ovs: Fix validation error<commit_after>package main

import (
	"fmt"
	"log"
	"reflect"

	"github.com/ovn-org/libovsdb"
)

// Silly game that detects creation of Bridge named "stop" and exits
// Just a demonstration of how an app can use libovsdb library to configure and manage OVS
const (
	bridgeTable = "Bridge"
	ovsDb       = "Open_vSwitch"
	ovsTable    = ovsDb
)

var quit chan bool
var update chan *libovsdb.TableUpdates
var cache map[string]map[string]libovsdb.Row

func play(ovs *libovsdb.OvsdbClient) {
	go processInput(ovs)
	for currUpdate := range update {
		for table, tableUpdate := range currUpdate.Updates {
			if table == bridgeTable {
				for uuid, row := range tableUpdate.Rows {
					rowData, err := ovs.API.GetRowData(bridgeTable, &row.New)
					if err != nil {
						fmt.Println("ERROR getting Bridge Data", err)
					}
					if _, ok := rowData["name"]; ok {
						name := rowData["name"].(string)
						if name == "stop" {
							fmt.Println("Bridge stop detected : ", uuid)
							ovs.Disconnect()
							quit <- true
						}
					}
				}
			}
		}
	}
}

func createBridge(ovs *libovsdb.OvsdbClient, bridgeName string) {
	namedUUID := "gopher"
	// bridge row to insert
	bridge := make(map[string]interface{})
	bridge["name"] = bridgeName
	bridge["external_ids"] = map[string]string{"purpose": "fun"}

	brow, err := ovs.API.NewRow(bridgeTable, bridge)
	if err != nil {
		log.Fatalf("Row Error: %s", err.Error())
	}
	// simple insert operation
	insertOp := libovsdb.Operation{
		Op:       "insert",
		Table:    bridgeTable,
		Row:      brow,
		UUIDName: namedUUID,
	}

	// Inserting a Bridge row in Bridge table requires mutating the open_vswitch table.
	mutation, err := ovs.API.NewMutation(ovsTable, "bridges", "insert", []string{namedUUID})
	if err != nil {
		log.Fatalf("Mutation Error: %s", err.Error())
	}
	condition, err := ovs.API.NewCondition(ovsTable, "_uuid", "==", getRootUUID())
	if err != nil {
		log.Fatalf("Condition Error: %s", err.Error())
	}

	// simple mutate operation
	mutateOp := libovsdb.Operation{
		Op:        "mutate",
		Table:     ovsTable,
		Mutations: []interface{}{mutation},
		Where:     []interface{}{condition},
	}

	operations := []libovsdb.Operation{insertOp, mutateOp}
	reply, err := ovs.Transact(operations...)
	if err != nil {
		log.Fatal(err)
	}

	if len(reply) < len(operations) {
		fmt.Println("Number of Replies should be atleast equal to number of Operations")
	}
	ok := true
	for i, o := range reply {
		if o.Error != "" && i < len(operations) {
			fmt.Println("Transaction Failed due to an error :", o.Error, " details:", o.Details, " in ", operations[i])
			ok = false
		} else if o.Error != "" {
			fmt.Println("Transaction Failed due to an error :", o.Error)
			ok = false
		}
	}
	if ok {
		fmt.Println("Bridge Addition Successful : ", reply[0].UUID.GoUUID)
	}
}

func processInput(ovs *libovsdb.OvsdbClient) {
	for {
		fmt.Printf("\n Enter a Bridge Name : ")
		var bridgeName string
		fmt.Scanf("%s", &bridgeName)
		createBridge(ovs, bridgeName)
	}
}

func getRootUUID() string {
	for uuid := range cache[ovsTable] {
		return uuid
	}
	return ""
}

func populateCache(updates libovsdb.TableUpdates) {
	for table, tableUpdate := range updates.Updates {
		if _, ok := cache[table]; !ok {
			cache[table] = make(map[string]libovsdb.Row)

		}
		for uuid, row := range tableUpdate.Rows {
			empty := libovsdb.Row{}
			if !reflect.DeepEqual(row.New, empty) {
				cache[table][uuid] = row.New
			} else {
				delete(cache[table], uuid)
			}
		}
	}
}

func main() {
	quit = make(chan bool)
	update = make(chan *libovsdb.TableUpdates)
	cache = make(map[string]map[string]libovsdb.Row)

	// By default libovsdb connects to 127.0.0.0:6400.
	ovs, err := libovsdb.Connect("tcp:", "Open_vSwitch", nil)

	// If you prefer to connect to OVS in a specific location :
	// ovs, err := libovsdb.Connect("tcp:192.168.56.101:6640", nil)

	if err != nil {
		log.Fatal("Unable to Connect ", err)
	}
	var notifier myNotifier
	ovs.Register(notifier)

	initial, _ := ovs.MonitorAll("")
	populateCache(*initial)

	fmt.Println(`Silly game of stopping this app when a Bridge with name "stop" is monitored !`)
	go play(ovs)
	<-quit
}

type myNotifier struct {
}

func (n myNotifier) Update(context interface{}, tableUpdates libovsdb.TableUpdates) {
	populateCache(tableUpdates)
	update <- &tableUpdates
}
func (n myNotifier) Locked([]interface{}) {
}
func (n myNotifier) Stolen([]interface{}) {
}
func (n myNotifier) Echo([]interface{}) {
}
func (n myNotifier) Disconnected() {
}
<|endoftext|>


<commit_before>// Copyright 2015 Hajime Hoshi
//
// 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 blocks

import (
	"fmt"
	"image/color"
	"strings"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/inpututil"
)

type GamepadScene struct {
	gamepadID         int
	currentIndex      int
	countAfterSetting int
	buttonStates      []string
}

func (s *GamepadScene) Update(state *GameState) error {
	if s.currentIndex == 0 {
		state.Input.gamepadConfig.Reset()
		state.Input.gamepadConfig.SetGamepadID(s.gamepadID)
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		state.Input.gamepadConfig.Reset()
		state.SceneManager.GoTo(&TitleScene{})
	}

	if s.buttonStates == nil {
		s.buttonStates = make([]string, len(virtualGamepadButtons))
	}
	for i, b := range virtualGamepadButtons {
		if i < s.currentIndex {
			s.buttonStates[i] = strings.ToUpper(state.Input.gamepadConfig.ButtonName(b))
			continue
		}
		if s.currentIndex == i {
			s.buttonStates[i] = "_"
			continue
		}
		s.buttonStates[i] = ""
	}

	if 0 < s.countAfterSetting {
		s.countAfterSetting--
		if s.countAfterSetting <= 0 {
			state.SceneManager.GoTo(&TitleScene{})
		}
		return nil
	}

	b := virtualGamepadButtons[s.currentIndex]
	if state.Input.gamepadConfig.Scan(b) {
		s.currentIndex++
		if s.currentIndex == len(virtualGamepadButtons) {
			s.countAfterSetting = ebiten.MaxTPS()
		}
	}
	return nil
}

func (s *GamepadScene) Draw(screen *ebiten.Image) {
	screen.Fill(color.Black)

	if s.buttonStates == nil {
		return
	}

	f := `GAMEPAD CONFIGURATION
(PRESS ESC TO CANCEL)

MOVE LEFT:    %s

MOVE RIGHT:   %s

DROP:         %s

ROTATE LEFT:  %s

ROTATE RIGHT: %s

%s`
	msg := ""
	if s.currentIndex == len(virtualGamepadButtons) {
		msg = "OK!"
	}
	str := fmt.Sprintf(f, s.buttonStates[0], s.buttonStates[1], s.buttonStates[2], s.buttonStates[3], s.buttonStates[4], msg)
	drawTextWithShadow(screen, str, 16, 16, 1, color.White)
}
<commit_msg>examples/blocks: Bug fix: ESC key caused crashing<commit_after>// Copyright 2015 Hajime Hoshi
//
// 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 blocks

import (
	"fmt"
	"image/color"
	"strings"

	"github.com/hajimehoshi/ebiten"
	"github.com/hajimehoshi/ebiten/inpututil"
)

type GamepadScene struct {
	gamepadID         int
	currentIndex      int
	countAfterSetting int
	buttonStates      []string
}

func (s *GamepadScene) Update(state *GameState) error {
	if s.currentIndex == 0 {
		state.Input.gamepadConfig.Reset()
		state.Input.gamepadConfig.SetGamepadID(s.gamepadID)
	}
	if inpututil.IsKeyJustPressed(ebiten.KeyEscape) {
		state.Input.gamepadConfig.Reset()
		state.SceneManager.GoTo(&TitleScene{})
		return nil
	}

	if s.buttonStates == nil {
		s.buttonStates = make([]string, len(virtualGamepadButtons))
	}
	for i, b := range virtualGamepadButtons {
		if i < s.currentIndex {
			s.buttonStates[i] = strings.ToUpper(state.Input.gamepadConfig.ButtonName(b))
			continue
		}
		if s.currentIndex == i {
			s.buttonStates[i] = "_"
			continue
		}
		s.buttonStates[i] = ""
	}

	if 0 < s.countAfterSetting {
		s.countAfterSetting--
		if s.countAfterSetting <= 0 {
			state.SceneManager.GoTo(&TitleScene{})
		}
		return nil
	}

	b := virtualGamepadButtons[s.currentIndex]
	if state.Input.gamepadConfig.Scan(b) {
		s.currentIndex++
		if s.currentIndex == len(virtualGamepadButtons) {
			s.countAfterSetting = ebiten.MaxTPS()
		}
	}
	return nil
}

func (s *GamepadScene) Draw(screen *ebiten.Image) {
	screen.Fill(color.Black)

	if s.buttonStates == nil {
		return
	}

	f := `GAMEPAD CONFIGURATION
(PRESS ESC TO CANCEL)

MOVE LEFT:    %s

MOVE RIGHT:   %s

DROP:         %s

ROTATE LEFT:  %s

ROTATE RIGHT: %s

%s`
	msg := ""
	if s.currentIndex == len(virtualGamepadButtons) {
		msg = "OK!"
	}
	str := fmt.Sprintf(f, s.buttonStates[0], s.buttonStates[1], s.buttonStates[2], s.buttonStates[3], s.buttonStates[4], msg)
	drawTextWithShadow(screen, str, 16, 16, 1, color.White)
}
<|endoftext|>