<commit_before>// Package stopwatch provides a timer that implements common stopwatch
// functionality.
package stopwatch

import (
	"fmt"
	"log"
	"strings"
	"time"
)

type Stopwatch struct {
	start, stop, lap time.Time
	laps             []time.Duration
}

// New creates a new Stopwatch. To start the stopwatch Start() should be invoked.
func New() *Stopwatch {
	return &Stopwatch{}
}

// Starts creates a new Stopwatch which starts immediately.
func Start() *Stopwatch {
	s := &Stopwatch{}
	s.init()
	return s
}

// After creates a new Stopwatch which starts after the given duration.
func After(t time.Duration) *Stopwatch {
	s := &Stopwatch{}
	time.AfterFunc(t, s.init)
	return s
}

func (s *Stopwatch) init() {
	s.start, s.lap = time.Now(), time.Now()
	s.laps = make([]time.Duration, 0)
}

func (s *Stopwatch) isStopped() bool {
	return s.stop.After(s.start)
}

func (s *Stopwatch) isResetted() bool {
	return s.start.IsZero()
}

// ElapsedTime returns the duration between the start and current time.
func (s *Stopwatch) ElapsedTime() time.Duration {
	if s.isStopped() {
		return s.stop.Sub(s.start)
	}

	if s.isResetted() {
		return time.Duration(0)
	}

	return time.Since(s.start)
}

// Print calls fmt.Printf() with the given string and the elapsed time attached.
// Useful to use with a defer statement.
// Example : defer Start().Print("myFunction")
// Output  :  myFunction - elapsed: 2.000629842s
func (s *Stopwatch) Print(msg string) {
	fmt.Printf("%s - elapsed: %s\n", msg, s.ElapsedTime().String())
}

// Log calls log.Printf() with the given string and the elapsed time attached.
// Useful to use with a defer statement.
// Example : defer Start().Log("myFunction")
// Output: 2014/02/10 00:44:56 myFunction - elapsed: 2.000169591s
func (s *Stopwatch) Log(msg string) {
	log.Printf("%s - elapsed: %s\n", msg, s.ElapsedTime().String())
}

// Stop stops the timer. To resume the timer Start() needs to be called again.
func (s *Stopwatch) Stop() {
	s.stop = time.Now()
}

// Start resumes or starts the timer. If a Stop() was invoked it resumes the
// timer. If a Reset() was invoked it starts a new session.
func (s *Stopwatch) Start() {
	if s.isResetted() {
		s.init()
	} else { //stopped
		s.start = s.start.Add(time.Since(s.stop))
	}
}

// Reset resets the timer. It needs to be started again with the Start() method.
func (s *Stopwatch) Reset() {
	s.start, s.stop, s.lap = time.Time{}, time.Time{}, time.Time{}
	s.laps = nil
}

// Lap takes and stores the current lap time and returns the elapsed time
// since the latest lap.
func (s *Stopwatch) Lap() time.Duration {
	// There is no lap if the timer is resetted or stoped
	if s.isStopped() || s.isResetted() {
		return time.Duration(0)
	}

	lap := time.Since(s.lap)
	s.lap = time.Now()
	s.laps = append(s.laps, lap)

	return lap
}

// Laps returns the list of all laps.
func (s *Stopwatch) Laps() []time.Duration {
	return s.laps
}

// String representation of a single Stopwatch instance.
func (s *Stopwatch) String() string {
	return fmt.Sprintf("[start: %s current: %s elapsed: %s]",
		s.start.Format(time.Stamp), time.Now().Format(time.Stamp), s.ElapsedTime())
}

// MarshalJSON implements the json.Marshaler interface. The elapsed time is
// quoted as a string and is in the form "72h3m0.5s". For more info please
// refer to time.Duration.String().
func (s *Stopwatch) MarshalJSON() ([]byte, error) {
	return []byte(`"` + s.ElapsedTime().String() + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The elapsed time
// is expected to be a string that can be successful parsed with
// time.ParseDuration.
func (s *Stopwatch) UnmarshalJSON(data []byte) (err error) {
	unquoted := strings.Replace(string(data), "\"", "", -1)
	d, err := time.ParseDuration(unquoted)
	if err != nil {
		return err
	}

	// set the start time based on the elapsed time
	s.start = time.Now().Add(-d)
	return nil
}
<commit_msg>Remove init(), no need for that<commit_after>// Package stopwatch provides a timer that implements common stopwatch
// functionality.
package stopwatch

import (
	"fmt"
	"log"
	"strings"
	"time"
)

type Stopwatch struct {
	start, stop, lap time.Time
	laps             []time.Duration
}

// New creates a new Stopwatch. To start the stopwatch Start() should be invoked.
func New() *Stopwatch {
	return &Stopwatch{}
}

// Starts creates a new Stopwatch which starts immediately.
func Start() *Stopwatch {
	s := &Stopwatch{
		start: time.Now(),
		lap:   time.Now(),
		laps:  make([]time.Duration, 0),
	}
	return s
}

// After creates a new Stopwatch which starts after the given duration.
func After(t time.Duration) *Stopwatch {
	s := &Stopwatch{}
	time.AfterFunc(t, s.Start)
	return s
}

func (s *Stopwatch) isStopped() bool {
	return s.stop.After(s.start)
}

func (s *Stopwatch) isResetted() bool {
	return s.start.IsZero()
}

// ElapsedTime returns the duration between the start and current time.
func (s *Stopwatch) ElapsedTime() time.Duration {
	if s.isStopped() {
		return s.stop.Sub(s.start)
	}

	if s.isResetted() {
		return time.Duration(0)
	}

	return time.Since(s.start)
}

// Print calls fmt.Printf() with the given string and the elapsed time attached.
// Useful to use with a defer statement.
// Example : defer Start().Print("myFunction")
// Output  :  myFunction - elapsed: 2.000629842s
func (s *Stopwatch) Print(msg string) {
	fmt.Printf("%s - elapsed: %s\n", msg, s.ElapsedTime().String())
}

// Log calls log.Printf() with the given string and the elapsed time attached.
// Useful to use with a defer statement.
// Example : defer Start().Log("myFunction")
// Output: 2014/02/10 00:44:56 myFunction - elapsed: 2.000169591s
func (s *Stopwatch) Log(msg string) {
	log.Printf("%s - elapsed: %s\n", msg, s.ElapsedTime().String())
}

// Stop stops the timer. To resume the timer Start() needs to be called again.
func (s *Stopwatch) Stop() {
	s.stop = time.Now()
}

// Start resumes or starts the timer. If a Stop() was invoked it resumes the
// timer. If a Reset() was invoked it starts a new session.
func (s *Stopwatch) Start() {
	if s.isResetted() {
		*s = *Start()
	} else { //stopped
		s.start = s.start.Add(time.Since(s.stop))
	}
}

// Reset resets the timer. It needs to be started again with the Start() method.
func (s *Stopwatch) Reset() {
	s.start, s.stop, s.lap = time.Time{}, time.Time{}, time.Time{}
	s.laps = nil
}

// Lap takes and stores the current lap time and returns the elapsed time
// since the latest lap.
func (s *Stopwatch) Lap() time.Duration {
	// There is no lap if the timer is resetted or stoped
	if s.isStopped() || s.isResetted() {
		return time.Duration(0)
	}

	lap := time.Since(s.lap)
	s.lap = time.Now()
	s.laps = append(s.laps, lap)

	return lap
}

// Laps returns the list of all laps.
func (s *Stopwatch) Laps() []time.Duration {
	return s.laps
}

// String representation of a single Stopwatch instance.
func (s *Stopwatch) String() string {
	return fmt.Sprintf("[start: %s current: %s elapsed: %s]",
		s.start.Format(time.Stamp), time.Now().Format(time.Stamp), s.ElapsedTime())
}

// MarshalJSON implements the json.Marshaler interface. The elapsed time is
// quoted as a string and is in the form "72h3m0.5s". For more info please
// refer to time.Duration.String().
func (s *Stopwatch) MarshalJSON() ([]byte, error) {
	return []byte(`"` + s.ElapsedTime().String() + `"`), nil
}

// UnmarshalJSON implements the json.Unmarshaler interface. The elapsed time
// is expected to be a string that can be successful parsed with
// time.ParseDuration.
func (s *Stopwatch) UnmarshalJSON(data []byte) (err error) {
	unquoted := strings.Replace(string(data), "\"", "", -1)
	d, err := time.ParseDuration(unquoted)
	if err != nil {
		return err
	}

	// set the start time based on the elapsed time
	s.start = time.Now().Add(-d)
	return nil
}
<|endoftext|>


<commit_before>/*
Copyright 2017 WALLIX

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 sync

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	gosync "sync"
	"time"

	"github.com/wallix/awless/aws"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/graph"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync/repo"
)

const fileExt = ".triples"

var DefaultSyncer Syncer

type Syncer interface {
	repo.Repo
	Sync(...cloud.Service) (map[string]*graph.Graph, error)
}

type syncer struct {
	repo.Repo
	logger *logger.Logger
}

func NewSyncer(l ...*logger.Logger) Syncer {
	repo, err := repo.New()
	if err != nil {
		panic(err)
	}

	s := &syncer{Repo: repo}

	if len(l) > 0 {
		s.logger = l[0]
	} else {
		s.logger = logger.DiscardLogger
	}

	return s
}

func (s *syncer) Sync(services ...cloud.Service) (map[string]*graph.Graph, error) {
	var workers gosync.WaitGroup

	type result struct {
		service cloud.Service
		gph     *graph.Graph
		start   time.Time
		err     error
	}

	resultc := make(chan *result, len(services))

	for _, service := range services {
		if service.IsSyncDisabled() {
			s.logger.Verbosef("sync: *disabled* for service %s", service.Name())
			continue
		}
		workers.Add(1)
		go func(srv cloud.Service) {
			defer workers.Done()
			start := time.Now()
			g, err := srv.FetchResources()
			resultc <- &result{service: srv, gph: g, start: start, err: err}
		}(service)
	}

	go func() {
		workers.Wait()
		close(resultc)
	}()

	var allErrors []error
	graphs := make(map[string]*graph.Graph)
	servicesByName := make(map[string]cloud.Service)
Loop:
	for {
		select {
		case res, ok := <-resultc:
			if !ok {
				break Loop
			}
			if res.err != nil {
				allErrors = append(allErrors, fmt.Errorf("syncing %s: %s", res.service.Name(), res.err))
			} else {
				logger.ExtraVerbosef("sync: fetched %s service took %s", res.service.Name(), time.Since(res.start))
			}
			if serv := res.service; serv != nil {
				servicesByName[serv.Name()] = serv
				if res.gph != nil {
					graphs[serv.Name()] = res.gph
				}
			}
		}
	}

	var filepaths []string

	for name, g := range graphs {
		filename := fmt.Sprintf("%s%s", name, fileExt)
		content, err := g.Marshal()
		if err != nil {
			allErrors = append(allErrors, fmt.Errorf("marshal %s: %s", filename, err))
		}

		serviceDir := filepath.Join(s.BaseDir(), servicesByName[name].Region())
		os.MkdirAll(serviceDir, 0700)

		writePath := filepath.Join(serviceDir, filename)
		if err = ioutil.WriteFile(writePath, content, 0600); err != nil {
			allErrors = append(allErrors, fmt.Errorf("writing %s: %s", writePath, err))
		}
		filepaths = append(filepaths, filepath.Join(servicesByName[name].Region(), filename))
	}

	if err := s.Commit(filepaths...); err != nil {
		allErrors = append(allErrors, fmt.Errorf("committing %s: %s", strings.Join(filepaths, ", "), err))
	}

	return graphs, concatErrors(allErrors)
}

func concatErrors(errs []error) error {
	if len(errs) == 0 {
		return nil
	}

	lines := []string{"syncing errors:"}
	for _, err := range errs {
		lines = append(lines, fmt.Sprintf("\t\t%s", err))
	}

	return errors.New(strings.Join(lines, "\n"))
}

func LoadLocalGraphForService(serviceName, region string) *graph.Graph {
	regionDir := region
	if aws.IsGlobalService(serviceName) {
		regionDir = "global"
	}
	path := filepath.Join(repo.BaseDir(), regionDir, fmt.Sprintf("%s%s", serviceName, fileExt))
	g, err := graph.NewGraphFromFile(path)
	if err != nil {
		return graph.NewGraph()
	}
	return g
}

func LoadLocalGraphs(region string) (*graph.Graph, error) {
	var files []string
	globalFiles, _ := filepath.Glob(filepath.Join(repo.BaseDir(), "global", fmt.Sprintf("*%s", fileExt)))
	regionFiles, _ := filepath.Glob(filepath.Join(repo.BaseDir(), region, fmt.Sprintf("*%s", fileExt)))

	files = append(files, globalFiles...)
	files = append(files, regionFiles...)

	g := graph.NewGraph()

	var readers []io.Reader
	for _, f := range files {
		reader, err := os.Open(f)
		if err != nil {
			return g, fmt.Errorf("loading '%s': %s", f, err)
		}
		readers = append(readers, reader)
	}

	err := g.UnmarshalMultiple(readers...)
	return g, err
}

func LoadAllLocalGraphs() (*graph.Graph, error) {
	path := filepath.Join(repo.BaseDir(), "*", fmt.Sprintf("*%s", fileExt))
	files, _ := filepath.Glob(path)

	g := graph.NewGraph()

	var readers []io.Reader
	for _, f := range files {
		reader, err := os.Open(f)
		if err != nil {
			return g, fmt.Errorf("loading '%s': %s", f, err)
		}
		readers = append(readers, reader)
	}

	err := g.UnmarshalMultiple(readers...)
	return g, err
}
<commit_msg>Fix #119 - Do not commit on sync when on Windows<commit_after>/*
Copyright 2017 WALLIX

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 sync

import (
	"errors"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	gosync "sync"
	"time"

	"runtime"

	"github.com/wallix/awless/aws"
	"github.com/wallix/awless/cloud"
	"github.com/wallix/awless/graph"
	"github.com/wallix/awless/logger"
	"github.com/wallix/awless/sync/repo"
)

const fileExt = ".triples"

var DefaultSyncer Syncer

type Syncer interface {
	repo.Repo
	Sync(...cloud.Service) (map[string]*graph.Graph, error)
}

type syncer struct {
	repo.Repo
	logger *logger.Logger
}

func NewSyncer(l ...*logger.Logger) Syncer {
	repo, err := repo.New()
	if err != nil {
		panic(err)
	}

	s := &syncer{Repo: repo}

	if len(l) > 0 {
		s.logger = l[0]
	} else {
		s.logger = logger.DiscardLogger
	}

	return s
}

func (s *syncer) Sync(services ...cloud.Service) (map[string]*graph.Graph, error) {
	var workers gosync.WaitGroup

	type result struct {
		service cloud.Service
		gph     *graph.Graph
		start   time.Time
		err     error
	}

	resultc := make(chan *result, len(services))

	for _, service := range services {
		if service.IsSyncDisabled() {
			s.logger.Verbosef("sync: *disabled* for service %s", service.Name())
			continue
		}
		workers.Add(1)
		go func(srv cloud.Service) {
			defer workers.Done()
			start := time.Now()
			g, err := srv.FetchResources()
			resultc <- &result{service: srv, gph: g, start: start, err: err}
		}(service)
	}

	go func() {
		workers.Wait()
		close(resultc)
	}()

	var allErrors []error
	graphs := make(map[string]*graph.Graph)
	servicesByName := make(map[string]cloud.Service)
Loop:
	for {
		select {
		case res, ok := <-resultc:
			if !ok {
				break Loop
			}
			if res.err != nil {
				allErrors = append(allErrors, fmt.Errorf("syncing %s: %s", res.service.Name(), res.err))
			} else {
				logger.ExtraVerbosef("sync: fetched %s service took %s", res.service.Name(), time.Since(res.start))
			}
			if serv := res.service; serv != nil {
				servicesByName[serv.Name()] = serv
				if res.gph != nil {
					graphs[serv.Name()] = res.gph
				}
			}
		}
	}

	var filepaths []string

	for name, g := range graphs {
		filename := fmt.Sprintf("%s%s", name, fileExt)
		content, err := g.Marshal()
		if err != nil {
			allErrors = append(allErrors, fmt.Errorf("marshal %s: %s", filename, err))
		}

		serviceDir := filepath.Join(s.BaseDir(), servicesByName[name].Region())
		os.MkdirAll(serviceDir, 0700)

		writePath := filepath.Join(serviceDir, filename)
		if err = ioutil.WriteFile(writePath, content, 0600); err != nil {
			allErrors = append(allErrors, fmt.Errorf("writing %s: %s", writePath, err))
		}
		filepaths = append(filepaths, filepath.Join(servicesByName[name].Region(), filename))
	}

	if runtime.GOOS != "windows" { // https://github.com/wallix/awless/issues/119
		if err := s.Commit(filepaths...); err != nil {
			allErrors = append(allErrors, fmt.Errorf("committing %s: %s", strings.Join(filepaths, ", "), err))
		}
	}

	return graphs, concatErrors(allErrors)
}

func concatErrors(errs []error) error {
	if len(errs) == 0 {
		return nil
	}

	lines := []string{"syncing errors:"}
	for _, err := range errs {
		lines = append(lines, fmt.Sprintf("\t\t%s", err))
	}

	return errors.New(strings.Join(lines, "\n"))
}

func LoadLocalGraphForService(serviceName, region string) *graph.Graph {
	regionDir := region
	if aws.IsGlobalService(serviceName) {
		regionDir = "global"
	}
	path := filepath.Join(repo.BaseDir(), regionDir, fmt.Sprintf("%s%s", serviceName, fileExt))
	g, err := graph.NewGraphFromFile(path)
	if err != nil {
		return graph.NewGraph()
	}
	return g
}

func LoadLocalGraphs(region string) (*graph.Graph, error) {
	var files []string
	globalFiles, _ := filepath.Glob(filepath.Join(repo.BaseDir(), "global", fmt.Sprintf("*%s", fileExt)))
	regionFiles, _ := filepath.Glob(filepath.Join(repo.BaseDir(), region, fmt.Sprintf("*%s", fileExt)))

	files = append(files, globalFiles...)
	files = append(files, regionFiles...)

	g := graph.NewGraph()

	var readers []io.Reader
	for _, f := range files {
		reader, err := os.Open(f)
		if err != nil {
			return g, fmt.Errorf("loading '%s': %s", f, err)
		}
		readers = append(readers, reader)
	}

	err := g.UnmarshalMultiple(readers...)
	return g, err
}

func LoadAllLocalGraphs() (*graph.Graph, error) {
	path := filepath.Join(repo.BaseDir(), "*", fmt.Sprintf("*%s", fileExt))
	files, _ := filepath.Glob(path)

	g := graph.NewGraph()

	var readers []io.Reader
	for _, f := range files {
		reader, err := os.Open(f)
		if err != nil {
			return g, fmt.Errorf("loading '%s': %s", f, err)
		}
		readers = append(readers, reader)
	}

	err := g.UnmarshalMultiple(readers...)
	return g, err
}
<|endoftext|>


<commit_before>package main

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

	restful "github.com/emicklei/go-restful"
	"github.com/rolevax/ih/mako"
	"github.com/rolevax/ih/teru/account"
	"github.com/rolevax/ih/teru/admin"
	"github.com/rolevax/ih/teru/my"
	"github.com/rolevax/ih/teru/task"
)

const (
	Port        = ":8080"
	CertPath    = "/srv/cert.pem"
	PrivKeyPath = "/srv/key.pem"
	DictPath    = "/srv/dict.txt"
)

type logWriter struct{}

func (w logWriter) Write(bytes []byte) (int, error) {
	prefix := time.Now().Format("01/02 15:04:05")
	return fmt.Print(prefix, " ", string(bytes))
}

func main() {
	log.SetFlags(0)
	log.SetOutput(&logWriter{})

	if flag.Parsed() {
		log.Fatalln("unexpected flag parse before main()")
	}

	redis := flag.String("redis", "localhost:6379", "redis server addr")
	db := flag.String("db", "localhost:5432", "pg db server addr")
	flag.Parse()
	mako.InitRedis(*redis)
	mako.InitDb(*db)
	hitomi.Init(DictPath)

	addWebService()
	supportCors()
	log.Fatal(http.ListenAndServeTLS(Port, CertPath, PrivKeyPath, nil))
}

func addWebService() {
	restful.Filter(globalLogging)
	addWebServiceAccount()
	addWebServiceAdmin()
	addWebServiceMy()
	addWebServiceTask()
}

func globalLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	log.Printf("%s %s %v\n", req.Request.Method, req.Request.URL, req.Request.RemoteAddr)
	chain.ProcessFilter(req, resp)
}

func addWebServiceAccount() {
	ws := &restful.WebService{}
	ws.
		Path("/account").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.POST("/auth").To(account.PostAuth))
	ws.Route(ws.POST("/create").To(account.PostCreate))

	ws.Route(ws.GET("/c-points").To(account.GetCPoints))

	restful.Add(ws)
}

func addWebServiceAdmin() {
	ws := &restful.WebService{}
	ws.
		Path("/admin").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.POST("/c-point").To(admin.PostCPoint))
	ws.Route(ws.POST("/upsert-task").To(admin.PostUpsertTask))
	ws.Route(ws.POST("/check-task").To(admin.PostCheckTask))

	restful.Add(ws)
}

func addWebServiceMy() {
	ws := &restful.WebService{}
	ws.
		Path("/my").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.GET("/null").Filter(account.FilterAuth).To(my.GetNull))

	restful.Add(ws)
}

func addWebServiceTask() {
	ws := &restful.WebService{}
	ws.
		Path("/task").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(
		ws.GET("/").
			To(task.GetRoot),
	)
	ws.Route(
		ws.GET("/{task-id}").
			To(task.GetTask),
	)
	ws.Route(
		ws.POST("/start/{task-id}").
			Filter(account.FilterAuth).
			To(task.PostStart),
	)
	ws.Route(
		ws.POST("/pr/{task-id}").
			Filter(account.FilterAuth).
			To(task.PostPr),
	)

	restful.Add(ws)
}

func supportCors() {
	cors := restful.CrossOriginResourceSharing{
		ExposeHeaders:  []string{"X-My-Header"},
		AllowedHeaders: []string{"Content-Type", "Accept", "Authorization"},
		AllowedMethods: []string{"GET", "POST"},
		CookiesAllowed: false,
		Container:      restful.DefaultContainer,
	}
	restful.Filter(cors.Filter)
	restful.Filter(restful.OPTIONSFilter())
}
<commit_msg>fix teru compile<commit_after>package main

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

	restful "github.com/emicklei/go-restful"
	"github.com/rolevax/ih/hitomi"
	"github.com/rolevax/ih/mako"
	"github.com/rolevax/ih/teru/account"
	"github.com/rolevax/ih/teru/admin"
	"github.com/rolevax/ih/teru/my"
	"github.com/rolevax/ih/teru/task"
)

const (
	Port        = ":8080"
	CertPath    = "/srv/cert.pem"
	PrivKeyPath = "/srv/key.pem"
	DictPath    = "/srv/dict.txt"
)

type logWriter struct{}

func (w logWriter) Write(bytes []byte) (int, error) {
	prefix := time.Now().Format("01/02 15:04:05")
	return fmt.Print(prefix, " ", string(bytes))
}

func main() {
	log.SetFlags(0)
	log.SetOutput(&logWriter{})

	if flag.Parsed() {
		log.Fatalln("unexpected flag parse before main()")
	}

	redis := flag.String("redis", "localhost:6379", "redis server addr")
	db := flag.String("db", "localhost:5432", "pg db server addr")
	flag.Parse()
	mako.InitRedis(*redis)
	mako.InitDb(*db)
	hitomi.Init(DictPath)

	addWebService()
	supportCors()
	log.Fatal(http.ListenAndServeTLS(Port, CertPath, PrivKeyPath, nil))
}

func addWebService() {
	restful.Filter(globalLogging)
	addWebServiceAccount()
	addWebServiceAdmin()
	addWebServiceMy()
	addWebServiceTask()
}

func globalLogging(req *restful.Request, resp *restful.Response, chain *restful.FilterChain) {
	log.Printf("%s %s %v\n", req.Request.Method, req.Request.URL, req.Request.RemoteAddr)
	chain.ProcessFilter(req, resp)
}

func addWebServiceAccount() {
	ws := &restful.WebService{}
	ws.
		Path("/account").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.POST("/auth").To(account.PostAuth))
	ws.Route(ws.POST("/create").To(account.PostCreate))

	ws.Route(ws.GET("/c-points").To(account.GetCPoints))

	restful.Add(ws)
}

func addWebServiceAdmin() {
	ws := &restful.WebService{}
	ws.
		Path("/admin").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.POST("/c-point").To(admin.PostCPoint))
	ws.Route(ws.POST("/upsert-task").To(admin.PostUpsertTask))
	ws.Route(ws.POST("/check-task").To(admin.PostCheckTask))

	restful.Add(ws)
}

func addWebServiceMy() {
	ws := &restful.WebService{}
	ws.
		Path("/my").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(ws.GET("/null").Filter(account.FilterAuth).To(my.GetNull))

	restful.Add(ws)
}

func addWebServiceTask() {
	ws := &restful.WebService{}
	ws.
		Path("/task").
		Consumes(restful.MIME_JSON).
		Produces(restful.MIME_JSON)

	ws.Route(
		ws.GET("/").
			To(task.GetRoot),
	)
	ws.Route(
		ws.GET("/{task-id}").
			To(task.GetTask),
	)
	ws.Route(
		ws.POST("/start/{task-id}").
			Filter(account.FilterAuth).
			To(task.PostStart),
	)
	ws.Route(
		ws.POST("/pr/{task-id}").
			Filter(account.FilterAuth).
			To(task.PostPr),
	)

	restful.Add(ws)
}

func supportCors() {
	cors := restful.CrossOriginResourceSharing{
		ExposeHeaders:  []string{"X-My-Header"},
		AllowedHeaders: []string{"Content-Type", "Accept", "Authorization"},
		AllowedMethods: []string{"GET", "POST"},
		CookiesAllowed: false,
		Container:      restful.DefaultContainer,
	}
	restful.Filter(cors.Filter)
	restful.Filter(restful.OPTIONSFilter())
}
<|endoftext|>


<commit_before>package main

func a(c int) int {
	return 3
}

func b() int {
	return 0
}

func c(a,b int) int {
	return 1
}

func main() {
	x := a(1)
	y := b()
	z := c(a(b()), b())

	a(c(b(), b()))
}
<commit_msg>improve test, formatting'<commit_after>package main

func a(c int) int {
	return 3
}

func b() int {
	return 0
}

func c(a, b int) int {
	return 1
}

func main() {
	var (
		q int
		t string
	)
	x := a(1)
	y := b()
	z := c(a(q), b())

	a(c(b(), b()))
}
<|endoftext|>


<commit_before>package jq

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/jingweno/jqpipe-go"
)

const jqExecTimeout = 5

var Path, Version string

func init() {
	var err error

	Path, err = setupJQPath()
	if err != nil {
		log.Fatal(err)
	}

	Version, err = jqVersion()
	if err != nil {
		log.Fatal(err)
	}
}

func setupJQPath() (string, error) {
	pwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	jqPath := filepath.Join(pwd, "bin", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Setenv("PATH", fmt.Sprintf("%s%c%s", jqPath, os.PathListSeparator, os.Getenv("PATH")))

	return filepath.Join(jqPath, "jq"), nil
}

func jqVersion() (string, error) {
	// get version from `jq --help`
	// since `jq --version` diffs between versions
	// e.g., 1.3 & 1.4
	var b bytes.Buffer
	cmd := exec.Command(Path, "--help")
	cmd.Stdout = &b
	cmd.Stderr = &b
	cmd.Run()

	out := bytes.TrimSpace(b.Bytes())
	r := regexp.MustCompile(`\[version (.+)\]`)
	if r.Match(out) {
		m := r.FindSubmatch(out)[1]
		return string(m), nil
	}

	return "", fmt.Errorf("can't find jq version: %s", out)
}

type jqResult struct {
	Seq []json.RawMessage
	Err error
}

func (r *jqResult) Result() (string, error) {
	if r.Err != nil {
		return "", r.Err
	}

	result := []string{}
	for _, s := range r.Seq {
		ss := string(s)
		if ss != "" && ss != "null" {
			result = append(result, ss)
		}
	}

	return strings.Join(result, "\n"), nil
}

type JQ struct {
	J string          `json:"j"`
	Q string          `json:"q"`
	O map[string]bool `json:"o"`
}

func (j *JQ) Opts() []string {
	opts := []string{}
	for opt, enabled := range j.O {
		if enabled {
			opts = append(opts, fmt.Sprintf("--%s", opt))
		}
	}

	return opts
}

// eval `jq` expression with timeout support
func (j *JQ) Eval() (string, error) {
	resultCh := make(chan jqResult, 1)
	go func(js, expr string, opts ...string) {
		seq, err := eval(js, expr, opts...)
		resultCh <- jqResult{seq, err}
	}(j.J, j.Q, j.Opts()...)

	select {
	case r := <-resultCh:
		return r.Result()
	case <-time.After(time.Second * jqExecTimeout):
		return "", fmt.Errorf("jq execution timeout")
	}
}

func (j *JQ) Validate() error {
	errMsgs := []string{}

	if j.Q == "" {
		errMsgs = append(errMsgs, "missing filter")
	}

	if j.J == "" {
		errMsgs = append(errMsgs, "missing JSON")
	}

	if len(errMsgs) > 0 {
		return fmt.Errorf("invalid input: %s", strings.Join(errMsgs, " and "))
	}

	return nil
}

func (j JQ) String() string {
	return fmt.Sprintf("j=%s, q=%s, o=%v", j.J, j.Q, j.Opts())
}

// eval `jq` expression
func eval(js string, expr string, opts ...string) ([]json.RawMessage, error) {
	jq, err := jq.New(bytes.NewReader([]byte(js)), expr, opts...)
	if err != nil {
		return nil, err
	}

	ret := make([]json.RawMessage, 0, 16)
	for {
		next, err := jq.Next()
		switch err {
		case nil:
			ret = append(ret, next)
		case io.EOF:
			return ret, nil
		default:
			return ret, err
		}
	}
}
<commit_msg>Log jq timeout<commit_after>package jq

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"runtime"
	"strings"
	"time"

	"github.com/jingweno/jqpipe-go"
)

const jqExecTimeout = 5

var Path, Version string

func init() {
	var err error

	Path, err = setupJQPath()
	if err != nil {
		log.Fatal(err)
	}

	Version, err = jqVersion()
	if err != nil {
		log.Fatal(err)
	}
}

func setupJQPath() (string, error) {
	pwd, err := os.Getwd()
	if err != nil {
		return "", err
	}

	jqPath := filepath.Join(pwd, "bin", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH))
	os.Setenv("PATH", fmt.Sprintf("%s%c%s", jqPath, os.PathListSeparator, os.Getenv("PATH")))

	return filepath.Join(jqPath, "jq"), nil
}

func jqVersion() (string, error) {
	// get version from `jq --help`
	// since `jq --version` diffs between versions
	// e.g., 1.3 & 1.4
	var b bytes.Buffer
	cmd := exec.Command(Path, "--help")
	cmd.Stdout = &b
	cmd.Stderr = &b
	cmd.Run()

	out := bytes.TrimSpace(b.Bytes())
	r := regexp.MustCompile(`\[version (.+)\]`)
	if r.Match(out) {
		m := r.FindSubmatch(out)[1]
		return string(m), nil
	}

	return "", fmt.Errorf("can't find jq version: %s", out)
}

type jqResult struct {
	Seq []json.RawMessage
	Err error
}

func (r *jqResult) Result() (string, error) {
	if r.Err != nil {
		return "", r.Err
	}

	result := []string{}
	for _, s := range r.Seq {
		ss := string(s)
		if ss != "" && ss != "null" {
			result = append(result, ss)
		}
	}

	return strings.Join(result, "\n"), nil
}

type JQ struct {
	J string          `json:"j"`
	Q string          `json:"q"`
	O map[string]bool `json:"o"`
}

func (j *JQ) Opts() []string {
	opts := []string{}
	for opt, enabled := range j.O {
		if enabled {
			opts = append(opts, fmt.Sprintf("--%s", opt))
		}
	}

	return opts
}

// eval `jq` expression with timeout support
func (j *JQ) Eval() (string, error) {
	resultCh := make(chan jqResult, 1)
	go func(js, expr string, opts ...string) {
		seq, err := eval(js, expr, opts...)
		resultCh <- jqResult{seq, err}
	}(j.J, j.Q, j.Opts()...)

	select {
	case r := <-resultCh:
		return r.Result()
	case <-time.After(time.Second * jqExecTimeout):
		log.Printf("Error: JQ timeout - j=%s, q=%s, o=%v\n", j.J, j.Q, j.O)
		return "", fmt.Errorf("jq execution timeout")
	}
}

func (j *JQ) Validate() error {
	errMsgs := []string{}

	if j.Q == "" {
		errMsgs = append(errMsgs, "missing filter")
	}

	if j.J == "" {
		errMsgs = append(errMsgs, "missing JSON")
	}

	if len(errMsgs) > 0 {
		return fmt.Errorf("invalid input: %s", strings.Join(errMsgs, " and "))
	}

	return nil
}

func (j JQ) String() string {
	return fmt.Sprintf("j=%s, q=%s, o=%v", j.J, j.Q, j.Opts())
}

// eval `jq` expression
func eval(js string, expr string, opts ...string) ([]json.RawMessage, error) {
	jq, err := jq.New(bytes.NewReader([]byte(js)), expr, opts...)
	if err != nil {
		return nil, err
	}

	ret := make([]json.RawMessage, 0, 16)
	for {
		next, err := jq.Next()
		switch err {
		case nil:
			ret = append(ret, next)
		case io.EOF:
			return ret, nil
		default:
			return ret, err
		}
	}
}
<|endoftext|>


<commit_before>package main

import (
	"crypto/rsa"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/leonlee/jrdwp/client"
	"github.com/leonlee/jrdwp/common"
	"github.com/leonlee/jrdwp/server"
)

const (
	//ModeClient client mode
	ModeClient = "client"
	//ModeServer server mode
	ModeServer = "server"
	//PortListen default port of tcp server on client or ws server on remote server
	PortListen = 9876
	//PortServer default port of ws server on client
	PortServer = 9877
	//WsPath default websocket server path
	WsPath = "jrdwp"
	//DefaultJdwpPorts default enabled ports
	DefaultJdwpPorts = "5005"
	//DefaultServerDeadline deadline of jrdwp server in minutes, to reduce risks it will shutdown
	//on deadline automatically
	DefaultServerDeadline = 60
)

//Config configuration struct
type Config struct {
	Mode             *string        `json:"mode"`
	BindHost         *string        `json:"bindHost"`
	BindPort         *int           `json:"bindPort"`
	ServerHost       *string        `json:"serverHost"`
	ServerPort       *int           `json:"serverPort"`
	WsPath           *string        `json:"wsPath"`
	WsOrigin         *string        `json:"wsOrigin"`
	AllowedJdwpPorts []int          `json:"allowedJdwpPorts"`
	JdwpPort         *int           `json:"jdwpPort"`
	ServerDeadline   *int           `json:"serverDeadline"`
	PublicKey        *rsa.PublicKey `json:"clientKey"`
}

func (conf *Config) String() string {
	confJSON, err := json.Marshal(*conf)
	if err != nil {
		return err.Error()
	}
	return string(confJSON)
}

func main() {
	conf := parseFlags()
	start(conf)
}

func parseFlags() *Config {
	log.Printf("initializing with %v ...", flag.Args())

	conf := &Config{}
	conf.Mode = flag.String("mode", ModeClient, "jrdwp mode, \"client\" or \"server\"")
	conf.BindHost = flag.String("bind-host", "", "bind host, default \"\"")
	conf.BindPort = flag.Int("bind-port", PortListen, "bind port, default 9876")
	conf.ServerHost = flag.String("server-host", "", "server host")
	conf.ServerPort = flag.Int("server-port", PortServer, "server port, default 9877")
	conf.WsPath = flag.String("ws-path", WsPath, "websocket server path, default \"/jrdwp\"")
	conf.WsOrigin = flag.String("ws-origin", "", "websocket request origin header, default \"\"")
	conf.JdwpPort = flag.Int("jdwp-port", -1, "jdwp port of remote application, mandatory")
	conf.ServerDeadline = flag.Int("server-deadline", DefaultServerDeadline, "server deadline in minutes that server will shutdown on deadline, default 60 minutes")
	jdwpPortsText := flag.String("allowed-jdwp-ports", "", "allowed jdwp ports likes: \"5005,5006\", mandatory")
	flag.Parse()

	if *conf.Mode == ModeServer {
		conf.AllowedJdwpPorts = common.SplitToInt(*jdwpPortsText)
	}

	if *conf.WsPath == "" {
		log.Fatal("invalid ws-path")
	}

	if *conf.WsOrigin == "" {
		log.Fatal("invalid ws-origin")
	}

	log.Printf("initialized by %s \n", conf)

	return conf
}

func start(conf *Config) {
	log.Println("starting jrdwp...")

	switch *conf.Mode {
	case ModeClient:
		startClient(conf)
	case ModeServer:
		startServer(conf)
	default:
		log.Fatalf("bad mode %s\n", *conf.Mode)
	}

	log.Printf("jrdwp started in %v mode\n", conf.Mode)
}

func startClient(conf *Config) {
	loadKey(conf)

	wsClient := client.NewWSClient(
		*conf.ServerHost,
		*conf.ServerPort,
		*conf.WsPath,
		*conf.WsOrigin,
		*conf.JdwpPort,
		conf.PublicKey)

	tcpServer := client.NewTCPServer(wsClient, *conf.BindPort)
	if err := tcpServer.Start(); err != nil {
		log.Fatalln("can't start tcp server", err.Error())
	}
}

func startServer(conf *Config) {
	tcpClient := server.NewTCPClient(*conf.ServerHost)
	wsServer := server.NewWSServer(*conf.WsPath,
		*conf.WsOrigin,
		*conf.BindPort,
		conf.AllowedJdwpPorts,
		tcpClient)

	startDeadlineTimer(*conf.ServerDeadline)
	wsServer.Start()
}

func startDeadlineTimer(deadline int) {
	time.AfterFunc(time.Duration(deadline)*time.Minute, func() {
		goodbye := `
 _________________________________________
< Bug's life was short, long live Gopher! >
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
`
		log.Fatalln(goodbye)
	})
}

func loadKey(conf *Config) {
	bytes, err := ioutil.ReadFile(common.PublicKeyPath())
	if err != nil {
		log.Fatalln("Can't read public key", err.Error())
	}

	conf.PublicKey, err = common.ParsePublicKey(bytes)
	if err != nil {
		log.Fatalln("can't parse public key", err.Error())
	}
}
<commit_msg>Added scheme flag<commit_after>package main

import (
	"crypto/rsa"
	"encoding/json"
	"flag"
	"io/ioutil"
	"log"
	"time"

	"github.com/leonlee/jrdwp/client"
	"github.com/leonlee/jrdwp/common"
	"github.com/leonlee/jrdwp/server"
)

const (
	//ModeClient client mode
	ModeClient = "client"
	//ModeServer server mode
	ModeServer = "server"
	//PortListen default port of tcp server on client or ws server on remote server
	PortListen = 9876
	//PortServer default port of ws server on client
	PortServer = 9877
	//WsPath default websocket server path
	WsPath = "jrdwp"
	//DefaultJdwpPorts default enabled ports
	DefaultJdwpPorts = "5005"
	//DefaultServerDeadline deadline of jrdwp server in minutes, to reduce risks it will shutdown
	//on deadline automatically
	DefaultServerDeadline = 60
)

//Config configuration struct
type Config struct {
	Mode             *string        `json:"mode"`
	BindHost         *string        `json:"bindHost"`
	BindPort         *int           `json:"bindPort"`
	ServerHost       *string        `json:"serverHost"`
	ServerPort       *int           `json:"serverPort"`
	WsPath           *string        `json:"wsPath"`
	WsOrigin         *string        `json:"wsOrigin"`
	AllowedJdwpPorts []int          `json:"allowedJdwpPorts"`
	JdwpPort         *int           `json:"jdwpPort"`
	ServerDeadline   *int           `json:"serverDeadline"`
	Scheme           *string          `json:"scheme"`
	PublicKey        *rsa.PublicKey `json:"clientKey"`
}

func (conf *Config) String() string {
	confJSON, err := json.Marshal(*conf)
	if err != nil {
		return err.Error()
	}
	return string(confJSON)
}

func main() {
	conf := parseFlags()
	start(conf)
}

func parseFlags() *Config {
	log.Printf("initializing with %v ...", flag.Args())

	conf := &Config{}
	conf.Mode = flag.String("mode", ModeClient, "jrdwp mode, \"client\" or \"server\"")
	conf.BindHost = flag.String("bind-host", "", "bind host, default \"\"")
	conf.BindPort = flag.Int("bind-port", PortListen, "bind port, default 9876")
	conf.ServerHost = flag.String("server-host", "", "server host")
	conf.ServerPort = flag.Int("server-port", PortServer, "server port, default 9877")
	conf.WsPath = flag.String("ws-path", WsPath, "websocket server path, default \"/jrdwp\"")
	conf.WsOrigin = flag.String("ws-origin", "", "websocket request origin header, default \"\"")
	conf.JdwpPort = flag.Int("jdwp-port", -1, "jdwp port of remote application, mandatory")
	conf.ServerDeadline = flag.Int("server-deadline", DefaultServerDeadline, "server deadline in minutes that server will shutdown on deadline, default 60 minutes")
        conf.Scheme = flag.String("scheme", "ws", "Scheme, ws or wss, default ws")
	jdwpPortsText := flag.String("allowed-jdwp-ports", "", "allowed jdwp ports likes: \"5005,5006\", mandatory")
	flag.Parse()

	if *conf.Mode == ModeServer {
		conf.AllowedJdwpPorts = common.SplitToInt(*jdwpPortsText)
	}

	if *conf.WsPath == "" {
		log.Fatal("invalid ws-path")
	}

	if *conf.WsOrigin == "" {
		log.Fatal("invalid ws-origin")
	}

	log.Printf("initialized by %s \n", conf)

	return conf
}

func start(conf *Config) {
	log.Println("starting jrdwp...")

	switch *conf.Mode {
	case ModeClient:
		startClient(conf)
	case ModeServer:
		startServer(conf)
	default:
		log.Fatalf("bad mode %s\n", *conf.Mode)
	}

	log.Printf("jrdwp started in %v mode\n", conf.Mode)
}

func startClient(conf *Config) {
	loadKey(conf)

	wsClient := client.NewWSClient(
		*conf.ServerHost,
		*conf.ServerPort,
		*conf.WsPath,
		*conf.WsOrigin,
		*conf.JdwpPort,
                *conf.Scheme,
		conf.PublicKey)

	tcpServer := client.NewTCPServer(wsClient, *conf.BindPort)
	if err := tcpServer.Start(); err != nil {
		log.Fatalln("can't start tcp server", err.Error())
	}
}

func startServer(conf *Config) {
	tcpClient := server.NewTCPClient(*conf.ServerHost)
	wsServer := server.NewWSServer(*conf.WsPath,
		*conf.WsOrigin,
		*conf.BindPort,
		conf.AllowedJdwpPorts,
		tcpClient)

	startDeadlineTimer(*conf.ServerDeadline)
	wsServer.Start()
}

func startDeadlineTimer(deadline int) {
	time.AfterFunc(time.Duration(deadline)*time.Minute, func() {
		goodbye := `
 _________________________________________
< Bug's life was short, long live Gopher! >
 -----------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
`
		log.Fatalln(goodbye)
	})
}

func loadKey(conf *Config) {
	bytes, err := ioutil.ReadFile(common.PublicKeyPath())
	if err != nil {
		log.Fatalln("Can't read public key", err.Error())
	}

	conf.PublicKey, err = common.ParsePublicKey(bytes)
	if err != nil {
		log.Fatalln("can't parse public key", err.Error())
	}
}
<|endoftext|>


<commit_before>package ip

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
	"time"

	"github.com/toorop/govh"
)

// Client is a REST client for server API
type Client struct {
	*govh.OVHClient
}

// New return a new server Client
func New(client *govh.OVHClient) (*Client, error) {
	if client == nil {
		return nil, errors.New("client is nil")
	}
	return &Client{client}, nil
}

// List return a slice of IpBlock
func (c *Client) List(filterDesc, filterIP, filterRoutedTo, filterType string) (ips []IPBlock, err error) {
	uri := "ip"
	args := []string{}

	if len(filterDesc) > 0 {
		args = append(args, "description="+url.QueryEscape(filterDesc))
	}
	if len(filterIP) > 0 {
		args = append(args, "ip="+url.QueryEscape(filterIP))
	}
	if len(filterRoutedTo) > 0 {
		args = append(args, "routedTo.serviceName="+url.QueryEscape(filterRoutedTo))
	}
	if len(filterType) > 0 {
		args = append(args, "type="+url.QueryEscape(filterType))
	}

	if len(args) > 0 {
		uri = uri + "?" + strings.Join(args, "&")
	}
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	var ipl = []string{}
	if err = json.Unmarshal(r.Body, &ipl); err == nil {
		for _, i := range ipl {
			ips = append(ips, IPBlock{i, filterType})
		}
	}
	return
}

// GetIPProperties return properties of an IP
func (c *Client) GetIPProperties(IP string) (properties IPProperties, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(IP))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &properties)
	return
}

// UpdateProperties update IP properties
func (c *Client) UpdateProperties(IP, desc string) error {
	payload, err := json.Marshal(IpUpdatableProperties{
		Description: desc,
	})
	if err != nil {
		return err
	}
	r, err := c.PUT("ip/"+url.QueryEscape(IP), string(payload))
	err = r.HandleErr(err, []int{200})
	return err
}

/*
//
//// LOADBALANCING
//

// List IP load balancing
func (r *Client) LbList() (resp []byte, err error) {
	resp, err = r.client.Do("GET", "ip/loadBalancing", "")
	return
}*/

//
//// FIREWALL
//

// FwListIPOfBlock List IP of block IP under firewall protection
func (c *Client) FwListIPOfBlock(block IPBlock) (IPs []string, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall")
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IPs)
	return
}

// FwAddIP Add IP to firewall
func (c *Client) FwAddIP(block IPBlock, IPv4 string) error {
	type p struct {
		IPOnFirewall string `json:"ipOnFirewall"`
	}
	payload, err := json.Marshal(p{IPv4})
	if err != nil {
		return err
	}
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/firewall", string(payload))
	return r.HandleErr(err, []int{200})
}

// FwRemoveIP Remove IP from firewall
func (c *Client) FwRemoveIP(block IPBlock, IPv4 string) error {
	r, err := c.DELETE("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4))
	return r.HandleErr(err, []int{200})
}

// FwGetIPProperties Get properties about an IP firewalled
func (c *Client) FwGetIPProperties(block IPBlock, IPv4 string) (IP FirewalledIp, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IP)
	return
}

// FwUpdateIP  update properties of an IP on firewall
func (c *Client) FwUpdateIP(block IPBlock, IPv4 string, enabled bool) error {
	var err error
	var payload []byte
	type p struct {
		Enabled bool `json:"enabled"`
	}
	if payload, err = json.Marshal(p{enabled}); err != nil {
		return err
	}
	r, err := c.PUT("ip/"+url.QueryEscape(block.IP)+"/firewall/"+url.QueryEscape(IPv4), string(payload))
	return r.HandleErr(err, []int{200})
}

// FwAddRule adds a firewall rule
func (c *Client) FwAddRule(block IPBlock, IPv4 string, rule FwRule2Add) error {
	payload, err := json.Marshal(rule)
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/firewall/"+url.QueryEscape(IPv4)+"/rule", string(payload))
	return r.HandleErr(err, []int{200})
}

// FwListRules return rules sequences
func (c *Client) FwListRules(block IPBlock, IPv4 string, state ...string) (sequences []int, err error) {
	uri := fmt.Sprintf("ip/%s/firewall/%s/rule", url.QueryEscape(block.IP), url.QueryEscape(IPv4))
	if len(state) > 0 {
		if !(state[0] == "creationPending" || state[0] == "ok" || state[0] == "removalPending") {
			err = errors.New("Bad parameter state (creationPending|ok|removalPending)")
			return
		}
		uri = uri + "?state=" + url.QueryEscape(state[0])
	}
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &sequences)
	return
}

// FwGetRuleProperties returns rule Properties
func (c *Client) FwGetRuleProperties(block IPBlock, IPv4 string, sequence int) (rule FirewallRule, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4) + "/rule/" + url.QueryEscape(fmt.Sprintf("%d", sequence)))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &rule)
	return
}

//FwRemoveRule removes a rule
func (c *Client) FwRemoveRule(block IPBlock, IPv4 string, sequence int) error {
	r, err := c.DELETE("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4) + "/rule/" + url.QueryEscape(fmt.Sprintf("%d", sequence)))
	return r.HandleErr(err, []int{200})
}

//
// SPAM
//

// SpamGetSpammingIps returns Spamming IP
// state :
// 		* blockedForSpam : currently blocked
// 		* unblocking : in the way to be unblocked (or not)
// 		* unblocked : blocked in the past
//
func (c *Client) SpamGetSpammingIPs(block IPBlock, state string) (IPs []string, err error) {
	uri := fmt.Sprintf("ip/%s/spam", url.QueryEscape(block.IP))
	if state == "blockedForSpam" || state == "unblocking" || state == "unblocked" {
		uri = fmt.Sprintf("%s?state=%s", uri, state)
	}
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IPs)
	return
}

// SpamGetIP returns detailed info about a spamming IP
func (c *Client) SpamGetIP(block IPBlock, IPv4 string) (spamIP *SpamIP, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/spam/" + url.QueryEscape(IPv4))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &spamIP)
	return
}

// SpamGetIPStats returns stats about a spamming IP
func (c *Client) SpamGetIPStats(block IPBlock, IPv4 string, from time.Time, to time.Time) (spamStats *SpamStats, err error) {
	uri := fmt.Sprintf("ip/%s/spam/%s/stats?from=%s&to=%s", url.QueryEscape(block.IP), IPv4, url.QueryEscape(from.Format(time.RFC3339)), url.QueryEscape(to.Format(time.RFC3339)))
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	if len(r.Body) > 2 {
		err = json.Unmarshal(r.Body[1:len(r.Body)-1], &spamStats)
	}
	return
}

//SpamUnblockSpamIP Unblocks a spamming IP
func (c *Client) SpamUnblockSpamIP(block IPBlock, IPv4 string) error {
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/spam/"+url.QueryEscape(IPv4)+"/unblock", "")
	return r.HandleErr(err, []int{200})
}

// GetBlockedForSpam returns IPs which are currently blocked for spam
func (c *Client) GetBlockedForSpam() (IPs []string, err error) {
	IPBlocks, err := c.List("", "", "", "")
	if err != nil {
		return
	}
	for _, IPb := range IPBlocks {
		// remove IPv6
		if len(strings.Split(IPb.IP, ":")) > 1 {
			continue
		}
		IPsBlocked, err := c.SpamGetSpammingIPs(IPb, "blockedForSpam")
		if err != nil {
			// Not all IP are concerned by spamming status, if not found continue
			if strings.HasPrefix(err.Error(), "404 This service does not exist") {
				continue
			} else if strings.HasPrefix(err.Error(), "460 This Service is expired") {
				continue
			}
			return IPs, err
		}
		if len(IPsBlocked) > 0 {
			for _, IP := range IPsBlocked {
				IPs = append(IPs, IP)
			}
		}
	}
	return
}
<commit_msg>IP reverse<commit_after>package ip

import (
	"encoding/json"
	"errors"
	"fmt"
	"net/url"
	"strings"
	"time"

	"github.com/toorop/govh"
)

// Client is a REST client for server API
type Client struct {
	*govh.OVHClient
}

// New return a new server Client
func New(client *govh.OVHClient) (*Client, error) {
	if client == nil {
		return nil, errors.New("client is nil")
	}
	return &Client{client}, nil
}

// List return a slice of IpBlock
func (c *Client) List(filterDesc, filterIP, filterRoutedTo, filterType string) (ips []IPBlock, err error) {
	uri := "ip"
	args := []string{}

	if len(filterDesc) > 0 {
		args = append(args, "description="+url.QueryEscape(filterDesc))
	}
	if len(filterIP) > 0 {
		args = append(args, "ip="+url.QueryEscape(filterIP))
	}
	if len(filterRoutedTo) > 0 {
		args = append(args, "routedTo.serviceName="+url.QueryEscape(filterRoutedTo))
	}
	if len(filterType) > 0 {
		args = append(args, "type="+url.QueryEscape(filterType))
	}

	if len(args) > 0 {
		uri = uri + "?" + strings.Join(args, "&")
	}
	r, err := c.GET(uri)
	var ipl = []string{}
	if err = json.Unmarshal(r.Body, &ipl); err == nil {
		for _, i := range ipl {
			ips = append(ips, IPBlock{i, filterType})
		}
	}
	return
}

// GetIPProperties return properties of an IP
func (c *Client) GetIPProperties(IP string) (properties IPProperties, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(IP))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &properties)
	return
}

// UpdateProperties update IP properties
func (c *Client) UpdateProperties(IP, desc string) error {
	payload, err := json.Marshal(IpUpdatableProperties{
		Description: desc,
	})
	if err != nil {
		return err
	}
	r, err := c.PUT("ip/"+url.QueryEscape(IP), string(payload))
	err = r.HandleErr(err, []int{200})
	return err
}

/*
//
//// LOADBALANCING
//

// List IP load balancing
func (r *Client) LbList() (resp []byte, err error) {
	resp, err = r.client.Do("GET", "ip/loadBalancing", "")
	return
}*/

//
//// FIREWALL
//

// FwListIPOfBlock List IP of block IP under firewall protection
func (c *Client) FwListIPOfBlock(block IPBlock) (IPs []string, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall")
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IPs)
	return
}

// FwAddIP Add IP to firewall
func (c *Client) FwAddIP(block IPBlock, IPv4 string) error {
	type p struct {
		IPOnFirewall string `json:"ipOnFirewall"`
	}
	payload, err := json.Marshal(p{IPv4})
	if err != nil {
		return err
	}
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/firewall", string(payload))
	return r.HandleErr(err, []int{200})
}

// FwRemoveIP Remove IP from firewall
func (c *Client) FwRemoveIP(block IPBlock, IPv4 string) error {
	r, err := c.DELETE("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4))
	return r.HandleErr(err, []int{200})
}

// FwGetIPProperties Get properties about an IP firewalled
func (c *Client) FwGetIPProperties(block IPBlock, IPv4 string) (IP FirewalledIp, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IP)
	return
}

// FwUpdateIP  update properties of an IP on firewall
func (c *Client) FwUpdateIP(block IPBlock, IPv4 string, enabled bool) error {
	var err error
	var payload []byte
	type p struct {
		Enabled bool `json:"enabled"`
	}
	if payload, err = json.Marshal(p{enabled}); err != nil {
		return err
	}
	r, err := c.PUT("ip/"+url.QueryEscape(block.IP)+"/firewall/"+url.QueryEscape(IPv4), string(payload))
	return r.HandleErr(err, []int{200})
}

// FwAddRule adds a firewall rule
func (c *Client) FwAddRule(block IPBlock, IPv4 string, rule FwRule2Add) error {
	payload, err := json.Marshal(rule)
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/firewall/"+url.QueryEscape(IPv4)+"/rule", string(payload))
	return r.HandleErr(err, []int{200})
}

// FwListRules return rules sequences
func (c *Client) FwListRules(block IPBlock, IPv4 string, state ...string) (sequences []int, err error) {
	uri := fmt.Sprintf("ip/%s/firewall/%s/rule", url.QueryEscape(block.IP), url.QueryEscape(IPv4))
	if len(state) > 0 {
		if !(state[0] == "creationPending" || state[0] == "ok" || state[0] == "removalPending") {
			err = errors.New("Bad parameter state (creationPending|ok|removalPending)")
			return
		}
		uri = uri + "?state=" + url.QueryEscape(state[0])
	}
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &sequences)
	return
}

// FwGetRuleProperties returns rule Properties
func (c *Client) FwGetRuleProperties(block IPBlock, IPv4 string, sequence int) (rule FirewallRule, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4) + "/rule/" + url.QueryEscape(fmt.Sprintf("%d", sequence)))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &rule)
	return
}

//FwRemoveRule removes a rule
func (c *Client) FwRemoveRule(block IPBlock, IPv4 string, sequence int) error {
	r, err := c.DELETE("ip/" + url.QueryEscape(block.IP) + "/firewall/" + url.QueryEscape(IPv4) + "/rule/" + url.QueryEscape(fmt.Sprintf("%d", sequence)))
	return r.HandleErr(err, []int{200})
}

// REVERSE

// GetReverse return reverse of IP ip
func (c *Client) GetReverse(IP string) (string, error) {
	r, err := c.GET("ip/" + url.QueryEscape(IP+"/32") + "/reverse/" + url.QueryEscape(IP))
	if err != nil {
		return "", err
	}
	response := struct {
		IP      string `json:"ipReverse"`
		Reverse string `json:"reverse"`
	}{}
	err = json.Unmarshal([]byte(r.Body), &response)
	if err != nil {
		return "", err
	}
	return response.Reverse, err
}

//
// SPAM
//

// SpamGetSpammingIps returns Spamming IP
// state :
// 		* blockedForSpam : currently blocked
// 		* unblocking : in the way to be unblocked (or not)
// 		* unblocked : blocked in the past
//
func (c *Client) SpamGetSpammingIPs(block IPBlock, state string) (IPs []string, err error) {
	uri := fmt.Sprintf("ip/%s/spam", url.QueryEscape(block.IP))
	if state == "blockedForSpam" || state == "unblocking" || state == "unblocked" {
		uri = fmt.Sprintf("%s?state=%s", uri, state)
	}
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &IPs)
	return
}

// SpamGetIP returns detailed info about a spamming IP
func (c *Client) SpamGetIP(block IPBlock, IPv4 string) (spamIP *SpamIP, err error) {
	r, err := c.GET("ip/" + url.QueryEscape(block.IP) + "/spam/" + url.QueryEscape(IPv4))
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	err = json.Unmarshal(r.Body, &spamIP)
	return
}

// SpamGetIPStats returns stats about a spamming IP
func (c *Client) SpamGetIPStats(block IPBlock, IPv4 string, from time.Time, to time.Time) (spamStats *SpamStats, err error) {
	uri := fmt.Sprintf("ip/%s/spam/%s/stats?from=%s&to=%s", url.QueryEscape(block.IP), IPv4, url.QueryEscape(from.Format(time.RFC3339)), url.QueryEscape(to.Format(time.RFC3339)))
	r, err := c.GET(uri)
	if err = r.HandleErr(err, []int{200}); err != nil {
		return
	}
	if len(r.Body) > 2 {
		err = json.Unmarshal(r.Body[1:len(r.Body)-1], &spamStats)
	}
	return
}

//SpamUnblockSpamIP Unblocks a spamming IP
func (c *Client) SpamUnblockSpamIP(block IPBlock, IPv4 string) error {
	r, err := c.POST("ip/"+url.QueryEscape(block.IP)+"/spam/"+url.QueryEscape(IPv4)+"/unblock", "")
	return r.HandleErr(err, []int{200})
}

// GetBlockedForSpam returns IPs which are currently blocked for spam
func (c *Client) GetBlockedForSpam() (IPs []string, err error) {
	IPBlocks, err := c.List("", "", "", "")
	if err != nil {
		return
	}
	for _, IPb := range IPBlocks {
		// remove IPv6
		if len(strings.Split(IPb.IP, ":")) > 1 {
			continue
		}
		IPsBlocked, err := c.SpamGetSpammingIPs(IPb, "blockedForSpam")
		if err != nil {
			// Not all IP are concerned by spamming status, if not found continue
			if strings.HasPrefix(err.Error(), "404 This service does not exist") {
				continue
			} else if strings.HasPrefix(err.Error(), "460 This Service is expired") {
				continue
			}
			return IPs, err
		}
		if len(IPsBlocked) > 0 {
			for _, IP := range IPsBlocked {
				IPs = append(IPs, IP)
			}
		}
	}
	return
}
<|endoftext|>


<commit_before>package format

import (
	"fmt"
)

func FormatBytes(bytes uint64) string {
	if bytes>>30 > 100 {
		return fmt.Sprintf("%d GiB", bytes>>30)
	} else if bytes>>20 > 100 {
		return fmt.Sprintf("%d MiB", bytes>>20)
	} else if bytes>>10 > 100 {
		return fmt.Sprintf("%d KiB", bytes>>10)
	} else {
		return fmt.Sprintf("%d B", bytes)
	}
}
<commit_msg>Add lib.format.Duration() function.<commit_after>package format

import (
	"fmt"
	"time"
)

func FormatBytes(bytes uint64) string {
	if bytes>>30 > 100 {
		return fmt.Sprintf("%d GiB", bytes>>30)
	} else if bytes>>20 > 100 {
		return fmt.Sprintf("%d MiB", bytes>>20)
	} else if bytes>>10 > 100 {
		return fmt.Sprintf("%d KiB", bytes>>10)
	} else {
		return fmt.Sprintf("%d B", bytes)
	}
}

func Duration(duration time.Duration) string {
	if ns := duration.Nanoseconds(); ns < 1000 {
		return fmt.Sprintf("%dns", ns)
	} else if us := float64(duration) / float64(time.Microsecond); us < 1000 {
		return fmt.Sprintf("%.3gfµs", us)
	} else if ms := float64(duration) / float64(time.Millisecond); ms < 1000 {
		return fmt.Sprintf("%.3gms", ms)
	} else if s := float64(duration) / float64(time.Second); s < 60 {
		return fmt.Sprintf("%.3gs", s)
	} else {
		duration -= duration % time.Second
		return duration.String()
	}
}
<|endoftext|>


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

package libkbfs

import (
	"github.com/keybase/client/go/libkb"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfssync"
	"github.com/keybase/kbfs/tlf"
	"golang.org/x/net/context"
)

const (
	disableFavoritesEnvVar = "KEYBASE_DISABLE_FAVORITES"
)

type favToAdd struct {
	Favorite

	// created, if set to true, indicates that this is the first time the TLF has
	// ever existed. It is only used when adding the TLF to favorites
	created bool
}

func (f favToAdd) ToKBFolder() keybase1.Folder {
	return f.Favorite.ToKBFolder(f.created)
}

// favReq represents a request to access the logged-in user's
// favorites list.  A single request can do one or more of the
// following: refresh the current cached list, add a favorite, remove
// a favorite, and get all the favorites.  When the request is done,
// the resulting error (or nil) is sent over the done channel.  The
// given ctx is used for all network operations.
type favReq struct {
	// Request types
	refresh bool
	toAdd   []favToAdd
	toDel   []Favorite
	favs    chan<- []Favorite

	// Closed when the request is done.
	done chan struct{}
	// Set before done is closed
	err error

	// Context
	ctx context.Context
}

// Favorites manages a user's favorite list.
type Favorites struct {
	config   Config
	disabled bool

	// Channels for interacting with the favorites cache
	reqChan chan *favReq

	wg kbfssync.RepeatedWaitGroup

	// cache tracks the favorites for this user, that we know about.
	// It may not be consistent with the server's view of the user's
	// favorites list, if other devices have modified the list since
	// the last refresh.
	cache           map[Favorite]bool
	cacheExpireTime time.Time

	inFlightLock sync.Mutex
	inFlightAdds map[favToAdd]*favReq

	muShutdown sync.RWMutex
	shutdown   bool
}

func newFavoritesWithChan(config Config, reqChan chan *favReq) *Favorites {
	disableVal := strings.ToLower(os.Getenv(disableFavoritesEnvVar))
	if len(disableVal) > 0 && disableVal != "0" && disableVal != "false" &&
		disableVal != "no" {
		config.MakeLogger("").CDebugf(nil,
			"Disable favorites due to env var %s=%s",
			disableFavoritesEnvVar, disableVal)
		return &Favorites{
			config:   config,
			disabled: true,
		}
	}

	f := &Favorites{
		config:       config,
		reqChan:      reqChan,
		inFlightAdds: make(map[favToAdd]*favReq),
	}
	go f.loop()
	return f
}

// NewFavorites constructs a new Favorites instance.
func NewFavorites(config Config) *Favorites {
	return newFavoritesWithChan(config, make(chan *favReq, 100))
}

func (f *Favorites) closeReq(req *favReq, err error) {
	f.inFlightLock.Lock()
	defer f.inFlightLock.Unlock()
	req.err = err
	close(req.done)
	for _, fav := range req.toAdd {
		delete(f.inFlightAdds, fav)
	}
}

func (f *Favorites) handleReq(req *favReq) (err error) {
	defer func() { f.closeReq(req, err) }()

	kbpki := f.config.KBPKI()
	// Fetch a new list if:
	//  * The user asked us to refresh
	//  * We haven't fetched it before
	//  * It's stale
	if req.refresh || f.cache == nil || time.Now().After(f.cacheExpireTime) {
		folders, err := kbpki.FavoriteList(req.ctx)
		if err != nil {
			return err
		}

		f.cache = make(map[Favorite]bool)
		f.cacheExpireTime = libkb.ForceWallClock(time.Now()).Add(time.
			Hour * 24 * 7)
		for _, folder := range folders {
			f.cache[*NewFavoriteFromFolder(folder)] = true
		}
		session, err := f.config.KBPKI().GetCurrentSession(req.ctx)
		if err == nil {
			// Add favorites for the current user, that cannot be deleted.
			f.cache[Favorite{string(session.Name), tlf.Private}] = true
			f.cache[Favorite{string(session.Name), tlf.Public}] = true
		}
	}

	for _, fav := range req.toAdd {
		if !fav.created && f.cache[fav.Favorite] {
			continue
		}
		err := kbpki.FavoriteAdd(req.ctx, fav.ToKBFolder())
		if err != nil {
			f.config.MakeLogger("").CDebugf(req.ctx,
				"Failure adding favorite %v: %v", fav, err)
			return err
		}
		f.cache[fav.Favorite] = true
	}

	for _, fav := range req.toDel {
		// Since our cache isn't necessarily up-to-date, always delete
		// the favorite.
		folder := fav.ToKBFolder(false)
		err := kbpki.FavoriteDelete(req.ctx, folder)
		if err != nil {
			return err
		}
		delete(f.cache, fav)
	}

	if req.favs != nil {
		favorites := make([]Favorite, 0, len(f.cache))
		for fav := range f.cache {
			favorites = append(favorites, fav)
		}
		req.favs <- favorites
	}

	return nil
}

func (f *Favorites) loop() {
	for req := range f.reqChan {
		f.handleReq(req)
		f.wg.Done()
	}
}

// Shutdown shuts down this Favorites instance.
func (f *Favorites) Shutdown() error {
	if f.disabled {
		return nil
	}

	f.muShutdown.Lock()
	defer f.muShutdown.Unlock()
	f.shutdown = true
	close(f.reqChan)
	return f.wg.Wait(context.Background())
}

func (f *Favorites) hasShutdown() bool {
	f.muShutdown.RLock()
	defer f.muShutdown.RUnlock()
	return f.shutdown
}

func (f *Favorites) waitOnReq(ctx context.Context,
	req *favReq) (retry bool, err error) {
	select {
	case <-ctx.Done():
		return false, ctx.Err()
	case <-req.done:
		err = req.err
		// If the request was canceled due to a context timeout that
		// wasn't our own, try it again.
		if err == context.Canceled || err == context.DeadlineExceeded {
			select {
			case <-ctx.Done():
				return false, err
			default:
				return true, nil
			}
		}
		return false, err
	}
}

func (f *Favorites) sendReq(ctx context.Context, req *favReq) error {
	f.wg.Add(1)
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		f.wg.Done()
		err := ctx.Err()
		f.closeReq(req, err)
		return err
	}
	// With a direct sendReq call, we'll never have a shared request,
	// so no need to check the retry status.
	_, err := f.waitOnReq(ctx, req)
	return err
}

func (f *Favorites) startOrJoinAddReq(
	ctx context.Context, fav favToAdd) (req *favReq, doSend bool) {
	f.inFlightLock.Lock()
	defer f.inFlightLock.Unlock()
	req, ok := f.inFlightAdds[fav]
	if !ok {
		req = &favReq{
			ctx:   ctx,
			toAdd: []favToAdd{fav},
			done:  make(chan struct{}),
		}
		f.inFlightAdds[fav] = req
		doSend = true
	}
	return req, doSend
}

// Add adds a favorite to your favorites list.
func (f *Favorites) Add(ctx context.Context, fav favToAdd) error {
	if f.disabled {
		return nil
	}
	if f.hasShutdown() {
		return ShutdownHappenedError{}
	}
	doAdd := true
	var err error
	// Retry until we get an error that wasn't related to someone
	// else's context being canceled.
	for doAdd {
		req, doSend := f.startOrJoinAddReq(ctx, fav)
		if doSend {
			return f.sendReq(ctx, req)
		}
		doAdd, err = f.waitOnReq(ctx, req)
	}
	return err
}

// AddAsync initiates a request to add this favorite to your favorites
// list, if one is not already in flight, but it doesn't wait for the
// result.  (It could block while kicking off the request, if lots of
// different favorite operations are in flight.)  The given context is
// used only for enqueuing the request on an internal queue, not for
// any resulting I/O.
func (f *Favorites) AddAsync(ctx context.Context, fav favToAdd) {
	if f.disabled || f.hasShutdown() {
		return
	}
	// Use a fresh context, since we want the request to succeed even
	// if the original context is canceled.
	req, doSend := f.startOrJoinAddReq(context.Background(), fav)
	if doSend {
		f.wg.Add(1)
		select {
		case f.reqChan <- req:
		case <-ctx.Done():
			f.wg.Done()
			err := ctx.Err()
			f.closeReq(req, err)
			return
		}
	}
}

// Delete deletes a favorite from the favorites list.  It is
// idempotent.
func (f *Favorites) Delete(ctx context.Context, fav Favorite) error {
	if f.disabled {
		return nil
	}
	if f.hasShutdown() {
		return ShutdownHappenedError{}
	}
	return f.sendReq(ctx, &favReq{
		ctx:   ctx,
		toDel: []Favorite{fav},
		done:  make(chan struct{}),
	})
}

// RefreshCache refreshes the cached list of favorites.
func (f *Favorites) RefreshCache(ctx context.Context) {
	if f.disabled || f.hasShutdown() {
		return
	}
	// This request is non-blocking, so use a throw-away done channel
	// and context.
	req := &favReq{
		refresh: true,
		done:    make(chan struct{}),
		ctx:     context.Background(),
	}
	f.wg.Add(1)
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		f.wg.Done()
		return
	}
}

// Get returns the logged-in user's list of favorites. It uses the cache.
// TODO: decide on behavior if we've gotten an invalidation but not an updated
// list yet
func (f *Favorites) Get(ctx context.Context) ([]Favorite, error) {
	if f.disabled {
		session, err := f.config.KBPKI().GetCurrentSession(ctx)
		if err == nil {
			// Add favorites only for the current user.
			return []Favorite{
				{string(session.Name), tlf.Private},
				{string(session.Name), tlf.Public},
			}, nil
		}
		return nil, nil
	}
	if f.hasShutdown() {
		return nil, ShutdownHappenedError{}
	}
	favChan := make(chan []Favorite, 1)
	req := &favReq{
		ctx:  ctx,
		favs: favChan,
		done: make(chan struct{}),
	}
	err := f.sendReq(ctx, req)
	if err != nil {
		return nil, err
	}
	return <-favChan, nil
}
<commit_msg>favorites: shorten cache on refresh error<commit_after>// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.

package libkbfs

import (
	"github.com/keybase/client/go/libkb"
	"os"
	"strings"
	"sync"
	"time"

	"github.com/keybase/client/go/protocol/keybase1"
	"github.com/keybase/kbfs/kbfssync"
	"github.com/keybase/kbfs/tlf"
	"golang.org/x/net/context"
)

const (
	disableFavoritesEnvVar       = "KEYBASE_DISABLE_FAVORITES"
	favoritesCacheExpirationTime = time.Hour * 24 * 7 // one week
)

type favToAdd struct {
	Favorite

	// created, if set to true, indicates that this is the first time the TLF has
	// ever existed. It is only used when adding the TLF to favorites
	created bool
}

func (f favToAdd) ToKBFolder() keybase1.Folder {
	return f.Favorite.ToKBFolder(f.created)
}

// favReq represents a request to access the logged-in user's
// favorites list.  A single request can do one or more of the
// following: refresh the current cached list, add a favorite, remove
// a favorite, and get all the favorites.  When the request is done,
// the resulting error (or nil) is sent over the done channel.  The
// given ctx is used for all network operations.
type favReq struct {
	// Request types
	refresh bool
	toAdd   []favToAdd
	toDel   []Favorite
	favs    chan<- []Favorite

	// Closed when the request is done.
	done chan struct{}
	// Set before done is closed
	err error

	// Context
	ctx context.Context
}

// Favorites manages a user's favorite list.
type Favorites struct {
	config   Config
	disabled bool

	// Channels for interacting with the favorites cache
	reqChan chan *favReq

	wg kbfssync.RepeatedWaitGroup

	// cache tracks the favorites for this user, that we know about.
	// It may not be consistent with the server's view of the user's
	// favorites list, if other devices have modified the list since
	// the last refresh.
	cache           map[Favorite]bool
	cacheExpireTime time.Time

	inFlightLock sync.Mutex
	inFlightAdds map[favToAdd]*favReq

	muShutdown sync.RWMutex
	shutdown   bool
}

func newFavoritesWithChan(config Config, reqChan chan *favReq) *Favorites {
	disableVal := strings.ToLower(os.Getenv(disableFavoritesEnvVar))
	if len(disableVal) > 0 && disableVal != "0" && disableVal != "false" &&
		disableVal != "no" {
		config.MakeLogger("").CDebugf(nil,
			"Disable favorites due to env var %s=%s",
			disableFavoritesEnvVar, disableVal)
		return &Favorites{
			config:   config,
			disabled: true,
		}
	}

	f := &Favorites{
		config:       config,
		reqChan:      reqChan,
		inFlightAdds: make(map[favToAdd]*favReq),
	}
	go f.loop()
	return f
}

// NewFavorites constructs a new Favorites instance.
func NewFavorites(config Config) *Favorites {
	return newFavoritesWithChan(config, make(chan *favReq, 100))
}

func (f *Favorites) closeReq(req *favReq, err error) {
	f.inFlightLock.Lock()
	defer f.inFlightLock.Unlock()
	req.err = err
	close(req.done)
	for _, fav := range req.toAdd {
		delete(f.inFlightAdds, fav)
	}
}

func (f *Favorites) handleReq(req *favReq) (err error) {
	defer func() { f.closeReq(req, err) }()

	kbpki := f.config.KBPKI()
	// Fetch a new list if:
	//  * The user asked us to refresh
	//  * We haven't fetched it before
	//  * It's stale
	if req.refresh || f.cache == nil || time.Now().After(f.cacheExpireTime) {
		folders, err := kbpki.FavoriteList(req.ctx)
		if err != nil {
			if req.refresh {
				// if we're supposed to refresh the cache and it's not
				// working, try again in a few minutes.
				in5Minutes := time.Now().Add(5 * time.Minute)
				if in5Minutes.After(f.cacheExpireTime) {
					f.cacheExpireTime = in5Minutes
				}
			}
			return err
		}

		f.cache = make(map[Favorite]bool)
		f.cacheExpireTime = libkb.ForceWallClock(time.Now()).Add(favoritesCacheExpirationTime)
		for _, folder := range folders {
			f.cache[*NewFavoriteFromFolder(folder)] = true
		}
		session, err := f.config.KBPKI().GetCurrentSession(req.ctx)
		if err == nil {
			// Add favorites for the current user, that cannot be deleted.
			f.cache[Favorite{string(session.Name), tlf.Private}] = true
			f.cache[Favorite{string(session.Name), tlf.Public}] = true
		}
	}

	for _, fav := range req.toAdd {
		if !fav.created && f.cache[fav.Favorite] {
			continue
		}
		err := kbpki.FavoriteAdd(req.ctx, fav.ToKBFolder())
		if err != nil {
			f.config.MakeLogger("").CDebugf(req.ctx,
				"Failure adding favorite %v: %v", fav, err)
			return err
		}
		f.cache[fav.Favorite] = true
	}

	for _, fav := range req.toDel {
		// Since our cache isn't necessarily up-to-date, always delete
		// the favorite.
		folder := fav.ToKBFolder(false)
		err := kbpki.FavoriteDelete(req.ctx, folder)
		if err != nil {
			return err
		}
		delete(f.cache, fav)
	}

	if req.favs != nil {
		favorites := make([]Favorite, 0, len(f.cache))
		for fav := range f.cache {
			favorites = append(favorites, fav)
		}
		req.favs <- favorites
	}

	return nil
}

func (f *Favorites) loop() {
	for req := range f.reqChan {
		f.handleReq(req)
		f.wg.Done()
	}
}

// Shutdown shuts down this Favorites instance.
func (f *Favorites) Shutdown() error {
	if f.disabled {
		return nil
	}

	f.muShutdown.Lock()
	defer f.muShutdown.Unlock()
	f.shutdown = true
	close(f.reqChan)
	return f.wg.Wait(context.Background())
}

func (f *Favorites) hasShutdown() bool {
	f.muShutdown.RLock()
	defer f.muShutdown.RUnlock()
	return f.shutdown
}

func (f *Favorites) waitOnReq(ctx context.Context,
	req *favReq) (retry bool, err error) {
	select {
	case <-ctx.Done():
		return false, ctx.Err()
	case <-req.done:
		err = req.err
		// If the request was canceled due to a context timeout that
		// wasn't our own, try it again.
		if err == context.Canceled || err == context.DeadlineExceeded {
			select {
			case <-ctx.Done():
				return false, err
			default:
				return true, nil
			}
		}
		return false, err
	}
}

func (f *Favorites) sendReq(ctx context.Context, req *favReq) error {
	f.wg.Add(1)
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		f.wg.Done()
		err := ctx.Err()
		f.closeReq(req, err)
		return err
	}
	// With a direct sendReq call, we'll never have a shared request,
	// so no need to check the retry status.
	_, err := f.waitOnReq(ctx, req)
	return err
}

func (f *Favorites) startOrJoinAddReq(
	ctx context.Context, fav favToAdd) (req *favReq, doSend bool) {
	f.inFlightLock.Lock()
	defer f.inFlightLock.Unlock()
	req, ok := f.inFlightAdds[fav]
	if !ok {
		req = &favReq{
			ctx:   ctx,
			toAdd: []favToAdd{fav},
			done:  make(chan struct{}),
		}
		f.inFlightAdds[fav] = req
		doSend = true
	}
	return req, doSend
}

// Add adds a favorite to your favorites list.
func (f *Favorites) Add(ctx context.Context, fav favToAdd) error {
	if f.disabled {
		return nil
	}
	if f.hasShutdown() {
		return ShutdownHappenedError{}
	}
	doAdd := true
	var err error
	// Retry until we get an error that wasn't related to someone
	// else's context being canceled.
	for doAdd {
		req, doSend := f.startOrJoinAddReq(ctx, fav)
		if doSend {
			return f.sendReq(ctx, req)
		}
		doAdd, err = f.waitOnReq(ctx, req)
	}
	return err
}

// AddAsync initiates a request to add this favorite to your favorites
// list, if one is not already in flight, but it doesn't wait for the
// result.  (It could block while kicking off the request, if lots of
// different favorite operations are in flight.)  The given context is
// used only for enqueuing the request on an internal queue, not for
// any resulting I/O.
func (f *Favorites) AddAsync(ctx context.Context, fav favToAdd) {
	if f.disabled || f.hasShutdown() {
		return
	}
	// Use a fresh context, since we want the request to succeed even
	// if the original context is canceled.
	req, doSend := f.startOrJoinAddReq(context.Background(), fav)
	if doSend {
		f.wg.Add(1)
		select {
		case f.reqChan <- req:
		case <-ctx.Done():
			f.wg.Done()
			err := ctx.Err()
			f.closeReq(req, err)
			return
		}
	}
}

// Delete deletes a favorite from the favorites list.  It is
// idempotent.
func (f *Favorites) Delete(ctx context.Context, fav Favorite) error {
	if f.disabled {
		return nil
	}
	if f.hasShutdown() {
		return ShutdownHappenedError{}
	}
	return f.sendReq(ctx, &favReq{
		ctx:   ctx,
		toDel: []Favorite{fav},
		done:  make(chan struct{}),
	})
}

// RefreshCache refreshes the cached list of favorites.
func (f *Favorites) RefreshCache(ctx context.Context) {
	if f.disabled || f.hasShutdown() {
		return
	}
	// This request is non-blocking, so use a throw-away done channel
	// and context.
	req := &favReq{
		refresh: true,
		done:    make(chan struct{}),
		ctx:     context.Background(),
	}
	f.wg.Add(1)
	select {
	case f.reqChan <- req:
	case <-ctx.Done():
		f.wg.Done()
		return
	}
}

// Get returns the logged-in user's list of favorites. It uses the cache.
func (f *Favorites) Get(ctx context.Context) ([]Favorite, error) {
	if f.disabled {
		session, err := f.config.KBPKI().GetCurrentSession(ctx)
		if err == nil {
			// Add favorites only for the current user.
			return []Favorite{
				{string(session.Name), tlf.Private},
				{string(session.Name), tlf.Public},
			}, nil
		}
		return nil, nil
	}
	if f.hasShutdown() {
		return nil, ShutdownHappenedError{}
	}
	favChan := make(chan []Favorite, 1)
	req := &favReq{
		ctx:  ctx,
		favs: favChan,
		done: make(chan struct{}),
	}
	err := f.sendReq(ctx, req)
	if err != nil {
		return nil, err
	}
	return <-favChan, nil
}
<|endoftext|>


<commit_before>package ssgo

import (
	"net"
	"runtime"
	"time"
)

type ConPool struct {
	ctype    string
	clink    string
	ctimeout time.Duration
	conns    chan *Client
}

func NewConPool(hostAddr string, maxConn int) *ConPool {

	if maxConn < 1 {
		maxConn = runtime.NumCPU() * 2
	}

	cr := &ConPool{
		ctype:    "tcp",
		clink:    hostAddr,
		ctimeout: time.Duration(10) * time.Second,
		conns:    make(chan *Client, maxConn),
	}

	//	if cr.ctimeout < 1*time.Second {
	//		cr.ctimeout = 10 * time.Second
	//	}

	return cr
}

func dialTimeout(network, addr string) (*Client, error) {

	raddr, err := net.ResolveTCPAddr(network, addr)
	if err != nil {
		return nil, err
	}
	sock, err := net.DialTCP(network, nil, raddr)
	if err != nil {
		return nil, err
	}

	return &Client{sock: sock}, nil
}

func (cr *ConPool) dialNew() (*Client, error) {
	cn, err := dialTimeout(cr.ctype, cr.clink)
	if err != nil {
		return nil, err
	}
	cn.pool = cr
	return cn, nil
}

//func (cr *ConPool) Cmd(args ...interface{}) *Reply {
//
//	cn, _ := cr.GetClient()
//	defer cn.Release()
//
//	cn.sock.SetReadDeadline(time.Now().Add(cr.ctimeout))
//	cn.sock.SetWriteDeadline(time.Now().Add(cr.ctimeout))
//
//	return cn.Cmd(args...)
//}

func (cr *ConPool) Close() {
	var conn *Client
	for {
		select {
		case conn = <-cr.conns:
			conn.close()
		default:
			return
		}
	}
}

func (cr *ConPool) push(cn *Client) {
	select {
	case cr.conns <- cn:
	default:
		cn.close()
	}
}

func (cr *ConPool) GetClient() (cn *Client, err error) {
	select {
	case conn := <-cr.conns:
		return conn, nil
	default:
		return cr.dialNew()
	}
}
<commit_msg>no message<commit_after>package ssgo

import (
	"net"
	"runtime"
	"time"
)

type ConPool struct {
	ctype    string
	clink    string
	ctimeout time.Duration
	conns    chan *Client
}

func NewConPool(hostAddr string, maxConn int) *ConPool {

	if maxConn < 1 {
		maxConn = runtime.NumCPU() * 2
	}

	cr := &ConPool{
		ctype:    "tcp",
		clink:    hostAddr,
		ctimeout: time.Duration(10) * time.Second,
		conns:    make(chan *Client, maxConn),
	}

	//	if cr.ctimeout < 1*time.Second {
	//		cr.ctimeout = 10 * time.Second
	//	}

	return cr
}

func dialTimeout(network, addr string) (*Client, error) {

	raddr, err := net.ResolveTCPAddr(network, addr)
	if err != nil {
		return nil, err
	}
	sock, err := net.DialTCP(network, nil, raddr)
	if err != nil {
		return nil, err
	}

	return &Client{sock: sock}, nil
}

func (cr *ConPool) dialNew() (*Client, error) {
	cn, err := dialTimeout(cr.ctype, cr.clink)
	if err != nil {
		return nil, err
	}
	cn.pool = cr
	return cn, nil
}

func (cr *ConPool) Do(args ...interface{}) (Reply, error) {

	cn, e := cr.GetClient()
	if e != nil {
		return nil, e
	}
	defer cn.Release()

	cn.sock.SetReadDeadline(time.Now().Add(cr.ctimeout))
	cn.sock.SetWriteDeadline(time.Now().Add(cr.ctimeout))

	return cn.Do(args...)
}

func (cr *ConPool) Close() {
	var conn *Client
	for {
		select {
		case conn = <-cr.conns:
			conn.close()
		default:
			return
		}
	}
}

func (cr *ConPool) push(cn *Client) {
	select {
	case cr.conns <- cn:
	default:
		cn.close()
	}
}

func (cr *ConPool) GetClient() (cn *Client, err error) {
	select {
	case conn := <-cr.conns:
		return conn, nil
	default:
		return cr.dialNew()
	}
}
<|endoftext|>


<commit_before>package workerpool

// Job is the function which should be executed in worker.
type Job func()

type Pool struct {
	JobQueue chan Job
	d        *dispatcher
}

// New creates pool of workers.
// numWorkers - how many workers will be created for this pool
// queLen - how many jobs can we accept until we block
//
// Returned object contains JobQueue reference, which you can use to send job to pool.
func New(numWorkers int, queLen int) *Pool {
	jobQueue := make(chan Job, queLen)

	pool := &Pool{
		JobQueue: jobQueue,
		d:        newDispatcher(numWorkers, jobQueue),
	}

	return pool
}

// Will release resources used by pool
func (p *Pool) Stop() {
	p.d.stop()
}
<commit_msg>Add/fix some comments on the exported methods<commit_after>package workerpool

// Job is the function which should be executed in worker.
type Job func()

// Pool contains all information for the pool instance.
// Exports JobQueue used to send jobs to the pool
type Pool struct {
	JobQueue chan Job
	d        *dispatcher
}

// New creates pool of workers.
// numWorkers - how many workers will be created for this pool
// queueLen - how many jobs can we accept until we block
//
// Returned object contains JobQueue reference, which you can use to send job to pool.
func New(numWorkers int, queueLen int) *Pool {
	jobQueue := make(chan Job, queueLen)

	pool := &Pool{
		JobQueue: jobQueue,
		d:        newDispatcher(numWorkers, jobQueue),
	}

	return pool
}

// Stop will stop the workers and release resources used by pool
func (p *Pool) Stop() {
	p.d.stop()
}
<|endoftext|>


<commit_before>// Package pop3 provides a partial implementation of the Post Office Protocol,
// Version 3 as defined in RFC 1939. Selected client-sent messages are not
// implemented: APOP.

package main

import (
	"bufio"
	"crypto/tls"
	"errors"
	"fmt"
	"net"
)

// The POP3 client.
type Client struct {
	conn net.Conn
	bin  *bufio.Reader
}

// Dial creates an unsecured connection to the POP3 server at the given address
// and returns the corresponding Client.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// DialTLS creates a TLS-secured connection to the POP3 server at the given
// address and returns the corresponding Client.
func DialTLS(addr string) (*Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// NewClient returns a new Client object using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	client := &Client{
		bin: bufio.NewReader(conn),
		conn: conn,
	}
	// send dud command, to read a line
	_, err := client.cmd("")
	if err != nil { return nil, err }
	return client, nil
}

// Convenience function to synchronously run an arbitrary command and wait for
// output. The terminating CRLF must be included in the format string.
func (c *Client) cmd(format string, args ...interface{}) (string, error) {
	fmt.Fprintf(c.conn, format, args...)
	line, _, err := c.bin.ReadLine()
	l := string(line)
	if l[0:3] != "+OK" {
		err = errors.New(l[5:])
	}
	return l, err
}

// User sends the given username to the server. Generally, there is no reason
// not to use the Auth convenience method.
func (c *Client) User(username string) (err error) {
	_, err = c.cmd("USER %s\r\n", username)
	return
}

// Pass sends the given password to the server. The password is sent
// unencrypted unless the connection is already secured by TLS (via DialTLS or
// some other mechanism). Generally, there is no reason not to use the Auth
// convenience method.
func (c *Client) Pass(password string) (err error) {
	_, err = c.cmd("PASS %s\r\n", password)
	return
}

// Auth sends the given username and password to the server, calling the User
// and Pass methods as appropriate.
func (c *Client) Auth(username, password string) (err error) {
	err = c.User(username)
	if err != nil { return }
	err = c.Pass(password)
	return
}

// Quit sends the QUIT message to the POP3 server and closes the connection.
func (c *Client) Quit() error {
	_, err := c.cmd("QUIT\r\n")
	if err != nil { return err }
	c.conn.Close()
	return nil
}
<commit_msg>Adding APOP<commit_after>// Package pop3 provides an implementation of the Post Office Protocol, Version
// 3 as defined in RFC 1939.

package main

import (
	"bufio"
	"crypto/tls"
	"errors"
	"fmt"
	"net"
)

// The POP3 client.
type Client struct {
	conn net.Conn
	bin  *bufio.Reader
}

// Dial creates an unsecured connection to the POP3 server at the given address
// and returns the corresponding Client.
func Dial(addr string) (*Client, error) {
	conn, err := net.Dial("tcp", addr)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// DialTLS creates a TLS-secured connection to the POP3 server at the given
// address and returns the corresponding Client.
func DialTLS(addr string) (*Client, error) {
	conn, err := tls.Dial("tcp", addr, nil)
	if err != nil {
		return nil, err
	}
	return NewClient(conn)
}

// NewClient returns a new Client object using an existing connection.
func NewClient(conn net.Conn) (*Client, error) {
	client := &Client{
		bin: bufio.NewReader(conn),
		conn: conn,
	}
	// send dud command, to read a line
	_, err := client.cmd("")
	if err != nil { return nil, err }
	return client, nil
}

// Convenience function to synchronously run an arbitrary command and wait for
// output. The terminating CRLF must be included in the format string.
func (c *Client) cmd(format string, args ...interface{}) (string, error) {
	fmt.Fprintf(c.conn, format, args...)
	line, _, err := c.bin.ReadLine()
	l := string(line)
	if l[0:3] != "+OK" {
		err = errors.New(l[5:])
	}
	return l, err
}

// User sends the given username to the server. Generally, there is no reason
// not to use the Auth convenience method.
func (c *Client) User(username string) (err error) {
	_, err = c.cmd("USER %s\r\n", username)
	return
}

// Pass sends the given password to the server. The password is sent
// unencrypted unless the connection is already secured by TLS (via DialTLS or
// some other mechanism). Generally, there is no reason not to use the Auth
// convenience method.
func (c *Client) Pass(password string) (err error) {
	_, err = c.cmd("PASS %s\r\n", password)
	return
}

// Auth sends the given username and password to the server, calling the User
// and Pass methods as appropriate.
func (c *Client) Auth(username, password string) (err error) {
	err = c.User(username)
	if err != nil { return }
	err = c.Pass(password)
	return
}

// Apop sends the given username and password hash (MD5 digest) to the server.
// This method does not offer any more real security over Auth.
func (c *Client) Apop(username, digest string) (err error) {
	_, err = c.cmd("APOP %s %s\n", username, digest)
	return
}

// Quit sends the QUIT message to the POP3 server and closes the connection.
func (c *Client) Quit() error {
	_, err := c.cmd("QUIT\r\n")
	if err != nil { return err }
	c.conn.Close()
	return nil
}
<|endoftext|>


<commit_before>package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var cmdPush = &Command{
	Run:   runPush,
	Usage: "push (<metadata> <name> | <file>...)",
	Short: "Deploy artifact from a local directory",
	Long: `
Deploy artifact from a local directory
<metadata>: Accepts either actual directory name or Metadata type

Examples:
  force push classes MyClass
  force push ApexClass MyClass
  force push src/classes/MyClass.cls
`,
}

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path string
	name string
}

var metapaths = []metapath{
	metapath{"classes", "ApexClass"},
	metapath{"objects", "CustomObject"},
	metapath{"tabs", "CustomTab"},
	metapath{"flexipages", "FlexiPage"},
	metapath{"components", "ApexComponent"},
	metapath{"triggers", "ApexTrigger"},
	metapath{"pages", "ApexPage"},
}

func getPathForMeta(metaname string) string {
	for _, mp := range metapaths {
		if strings.EqualFold(mp.name, metaname) {
			return mp.path
		}
	}

	// Unknown, so use metaname
	return metaname
}

func getMetaForPath(path string) string {
	for _, mp := range metapaths {
		if mp.path == path {
			return mp.name
		}
	}

	// Unknown, so use path
	return path
}

func argIsFile(fpath string) bool {
	if _, err := os.Stat(fpath); err != nil {
		return false
	}
	return true
}

func runPush(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
		return
	}

	if argIsFile(args[0]) {
		fpath := args[0]
		pushByPaths(args)

		fmt.Printf("Pushed %s to Force.com\n", fpath)
		return
	}

	if len(args) == 2 {
		// If arg[0] is already path or meta, the method will return arg[0]
		objPath := getPathForMeta(args[0])
		objName := args[1]
		pushByName(objPath, objName)

		fmt.Printf("Pushed %s to Force.com\n", objName)
		return
	}

	fmt.Println("Could not find file or determine metadata")

	// If we got here, something is not valid
	cmd.printUsage()
}

func pushByName(objPath string, objName string) {
	wd, _ := os.Getwd()

	// First try for metadata directory
	root := filepath.Join(wd, "metadata")
	if _, err := os.Stat(filepath.Join(root, "package.xml")); os.IsNotExist(err) {
		// If not found, try for src directory
		root = filepath.Join(wd, "src")
		if _, err := os.Stat(filepath.Join(root, "package.xml")); os.IsNotExist(err) {
			ErrorAndExit("Current directory must contain a src or metadata directory")
		}
	}

	if _, err := os.Stat(filepath.Join(root, objPath)); os.IsNotExist(err) {
		ErrorAndExit("Folder " + objPath + " not found, must specify valid metadata")
	}

	// Find file by walking directory and ignoring extension
	found := false
	var fpath string
	err := filepath.Walk(filepath.Join(root, objPath), func(path string, f os.FileInfo, err error) error {
		if f.Mode().IsRegular() {
			fname := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			if strings.EqualFold(fname, objName) {
				found = true
				fpath = filepath.Join(root, objPath, f.Name())
			}
		}
		return nil
	})
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if !found {
		ErrorAndExit("Could not find " + objName + " in " + objPath)
	}

	pushByPath(fpath)
}

func pushByPath(fpath string) {
	pushByPaths([]string{fpath})
}

// Push metadata object by path to a file
func pushByPaths(fpaths []string) {
	files := make(ForceMetadataFiles)
	xmlMap := make(map[string][]string)

	for _, fpath := range fpaths {
		addFile(files, xmlMap, fpath)
	}

	files["package.xml"] = buildXml(xmlMap)

	deployFiles(files)
}

func addFile(files ForceMetadataFiles, xmlMap map[string][]string, fpath string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	hasMeta := true
	fname := filepath.Base(fpath)
	fname = strings.TrimSuffix(fname, filepath.Ext(fname))
	fdir := filepath.Dir(fpath)
	typePath := filepath.Base(fdir)
	srcDir := filepath.Dir(fdir)
	metaType := getMetaForPath(typePath)
	// Should be present since we worked back to srcDir
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err := os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			ErrorAndExit("Cound not open " + fmeta)
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	xmlMap[metaType] = append(xmlMap[metaType], fname)

	fdata, err := ioutil.ReadFile(fpath)
	files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		files[fmetarel] = fdata
	}
}

func buildXml(xmlMap map[string][]string) []byte {
	p := createPackage()

	for metaType, members := range xmlMap {
		t := MetaType{Name: metaType}
		for _, member := range members {
			t.Members = append(t.Members, member)
		}
		p.Types = append(p.Types, t)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)

	return byteXml
}

func deployFiles(files ForceMetadataFiles) {
	force, _ := ActiveForce()
	var DeploymentOptions ForceDeployOptions
	successes, problems, err := force.Metadata.Deploy(files, DeploymentOptions)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	fmt.Printf("\nFailures - %d\n", len(problems))
	for _, problem := range problems {
		if problem.FullName == "" {
			fmt.Println(problem.Problem)
		} else {
			fmt.Printf("ERROR with %s:\n %s\n", problem.FullName, problem.Problem)
		}
	}

	fmt.Printf("\nSuccesses - %d\n", len(successes))
	for _, success := range successes {
		if success.FullName != "package.xml" {
			verb := "unchanged"
			if success.Changed {
				verb = "changed"
			} else if success.Deleted {
				verb = "deleted"
			} else if success.Created {
				verb = "created"
			}
			fmt.Printf("%s\n\tstatus: %s\n\tid=%s\n", success.FullName, verb, success.Id)
		}
	}
}
<commit_msg>Ignore package.xml in successes<commit_after>package main

import (
	"encoding/xml"
	"fmt"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
)

var cmdPush = &Command{
	Run:   runPush,
	Usage: "push (<metadata> <name> | <file>...)",
	Short: "Deploy artifact from a local directory",
	Long: `
Deploy artifact from a local directory
<metadata>: Accepts either actual directory name or Metadata type

Examples:
  force push classes MyClass
  force push ApexClass MyClass
  force push src/classes/MyClass.cls
`,
}

// Structs for XML building
type Package struct {
	Xmlns   string     `xml:"xmlns,attr"`
	Types   []MetaType `xml:"types"`
	Version string     `xml:"version"`
}

type MetaType struct {
	Members []string `xml:"members"`
	Name    string   `xml:"name"`
}

func createPackage() Package {
	return Package{
		Version: strings.TrimPrefix(apiVersion, "v"),
		Xmlns:   "http://soap.sforce.com/2006/04/metadata",
	}
}

type metapath struct {
	path string
	name string
}

var metapaths = []metapath{
	metapath{"classes", "ApexClass"},
	metapath{"objects", "CustomObject"},
	metapath{"tabs", "CustomTab"},
	metapath{"flexipages", "FlexiPage"},
	metapath{"components", "ApexComponent"},
	metapath{"triggers", "ApexTrigger"},
	metapath{"pages", "ApexPage"},
}

func getPathForMeta(metaname string) string {
	for _, mp := range metapaths {
		if strings.EqualFold(mp.name, metaname) {
			return mp.path
		}
	}

	// Unknown, so use metaname
	return metaname
}

func getMetaForPath(path string) string {
	for _, mp := range metapaths {
		if mp.path == path {
			return mp.name
		}
	}

	// Unknown, so use path
	return path
}

func argIsFile(fpath string) bool {
	if _, err := os.Stat(fpath); err != nil {
		return false
	}
	return true
}

func runPush(cmd *Command, args []string) {
	if len(args) == 0 {
		cmd.printUsage()
		return
	}

	if argIsFile(args[0]) {
		fpath := args[0]
		pushByPaths(args)

		fmt.Printf("Pushed %s to Force.com\n", fpath)
		return
	}

	if len(args) == 2 {
		// If arg[0] is already path or meta, the method will return arg[0]
		objPath := getPathForMeta(args[0])
		objName := args[1]
		pushByName(objPath, objName)

		fmt.Printf("Pushed %s to Force.com\n", objName)
		return
	}

	fmt.Println("Could not find file or determine metadata")

	// If we got here, something is not valid
	cmd.printUsage()
}

func pushByName(objPath string, objName string) {
	wd, _ := os.Getwd()

	// First try for metadata directory
	root := filepath.Join(wd, "metadata")
	if _, err := os.Stat(filepath.Join(root, "package.xml")); os.IsNotExist(err) {
		// If not found, try for src directory
		root = filepath.Join(wd, "src")
		if _, err := os.Stat(filepath.Join(root, "package.xml")); os.IsNotExist(err) {
			ErrorAndExit("Current directory must contain a src or metadata directory")
		}
	}

	if _, err := os.Stat(filepath.Join(root, objPath)); os.IsNotExist(err) {
		ErrorAndExit("Folder " + objPath + " not found, must specify valid metadata")
	}

	// Find file by walking directory and ignoring extension
	found := false
	var fpath string
	err := filepath.Walk(filepath.Join(root, objPath), func(path string, f os.FileInfo, err error) error {
		if f.Mode().IsRegular() {
			fname := strings.TrimSuffix(f.Name(), filepath.Ext(f.Name()))
			if strings.EqualFold(fname, objName) {
				found = true
				fpath = filepath.Join(root, objPath, f.Name())
			}
		}
		return nil
	})
	if err != nil {
		ErrorAndExit(err.Error())
	}
	if !found {
		ErrorAndExit("Could not find " + objName + " in " + objPath)
	}

	pushByPath(fpath)
}

func pushByPath(fpath string) {
	pushByPaths([]string{fpath})
}

// Push metadata object by path to a file
func pushByPaths(fpaths []string) {
	files := make(ForceMetadataFiles)
	xmlMap := make(map[string][]string)

	for _, fpath := range fpaths {
		addFile(files, xmlMap, fpath)
	}

	files["package.xml"] = buildXml(xmlMap)

	deployFiles(files)
}

func addFile(files ForceMetadataFiles, xmlMap map[string][]string, fpath string) {
	fpath, err := filepath.Abs(fpath)
	if err != nil {
		ErrorAndExit("Cound not find " + fpath)
	}
	if _, err := os.Stat(fpath); err != nil {
		ErrorAndExit("Cound not open " + fpath)
	}

	hasMeta := true
	fname := filepath.Base(fpath)
	fname = strings.TrimSuffix(fname, filepath.Ext(fname))
	fdir := filepath.Dir(fpath)
	typePath := filepath.Base(fdir)
	srcDir := filepath.Dir(fdir)
	metaType := getMetaForPath(typePath)
	// Should be present since we worked back to srcDir
	frel, _ := filepath.Rel(srcDir, fpath)

	// Try to find meta file
	fmeta := fpath + "-meta.xml"
	fmetarel := ""
	if _, err := os.Stat(fmeta); err != nil {
		if os.IsNotExist(err) {
			hasMeta = false
		} else {
			ErrorAndExit("Cound not open " + fmeta)
		}
	} else {
		// Should be present since we worked back to srcDir
		fmetarel, _ = filepath.Rel(srcDir, fmeta)
	}

	xmlMap[metaType] = append(xmlMap[metaType], fname)

	fdata, err := ioutil.ReadFile(fpath)
	files[frel] = fdata
	if hasMeta {
		fdata, err = ioutil.ReadFile(fmeta)
		files[fmetarel] = fdata
	}
}

func buildXml(xmlMap map[string][]string) []byte {
	p := createPackage()

	for metaType, members := range xmlMap {
		t := MetaType{Name: metaType}
		for _, member := range members {
			t.Members = append(t.Members, member)
		}
		p.Types = append(p.Types, t)
	}

	byteXml, _ := xml.MarshalIndent(p, "", "    ")
	byteXml = append([]byte(xml.Header), byteXml...)

	return byteXml
}

func deployFiles(files ForceMetadataFiles) {
	force, _ := ActiveForce()
	var DeploymentOptions ForceDeployOptions
	successes, problems, err := force.Metadata.Deploy(files, DeploymentOptions)
	if err != nil {
		ErrorAndExit(err.Error())
	}
	fmt.Printf("\nFailures - %d\n", len(problems))
	for _, problem := range problems {
		if problem.FullName == "" {
			fmt.Println(problem.Problem)
		} else {
			fmt.Printf("ERROR with %s:\n %s\n", problem.FullName, problem.Problem)
		}
	}

	fmt.Printf("\nSuccesses - %d\n", len(successes) - 1)
	for _, success := range successes {
		if success.FullName != "package.xml" {
			verb := "unchanged"
			if success.Changed {
				verb = "changed"
			} else if success.Deleted {
				verb = "deleted"
			} else if success.Created {
				verb = "created"
			}
			fmt.Printf("%s\n\tstatus: %s\n\tid=%s\n", success.FullName, verb, success.Id)
		}
	}
}
<|endoftext|>