<commit_before>package dispatch

import (
	"errors"
	"github.com/deafbybeheading/femebe/message"
	"net"
	"sync"
)

type Scaffolding struct {
	HandleConnection(net.Conn)
}

type SessionManager interface {
	RunSession(session Session) error
	Cancel(backendPid, secretKey int32) error
}

type BackendKeyHolder interface {
	// Identifies this session, as per the FEBE protocol.
	// If this information is not yet available when this
	// method is called, or the router does not support
	// cancellation, it should return (-1, -1).
	BackendKeyData() (int32, int32)
}

// A Router moves protocol messages from the frontend to the backend
// (and vice versa). It is also responsible
type Router interface {
	BackendKeyHolder
	// Route the next message from the frontend
	RouteFrontend() error
	// Route the next message from the bcakend
	RouteBackend() error
}

type Resolver interface {
	// Resolve a given startup message into a Connector that can be
	// used to connect to or send cancellations to the given backend
	Resolve(params map[string]string) Connector
}

type Canceller interface {
	// Open a stream to a backend and send a cancellation
	// request with the given data, the close the stream.
	Cancel(backendPid, secretKey int32) error
}

type Connector interface {
	Canceller
	// Open a stream to a backend, go through TLS negotiation (if
	// desired), and send a StartupMessage on that stream before
	// returning it. Return an error if a stream cannot be
	// established or if sending the startup packet returns an
	// error
	Startup() (Stream, error)
}

type Session interface {
	BackendKeyHolder
	Canceller
	Run() error
}

type SessionError struct {
	error
	Session Session
}

type simpleSessionManager struct {
	sessions []Session
	sessionLock sync.Mutex
}

// and...
func (s *simpleSessionManager) RunSession(session Session) error {
	s.sessionLock.Lock()
	s.sessions = append(s.sessions, session)
	s.sessionLock.Unlock()

	// N.B.: this is a blocking call that will not return until
	// the session completes
	err := session.Run()
	s.sessionLock.Lock()
	for i, si := range s.sessions {
		if si == session {
			// slice out this session
			copy(s.sessions[i:], s.sessions[i+1:])
			s.sessions[len(s.sessions)-1] = nil
			s.sessions = s.sessions[:len(s.sessions)-1]
			break
		}
	}
	s.sessionLock.Unlock()
	return err
}

func (s *simpleSessionManager) Cancel(backendPid, secretKey int32) error {
	for _, session := range s.sessions {
		// TODO: we could cache this info once available, but
		// for a reasonably small number of sessions, there's
		// probably no point
		if p, k := session.BackendKeyData(); p == backendPid && k == secretKey  {
			s.sessionLock.Lock()
			defer s.sessionLock.Lock()
			return session.Cancel(backendPid, secretKey)
		}
	}
	return errors.New("not found")
}

type SimpleConnector struct {
	backendAddr string
	startupMessage Message
	cancelMessage Message
}

func NewSimpleConnector(target string, options map[string]string) (Connector, error) {
	c := &SimpleConnector{backendAddr: target}
	message.InitStartupMessage(&c.startupMessage)
	return c
}

func (c *SimpleConnector) dial() (Stream, error) {
	conn, err := net.Dial(backendAddr)
	if err != nil {
		return err
	}
	return NewBackendStream(conn)
}

func (c *SimpleConnector) Startup() (Stream, error) {
	beStream, err := c.dial()
	if err != nil {
		return nil, err
	}
	err := beStream.Send(&c.startupMessage)
	if err != nil {
		return nil, err
	}
	return beStream, nil
}

func (c *SimpleConnector) Cancel(backendPid, secreteKey int32) error {
	beStream, err := c.dial()
	if err != nil {
		return err
	}
	err := femebe.InitCancel(&c.cancelMessage, backendPid, secretKey)
	if err != nil {
		return err
	}
	err = beStream.Send(&c.cancelMessage)
	if err != nil {
		return err
	}

}

type simpleRouter struct {
	backendPid int32
	backendKeyData int32
	from Stream
	to Stream
	feBuf Message
	beBuf Message
}

func NewSimpleRouter(from, to Stream) Router {
	return &simpleRouter{
		backendPid: -1,
		backendKeyData: -1,
		from: from,
		to: to,
	}
}

func (s *simpleRouter) BackendKeyData() (int32, int32) {
	return s.backendPid, s.backendKeyData
}

// route the next message from frontend to backend,
// blocking and flushing if necessary
func (s *simpleRouter) RouteFrontend() (err error) {
	err = from.Next(&s.feBuf)
	if err != nil {
		return
	}
	err = to.Send(&s.feBuf)
	if err != nil {
		return
	}
	if !from.HasNext() {
		return to.Flush()
	}
	return
}

// route the next message from backend to frotnend,
// blocking and flushing if necessary
func (s *simpleRouter) RouteBackend() error {
	err = from.Next(&s.beBuf)
	if err != nil {
		return
	}
	if message.IsBackendKeyData(&s.beBuf) {
		beInfo, err := message.ReadBackendKeyData(&s.beBuf)
		if err != nil {
			return
		}
		s.BackendPid = beInfo.BackendPid
		s.BackendKeyData = beInfo.BackendKeyData
	}
	err = to.Send(&m)
	if !from.HasNext() {
		return to.Flush()
	}
}

type simpleSession struct {
	router Router
	Canceller
}

func NewSimpleSession(r Router, c Canceller) Session {
	return &simpleSession{r, c}
}

func (s *simpleSession) Run() (err error) {
	errs := make(chan error, 2)
	routeFrontend := func() { errToChannel(s.router.routeFrotend, errs) }
	routeBackend := func() { errToChannel(s.router.routeBackend, errs) }
	go routeFrontend()
	go routeBackend()
	err = <- errs
	// N.B.: we ignore the second error entirely, but we do wait
	// for it to ensure the session is fully cleaned up before we
	// exit
	_ = <- errs
	return
}
<commit_msg>Doc touchup<commit_after>package dispatch

import (
	"errors"
	"github.com/deafbybeheading/femebe/message"
	"net"
	"sync"
)

type Scaffolding struct {
	HandleConnection(net.Conn)
}

type SessionManager interface {
	RunSession(session Session) error
	Cancel(backendPid, secretKey int32) error
}

type BackendKeyHolder interface {
	// Identifies this session, as per the FEBE protocol.
	// If this information is not yet available when this
	// method is called, or the router does not support
	// cancellation, it should return (-1, -1).
	BackendKeyData() (int32, int32)
}

// A Router moves protocol messages from the frontend to the backend
// (and vice versa). It is also responsible
type Router interface {
	BackendKeyHolder
	// Route the next message from the frontend
	RouteFrontend() error
	// Route the next message from the bcakend
	RouteBackend() error
}

type Resolver interface {
	// Resolve a given startup message into a Connector that can be
	// used to connect to or send cancellations to the given backend
	Resolve(params map[string]string) Connector
}

// Can send (or delegate) a Postgres CancelRequest message. Should
// return an error if it knows that the request will not succeed. Note
// that due to the nature of the cancellation mechanism, there is no
// guarantee of success, so the absence of an error does not
// necessarily mean success.
type Canceller interface {
	// Open a stream to a backend and send a cancellation
	// request with the given data, the close the stream.
	Cancel(backendPid, secretKey int32) error
}

type Connector interface {
	Canceller
	// Open a stream to a backend, go through TLS negotiation (if
	// desired), and send a StartupMessage on that stream before
	// returning it. Return an error if a stream cannot be
	// established or if sending the startup packet returns an
	// error
	Startup() (Stream, error)
}

type Session interface {
	BackendKeyHolder
	Canceller
	Run() error
}

type SessionError struct {
	error
	Session Session
}

type simpleSessionManager struct {
	sessions []Session
	sessionLock sync.Mutex
}

func (s *simpleSessionManager) RunSession(session Session) error {
	s.sessionLock.Lock()
	s.sessions = append(s.sessions, session)
	s.sessionLock.Unlock()

	// N.B.: this is a blocking call that will not return until
	// the session completes
	err := session.Run()
	s.sessionLock.Lock()
	for i, si := range s.sessions {
		if si == session {
			// slice out this session
			copy(s.sessions[i:], s.sessions[i+1:])
			s.sessions[len(s.sessions)-1] = nil
			s.sessions = s.sessions[:len(s.sessions)-1]
			break
		}
	}
	s.sessionLock.Unlock()
	return err
}

func (s *simpleSessionManager) Cancel(backendPid, secretKey int32) error {
	for _, session := range s.sessions {
		// TODO: we could cache this info once available, but
		// for a reasonably small number of sessions, there's
		// probably no point
		if p, k := session.BackendKeyData(); p == backendPid && k == secretKey  {
			s.sessionLock.Lock()
			defer s.sessionLock.Lock()
			return session.Cancel(backendPid, secretKey)
		}
	}
	return errors.New("not found")
}

type SimpleConnector struct {
	backendAddr string
	startupMessage Message
	cancelMessage Message
}

func NewSimpleConnector(target string, options map[string]string) (Connector, error) {
	c := &SimpleConnector{backendAddr: target}
	message.InitStartupMessage(&c.startupMessage)
	return c
}

func (c *SimpleConnector) dial() (Stream, error) {
	conn, err := net.Dial(backendAddr)
	if err != nil {
		return err
	}
	return NewBackendStream(conn)
}

func (c *SimpleConnector) Startup() (Stream, error) {
	beStream, err := c.dial()
	if err != nil {
		return nil, err
	}
	err := beStream.Send(&c.startupMessage)
	if err != nil {
		return nil, err
	}
	return beStream, nil
}

func (c *SimpleConnector) Cancel(backendPid, secreteKey int32) error {
	beStream, err := c.dial()
	if err != nil {
		return err
	}
	err := femebe.InitCancel(&c.cancelMessage, backendPid, secretKey)
	if err != nil {
		return err
	}
	err = beStream.Send(&c.cancelMessage)
	if err != nil {
		return err
	}

}

type simpleRouter struct {
	backendPid int32
	backendKeyData int32
	from Stream
	to Stream
	feBuf Message
	beBuf Message
}

func NewSimpleRouter(from, to Stream) Router {
	return &simpleRouter{
		backendPid: -1,
		backendKeyData: -1,
		from: from,
		to: to,
	}
}

func (s *simpleRouter) BackendKeyData() (int32, int32) {
	return s.backendPid, s.backendKeyData
}

// route the next message from frontend to backend,
// blocking and flushing if necessary
func (s *simpleRouter) RouteFrontend() (err error) {
	err = from.Next(&s.feBuf)
	if err != nil {
		return
	}
	err = to.Send(&s.feBuf)
	if err != nil {
		return
	}
	if !from.HasNext() {
		return to.Flush()
	}
	return
}

// route the next message from backend to frotnend,
// blocking and flushing if necessary
func (s *simpleRouter) RouteBackend() error {
	err = from.Next(&s.beBuf)
	if err != nil {
		return
	}
	if message.IsBackendKeyData(&s.beBuf) {
		beInfo, err := message.ReadBackendKeyData(&s.beBuf)
		if err != nil {
			return
		}
		s.BackendPid = beInfo.BackendPid
		s.BackendKeyData = beInfo.BackendKeyData
	}
	err = to.Send(&m)
	if !from.HasNext() {
		return to.Flush()
	}
}

type simpleSession struct {
	router Router
	Canceller
}

func NewSimpleSession(r Router, c Canceller) Session {
	return &simpleSession{r, c}
}

func (s *simpleSession) Run() (err error) {
	errs := make(chan error, 2)
	routeFrontend := func() { errToChannel(s.router.routeFrotend, errs) }
	routeBackend := func() { errToChannel(s.router.routeBackend, errs) }
	go routeFrontend()
	go routeBackend()
	err = <- errs
	// N.B.: we ignore the second error entirely, but we do wait
	// for it to ensure the session is fully cleaned up before we
	// exit
	_ = <- errs
	return
}
<|endoftext|>


<commit_before>package adoc

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

type AuthConfig struct {
	UserName string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`
	Email    string `json:"email,omitempty"`
}

func (auth AuthConfig) Encode() string {
	var buffer bytes.Buffer
	json.NewEncoder(&buffer).Encode(auth)
	return base64.URLEncoding.EncodeToString(buffer.Bytes())
}

type Error struct {
	StatusCode int
	Status     string
}

func (e Error) Error() string {
	return fmt.Sprintf("%d: %s", e.StatusCode, e.Status)
}

const (
	kDefaultApiVersion = "v1.17"
	kDefaultTimeout    = 30
)

var apiVersions = map[string]bool{
	"v1.17": true,
	"v1.18": true,
}

type DockerClient struct {
	daemonUrl  *url.URL
	httpClient *http.Client
	tlsConfig  *tls.Config
	apiVersion string
	isSwarm    bool

	monitorLock sync.RWMutex
	monitors    map[int64]struct{}
}

func NewSwarmClient(swarmUrl string, tlsConfig *tls.Config, apiVersion ...string) (*DockerClient, error) {
	return NewSwarmClientTimeout(swarmUrl, tlsConfig, time.Duration(kDefaultTimeout*time.Second), apiVersion...)
}

func NewSwarmClientTimeout(swarmUrl string, tlsConfig *tls.Config, timeout time.Duration, apiVersion ...string) (*DockerClient, error) {
	docker, err := NewDockerClientTimeout(swarmUrl, tlsConfig, timeout, apiVersion...)
	docker.isSwarm = true
	return docker, err
}

func NewDockerClient(daemonUrl string, tlsConfig *tls.Config, apiVersion ...string) (*DockerClient, error) {
	return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(kDefaultTimeout*time.Second), apiVersion...)
}

func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, apiVersion ...string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "" || u.Scheme == "tcp" {
		if tlsConfig == nil {
			u.Scheme = "http"
		} else {
			u.Scheme = "https"
		}
	}
	httpClient := newHttpClient(u, tlsConfig, timeout)
	clientApiVersion := kDefaultApiVersion
	if len(apiVersion) > 0 && apiVersion[0] != "" {
		clientApiVersion = apiVersion[0]
		if !strings.HasPrefix(clientApiVersion, "v") {
			clientApiVersion = "v" + clientApiVersion
		}
	}
	if _, checked := apiVersions[clientApiVersion]; !checked {
		err = fmt.Errorf("*WARNING: Adoc haven't check out if the remote api version %s is supported, maybe not stable, but you can keep using the client anyway.", clientApiVersion)
	}
	return &DockerClient{
		daemonUrl:  u,
		httpClient: httpClient,
		tlsConfig:  tlsConfig,
		apiVersion: clientApiVersion,
		monitors:   make(map[int64]struct{}),
	}, err
}

type responseCallback func(resp *http.Response) error

func (client *DockerClient) sendRequestCallback(method string, path string, body []byte, headers map[string]string, callback responseCallback) error {
	b := bytes.NewBuffer(body)
	urlPath := fmt.Sprintf("%s/%s/%s", client.daemonUrl.String(), client.apiVersion, path)
	logger.Debugf("SendRequest %q, [%s]", method, urlPath)
	req, err := http.NewRequest(method, urlPath, b)
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")
	if headers != nil {
		for key, value := range headers {
			req.Header.Add(key, value)
		}
	}
	resp, err := client.httpClient.Do(req)
	if err != nil {
		if !strings.Contains(err.Error(), "connection refused") && client.tlsConfig == nil {
			return fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
		}
		return err
	}
	if resp.StatusCode >= 400 {
		return Error{resp.StatusCode, resp.Status}
	}

	defer resp.Body.Close()
	return callback(resp)
}

func (client *DockerClient) sendRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
	var data []byte
	err := client.sendRequestCallback(method, path, body, headers, func(resp *http.Response) error {
		var cbErr error
		if data, cbErr = ioutil.ReadAll(resp.Body); cbErr != nil {
			return cbErr
		}
		return nil
	})
	return data, err
}

// This part contains the misc apis listed in
// https://docs.docker.com/reference/api/docker_remote_api_v1.17/#23-misc

type Version struct {
	ApiVersion    string
	GitCommit     string
	GoVersion     string
	Version       string
	Os            string // v1.18
	Arch          string // v1.18
	KernelVersion string // v1.18
}

type DockerInfo struct {
	Containers         int64
	DockerRootDir      string
	Driver             string
	DriverStatus       [][2]string
	ExecutionDriver    string
	ID                 string
	IPv4Forwarding     int
	Images             int64
	IndexServerAddress string
	InitPath           string
	InitSha1           string
	KernelVersion      string
	Labels             []string
	MemTotal           int64
	MemoryLimit        int
	NCPU               int64
	NEventsListener    int64
	NFd                int64
	NGoroutines        int64
	Name               string
	OperatingSystem    string
	SwapLimit          int
	HttpProxy          string    // v1.18
	HttpsProxy         string    // v1.18
	NoProxy            string    // v1.18
	SystemTime         time.Time // v1.18
	//Debug              bool // this will conflict with docker api and swarm api, fuck
}

func (client *DockerClient) Version() (Version, error) {
	var ret Version
	if data, err := client.sendRequest("GET", "version", nil, nil); err != nil {
		return Version{}, err
	} else {
		err := json.Unmarshal(data, &ret)
		return ret, err
	}
}

func (client *DockerClient) Info() (DockerInfo, error) {
	var ret DockerInfo
	if data, err := client.sendRequest("GET", "info", nil, nil); err != nil {
		return ret, err
	} else {
		err := json.Unmarshal(data, &ret)
		return ret, err
	}
}

func (client *DockerClient) Ping() (bool, error) {
	if data, err := client.sendRequest("GET", "_ping", nil, nil); err != nil {
		return false, err
	} else {
		return string(data) == "OK", nil
	}
}

// Missing apis for
// auth
// commit: Create a new image from a container's changes
// events: Monitor Docker's events
// images/(name)/get: Get a tarball containing all images in a repository
// images/get: Get a tarball containing all images.
// images/load: Load a tarball with a set of images and tags into docker
// containers/(id)/exec: Exec Create
// exec/(id)/start: Exec Start
// exec/(id)/resize
// exec/(id)/json

var random *rand.Rand

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}
<commit_msg>Adding IsNotFound and IsServerInternalError<commit_after>package adoc

import (
	"bytes"
	"crypto/tls"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"math/rand"
	"net/http"
	"net/url"
	"strings"
	"sync"
	"time"
)

type AuthConfig struct {
	UserName string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`
	Email    string `json:"email,omitempty"`
}

func (auth AuthConfig) Encode() string {
	var buffer bytes.Buffer
	json.NewEncoder(&buffer).Encode(auth)
	return base64.URLEncoding.EncodeToString(buffer.Bytes())
}

type Error struct {
	StatusCode int
	Status     string
}

func (e Error) Error() string {
	return fmt.Sprintf("%d: %s", e.StatusCode, e.Status)
}

func IsNotFound(err error) bool {
	if adocErr, ok := err.(Error); ok {
		return adocErr.StatusCode == 404
	}
	return false
}

func IsServerInternalError(err error) bool {
	if adocErr, ok := err.(Error); ok {
		return adocErr.StatusCode == 500
	}
	return false
}

const (
	kDefaultApiVersion = "v1.17"
	kDefaultTimeout    = 30
)

var apiVersions = map[string]bool{
	"v1.17": true,
	"v1.18": true,
}

type DockerClient struct {
	daemonUrl  *url.URL
	httpClient *http.Client
	tlsConfig  *tls.Config
	apiVersion string
	isSwarm    bool

	monitorLock sync.RWMutex
	monitors    map[int64]struct{}
}

func NewSwarmClient(swarmUrl string, tlsConfig *tls.Config, apiVersion ...string) (*DockerClient, error) {
	return NewSwarmClientTimeout(swarmUrl, tlsConfig, time.Duration(kDefaultTimeout*time.Second), apiVersion...)
}

func NewSwarmClientTimeout(swarmUrl string, tlsConfig *tls.Config, timeout time.Duration, apiVersion ...string) (*DockerClient, error) {
	docker, err := NewDockerClientTimeout(swarmUrl, tlsConfig, timeout, apiVersion...)
	docker.isSwarm = true
	return docker, err
}

func NewDockerClient(daemonUrl string, tlsConfig *tls.Config, apiVersion ...string) (*DockerClient, error) {
	return NewDockerClientTimeout(daemonUrl, tlsConfig, time.Duration(kDefaultTimeout*time.Second), apiVersion...)
}

func NewDockerClientTimeout(daemonUrl string, tlsConfig *tls.Config, timeout time.Duration, apiVersion ...string) (*DockerClient, error) {
	u, err := url.Parse(daemonUrl)
	if err != nil {
		return nil, err
	}
	if u.Scheme == "" || u.Scheme == "tcp" {
		if tlsConfig == nil {
			u.Scheme = "http"
		} else {
			u.Scheme = "https"
		}
	}
	httpClient := newHttpClient(u, tlsConfig, timeout)
	clientApiVersion := kDefaultApiVersion
	if len(apiVersion) > 0 && apiVersion[0] != "" {
		clientApiVersion = apiVersion[0]
		if !strings.HasPrefix(clientApiVersion, "v") {
			clientApiVersion = "v" + clientApiVersion
		}
	}
	if _, checked := apiVersions[clientApiVersion]; !checked {
		err = fmt.Errorf("*WARNING: Adoc haven't check out if the remote api version %s is supported, maybe not stable, but you can keep using the client anyway.", clientApiVersion)
	}
	return &DockerClient{
		daemonUrl:  u,
		httpClient: httpClient,
		tlsConfig:  tlsConfig,
		apiVersion: clientApiVersion,
		monitors:   make(map[int64]struct{}),
	}, err
}

type responseCallback func(resp *http.Response) error

func (client *DockerClient) sendRequestCallback(method string, path string, body []byte, headers map[string]string, callback responseCallback) error {
	b := bytes.NewBuffer(body)
	urlPath := fmt.Sprintf("%s/%s/%s", client.daemonUrl.String(), client.apiVersion, path)
	logger.Debugf("SendRequest %q, [%s]", method, urlPath)
	req, err := http.NewRequest(method, urlPath, b)
	if err != nil {
		return err
	}
	req.Header.Add("Content-Type", "application/json")
	if headers != nil {
		for key, value := range headers {
			req.Header.Add(key, value)
		}
	}
	resp, err := client.httpClient.Do(req)
	if err != nil {
		if !strings.Contains(err.Error(), "connection refused") && client.tlsConfig == nil {
			return fmt.Errorf("%v. Are you trying to connect to a TLS-enabled daemon without TLS?", err)
		}
		return err
	}
	if resp.StatusCode >= 400 {
		return Error{resp.StatusCode, resp.Status}
	}

	defer resp.Body.Close()
	return callback(resp)
}

func (client *DockerClient) sendRequest(method string, path string, body []byte, headers map[string]string) ([]byte, error) {
	var data []byte
	err := client.sendRequestCallback(method, path, body, headers, func(resp *http.Response) error {
		var cbErr error
		if data, cbErr = ioutil.ReadAll(resp.Body); cbErr != nil {
			return cbErr
		}
		return nil
	})
	return data, err
}

// This part contains the misc apis listed in
// https://docs.docker.com/reference/api/docker_remote_api_v1.17/#23-misc

type Version struct {
	ApiVersion    string
	GitCommit     string
	GoVersion     string
	Version       string
	Os            string // v1.18
	Arch          string // v1.18
	KernelVersion string // v1.18
}

type DockerInfo struct {
	Containers         int64
	DockerRootDir      string
	Driver             string
	DriverStatus       [][2]string
	ExecutionDriver    string
	ID                 string
	IPv4Forwarding     int
	Images             int64
	IndexServerAddress string
	InitPath           string
	InitSha1           string
	KernelVersion      string
	Labels             []string
	MemTotal           int64
	MemoryLimit        int
	NCPU               int64
	NEventsListener    int64
	NFd                int64
	NGoroutines        int64
	Name               string
	OperatingSystem    string
	SwapLimit          int
	HttpProxy          string    // v1.18
	HttpsProxy         string    // v1.18
	NoProxy            string    // v1.18
	SystemTime         time.Time // v1.18
	//Debug              bool // this will conflict with docker api and swarm api, fuck
}

func (client *DockerClient) Version() (Version, error) {
	var ret Version
	if data, err := client.sendRequest("GET", "version", nil, nil); err != nil {
		return Version{}, err
	} else {
		err := json.Unmarshal(data, &ret)
		return ret, err
	}
}

func (client *DockerClient) Info() (DockerInfo, error) {
	var ret DockerInfo
	if data, err := client.sendRequest("GET", "info", nil, nil); err != nil {
		return ret, err
	} else {
		err := json.Unmarshal(data, &ret)
		return ret, err
	}
}

func (client *DockerClient) Ping() (bool, error) {
	if data, err := client.sendRequest("GET", "_ping", nil, nil); err != nil {
		return false, err
	} else {
		return string(data) == "OK", nil
	}
}

// Missing apis for
// auth
// commit: Create a new image from a container's changes
// events: Monitor Docker's events
// images/(name)/get: Get a tarball containing all images in a repository
// images/get: Get a tarball containing all images.
// images/load: Load a tarball with a set of images and tags into docker
// containers/(id)/exec: Exec Create
// exec/(id)/start: Exec Start
// exec/(id)/resize
// exec/(id)/json

var random *rand.Rand

func init() {
	random = rand.New(rand.NewSource(time.Now().UnixNano()))
}
<|endoftext|>


<commit_before>package apns

import (
	"crypto/tls"
	"errors"
	"net"
	"time"
)

// Client contains the fields necessary to communicate
// with Apple, such as the gateway to use and your
// certificate contents.
//
// You'll need to provide your own CertificateFile
// and KeyFile to send notifications. Ideally, you'll
// just set the CertificateFile and KeyFile fields to
// a location on drive where the certs can be loaded,
// but if you prefer you can use the CertificateBase64
// and KeyBase64 fields to store the actual contents.
type Client struct {
	Gateway           string
	CertificateFile   string
	CertificateBase64 string
	KeyFile           string
	KeyBase64         string
	Certificate       tls.Certificate
}

// BareClient can be used to set the contents of your
// certificate and key blocks manually.
func BareClient(gateway, certificateBase64, keyBase64 string) (c *Client) {
	c = new(Client)
	c.Gateway = gateway
	c.CertificateBase64 = certificateBase64
	c.KeyBase64 = keyBase64
	return
}

// NewClient assumes you'll be passing in paths that
// point to your certificate and key.
func NewClient(gateway, certificateFile, keyFile string) (c *Client) {
	c = new(Client)
	c.Gateway = gateway
	c.CertificateFile = certificateFile
	c.KeyFile = keyFile
	return
}

// Send connects to the APN service and sends your push notification.
// Remember that if the submission is successful, Apple won't reply.
func (client *Client) Send(pn *PushNotification) (resp *PushNotificationResponse) {
	resp = new(PushNotificationResponse)

	payload, err := pn.ToBytes()
	if err != nil {
		resp.Success = false
		resp.Error = err
		return
	}

	err = client.ConnectAndWrite(resp, payload)
	if err != nil {
		resp.Success = false
		resp.Error = err
		return
	}

	resp.Success = true
	resp.Error = nil

	return
}

// ConnectAndWrite establishes the connection to Apple and handles the
// transmission of your push notification, as well as waiting for a reply.
//
// In lieu of a timeout (which would be available in Go 1.1)
// we use a timeout channel pattern instead. We start two goroutines,
// one of which just sleeps for TimeoutSeconds seconds, while the other
// waits for a response from the Apple servers.
//
// Whichever channel puts data on first is the "winner". As such, it's
// possible to get a false positive if Apple takes a long time to respond.
// It's probably not a deal-breaker, but something to be aware of.
func (client *Client) ConnectAndWrite(resp *PushNotificationResponse, payload []byte) (err error) {
	cert, err := client.getCertificate()

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	conn, err := net.Dial("tcp", client.Gateway)
	if err != nil {
		return err
	}
	defer conn.Close()

	tlsConn := tls.Client(conn, conf)
	err = tlsConn.Handshake()
	if err != nil {
		return err
	}
	defer tlsConn.Close()

	_, err = tlsConn.Write(payload)
	if err != nil {
		return err
	}

	// Create one channel that will serve to handle
	// timeouts when the notification succeeds.
	timeoutChannel := make(chan bool, 1)
	go func() {
		time.Sleep(time.Second * TimeoutSeconds)
		timeoutChannel <- true
	}()

	// This channel will contain the binary response
	// from Apple in the event of a failure.
	responseChannel := make(chan []byte, 1)
	go func() {
		buffer := make([]byte, 6, 6)
		tlsConn.Read(buffer)
		responseChannel <- buffer
	}()

	// First one back wins!
	// The data structure for an APN response is as follows:
	//
	// command    -> 1 byte
	// status     -> 1 byte
	// identifier -> 4 bytes
	//
	// The first byte will always be set to 8.
	select {
	case r := <-responseChannel:
		resp.Success = false
		resp.AppleResponse = ApplePushResponses[r[1]]
		err = errors.New(resp.AppleResponse)
	case <-timeoutChannel:
		resp.Success = true
	}

	return err
}

// Returns a certificate to use to send the notification.
// The certificate is only created once to save on
// the overhead of the crypto libraries.
func (client *Client) getCertificate() (tls.Certificate, error) {
	var err error
	if &client.Certificate == nil {
		if len(client.CertificateBase64) == 0 && len(client.KeyBase64) == 0 {
			// The user did not specify raw block contents, so check the filesystem.
			client.Certificate, err = tls.LoadX509KeyPair(client.CertificateFile, client.KeyFile)
		} else {
			// The user provided the raw block contents, so use that.
			client.Certificate, err = tls.X509KeyPair([]byte(client.CertificateBase64), []byte(client.KeyBase64))
		}
	}

	return client.Certificate, err
}
<commit_msg>Check for the private key as the certificate may already exist<commit_after>package apns

import (
	"crypto/tls"
	"errors"
	"net"
	"time"
)

// Client contains the fields necessary to communicate
// with Apple, such as the gateway to use and your
// certificate contents.
//
// You'll need to provide your own CertificateFile
// and KeyFile to send notifications. Ideally, you'll
// just set the CertificateFile and KeyFile fields to
// a location on drive where the certs can be loaded,
// but if you prefer you can use the CertificateBase64
// and KeyBase64 fields to store the actual contents.
type Client struct {
	Gateway           string
	CertificateFile   string
	CertificateBase64 string
	KeyFile           string
	KeyBase64         string
	Certificate       tls.Certificate
}

// BareClient can be used to set the contents of your
// certificate and key blocks manually.
func BareClient(gateway, certificateBase64, keyBase64 string) (c *Client) {
	c = new(Client)
	c.Gateway = gateway
	c.CertificateBase64 = certificateBase64
	c.KeyBase64 = keyBase64
	return
}

// NewClient assumes you'll be passing in paths that
// point to your certificate and key.
func NewClient(gateway, certificateFile, keyFile string) (c *Client) {
	c = new(Client)
	c.Gateway = gateway
	c.CertificateFile = certificateFile
	c.KeyFile = keyFile
	return
}

// Send connects to the APN service and sends your push notification.
// Remember that if the submission is successful, Apple won't reply.
func (client *Client) Send(pn *PushNotification) (resp *PushNotificationResponse) {
	resp = new(PushNotificationResponse)

	payload, err := pn.ToBytes()
	if err != nil {
		resp.Success = false
		resp.Error = err
		return
	}

	err = client.ConnectAndWrite(resp, payload)
	if err != nil {
		resp.Success = false
		resp.Error = err
		return
	}

	resp.Success = true
	resp.Error = nil

	return
}

// ConnectAndWrite establishes the connection to Apple and handles the
// transmission of your push notification, as well as waiting for a reply.
//
// In lieu of a timeout (which would be available in Go 1.1)
// we use a timeout channel pattern instead. We start two goroutines,
// one of which just sleeps for TimeoutSeconds seconds, while the other
// waits for a response from the Apple servers.
//
// Whichever channel puts data on first is the "winner". As such, it's
// possible to get a false positive if Apple takes a long time to respond.
// It's probably not a deal-breaker, but something to be aware of.
func (client *Client) ConnectAndWrite(resp *PushNotificationResponse, payload []byte) (err error) {
	cert, err := client.getCertificate()

	if err != nil {
		return err
	}

	conf := &tls.Config{
		Certificates: []tls.Certificate{cert},
	}

	conn, err := net.Dial("tcp", client.Gateway)
	if err != nil {
		return err
	}
	defer conn.Close()

	tlsConn := tls.Client(conn, conf)
	err = tlsConn.Handshake()
	if err != nil {
		return err
	}
	defer tlsConn.Close()

	_, err = tlsConn.Write(payload)
	if err != nil {
		return err
	}

	// Create one channel that will serve to handle
	// timeouts when the notification succeeds.
	timeoutChannel := make(chan bool, 1)
	go func() {
		time.Sleep(time.Second * TimeoutSeconds)
		timeoutChannel <- true
	}()

	// This channel will contain the binary response
	// from Apple in the event of a failure.
	responseChannel := make(chan []byte, 1)
	go func() {
		buffer := make([]byte, 6, 6)
		tlsConn.Read(buffer)
		responseChannel <- buffer
	}()

	// First one back wins!
	// The data structure for an APN response is as follows:
	//
	// command    -> 1 byte
	// status     -> 1 byte
	// identifier -> 4 bytes
	//
	// The first byte will always be set to 8.
	select {
	case r := <-responseChannel:
		resp.Success = false
		resp.AppleResponse = ApplePushResponses[r[1]]
		err = errors.New(resp.AppleResponse)
	case <-timeoutChannel:
		resp.Success = true
	}

	return err
}

// Returns a certificate to use to send the notification.
// The certificate is only created once to save on
// the overhead of the crypto libraries.
func (client *Client) getCertificate() (tls.Certificate, error) {
	var err error
	if client.Certificate.PrivateKey == nil {
		if len(client.CertificateBase64) == 0 && len(client.KeyBase64) == 0 {
			// The user did not specify raw block contents, so check the filesystem.
			client.Certificate, err = tls.LoadX509KeyPair(client.CertificateFile, client.KeyFile)
		} else {
			// The user provided the raw block contents, so use that.
			client.Certificate, err = tls.X509KeyPair([]byte(client.CertificateBase64), []byte(client.KeyBase64))
		}
	}

	return client.Certificate, err
}
<|endoftext|>


<commit_before>package dynago

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"net/http"
)

const DynamoTargetPrefix = "DynamoDB_20120810." // This is the Dynamo API version we support

func NewClient(prefix string, region string, accessKey string, secretKey string) *Client {
	return &Client{
		endpoint: prefix,
		aws: AWSInfo{
			Region:    region,
			AccessKey: accessKey,
			SecretKey: secretKey,
			Service:   "dynamodb",
		},
	}
}

type Client struct {
	caller   http.Client
	endpoint string
	aws      AWSInfo
}

func (c *Client) makeRequest(target string, document interface{}) ([]byte, error) {
	buf, err := json.Marshal(document)
	log.Printf("Request Body: \n%s\n\n", buf)
	if err != nil {
		return nil, err
	}
	body := bytes.NewBuffer(buf)
	req, err := http.NewRequest("POST", c.endpoint, body)
	if err != nil {
		return nil, err
	}
	req.Header.Add("x-amz-target", DynamoTargetPrefix+target)
	req.Header.Add("content-type", "application/x-amz-json-1.0")
	req.Header.Set("Host", req.URL.Host)
	c.aws.signRequest(req, buf)
	response, err := c.caller.Do(req)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != http.StatusOK {
		resp := make([]byte, response.ContentLength)
		response.Body.Read(resp)
		log.Printf(" Another Status %d \n%#v\n\n%#v\n\n%s", response.StatusCode, req, response, resp)
	}
	return responseBytes(response)
}

func (c *Client) makeRequestUnmarshal(method string, document interface{}, dest interface{}) (err error) {
	body, err := c.makeRequest(method, document)
	if err != nil {
		return
	}
	err = json.Unmarshal(body, dest)
	return
}

/*
Return a Table object representing a table in dynamodb.
*/
func (c *Client) Table(tableName string) *Table {
	return &Table{c, tableName}
}

type Table struct {
	client    *Client
	tableName string
}

/*
Compose a GetItem on a dynamo table.

*/
func (c *Client) GetItem(table string, key Document) *GetItem {
	return newGetItem(c, table, key)
}

/*
Compose a Query on a dynamo table.

This returns a new Query struct which you can compose via chaining to build the query you want.

Then finish the chain by calling Execute() to run the query:

	result, err := table.Query().
		FilterExpression("Foo > :val").
		Param(":val", 45).
		Execute()

*/
func (c *Client) Query(table string) *Query {
	return newQuery(c, table)
}

/*
Compose a PutItem on a dynamo table.

item should be a document representing the record and containing the attributes for the primary key.

Like all the other requests, you must call `Execute()` to run this.
*/
func (c *Client) PutItem(table string, item Document) *PutItem {
	return newPutItem(c, table, item)
}

/*
Compose an UpdateItem on a dynamo table.
*/
func (c *Client) UpdateItem(table string, key Document) *UpdateItem {
	return newUpdateItem(c, table, key)
}

func responseBytes(response *http.Response) (buf []byte, err error) {
	if response.ContentLength > 0 {
		buf = make([]byte, response.ContentLength)
		_, err = response.Body.Read(buf)
		if err != nil && err != io.EOF {
			return nil, err
		}
		err = response.Body.Close()
	}
	return
}
<commit_msg>Updated docs, changed basic constructor<commit_after>package dynago

import (
	"bytes"
	"encoding/json"
	"io"
	"log"
	"net/http"
)

const DynamoTargetPrefix = "DynamoDB_20120810." // This is the Dynamo API version we support

/*
Create a new dynamo client.

region is the AWS region, e.g. us-east-1.
accessKey is your amazon access key ID.
secretKey is your amazon secret key ID.
*/
func NewClient(region string, accessKey string, secretKey string) *Client {
	return &Client{
		endpoint: "https://dynamodb." + region + ".amazonaws.com/",
		aws: AWSInfo{
			Region:    region,
			AccessKey: accessKey,
			SecretKey: secretKey,
			Service:   "dynamodb",
		},
	}
}

type Client struct {
	caller   http.Client
	endpoint string
	aws      AWSInfo
}

func (c *Client) makeRequest(target string, document interface{}) ([]byte, error) {
	buf, err := json.Marshal(document)
	log.Printf("Request Body: \n%s\n\n", buf)
	if err != nil {
		return nil, err
	}
	body := bytes.NewBuffer(buf)
	req, err := http.NewRequest("POST", c.endpoint, body)
	if err != nil {
		return nil, err
	}
	req.Header.Add("x-amz-target", DynamoTargetPrefix+target)
	req.Header.Add("content-type", "application/x-amz-json-1.0")
	req.Header.Set("Host", req.URL.Host)
	c.aws.signRequest(req, buf)
	response, err := c.caller.Do(req)
	if err != nil {
		return nil, err
	}
	if response.StatusCode != http.StatusOK {
		resp := make([]byte, response.ContentLength)
		response.Body.Read(resp)
		log.Printf(" Another Status %d \n%#v\n\n%#v\n\n%s", response.StatusCode, req, response, resp)
	}
	return responseBytes(response)
}

func (c *Client) makeRequestUnmarshal(method string, document interface{}, dest interface{}) (err error) {
	body, err := c.makeRequest(method, document)
	if err != nil {
		return
	}
	err = json.Unmarshal(body, dest)
	return
}

/*
Override the endpoint for this client.

Mostly this is for testing and the defaults should suffice in production.
*/
func (c *Client) SetEndpoint(endpoint string) {
	c.endpoint = endpoint
}

/*
Compose a GetItem on a dynamo table.

key should be a Document containing enough attributes to describe the primary key.

You can use the HashKey or HashRangeKey helpers to help build a key:

	client.GetItem("foo", dynago.HashKey("Id", 45))

	client.GetItem("foo", dynago.HashRangeKey("UserId", 45, "Date", "20140512"))
*/
func (c *Client) GetItem(table string, key Document) *GetItem {
	return newGetItem(c, table, key)
}

/*
Compose a Query on a dynamo table.

This returns a new Query struct which you can compose via chaining to build the query you want.

Then finish the chain by calling Execute() to run the query:

	result, err := table.Query().
		FilterExpression("Foo > :val").
		Param(":val", 45).
		Execute()

*/
func (c *Client) Query(table string) *Query {
	return newQuery(c, table)
}

/*
Compose a PutItem on a dynamo table.

item should be a document representing the record and containing the attributes for the primary key.

Like all the other requests, you must call `Execute()` to run this.
*/
func (c *Client) PutItem(table string, item Document) *PutItem {
	return newPutItem(c, table, item)
}

/*
Compose an UpdateItem on a dynamo table.
*/
func (c *Client) UpdateItem(table string, key Document) *UpdateItem {
	return newUpdateItem(c, table, key)
}

func responseBytes(response *http.Response) (buf []byte, err error) {
	if response.ContentLength > 0 {
		buf = make([]byte, response.ContentLength)
		_, err = response.Body.Read(buf)
		if err != nil && err != io.EOF {
			return nil, err
		}
		err = response.Body.Close()
	}
	return
}
<|endoftext|>


<commit_before>package goetty

import (
	"context"
	"errors"
	"io"
	"net"
	"net/url"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"go.uber.org/zap"
)

// NetApplication is a network based application
type NetApplication interface {
	// Start start the transport server
	Start() error
	// Stop stop the transport server
	Stop() error
	// GetSession get session
	GetSession(uint64) (IOSession, error)
	// Broadcast broadcast msg to all sessions
	Broadcast(msg interface{}) error
}

type sessionMap struct {
	sync.RWMutex
	sessions map[uint64]IOSession
}

type server struct {
	id         uint64
	opts       *appOptions
	listener   net.Listener
	closedC    chan struct{}
	sessions   map[uint64]*sessionMap
	handleFunc func(IOSession, interface{}, uint64) error

	mu struct {
		sync.RWMutex
		running bool
	}
}

// NewApplicationWithListener returns a net application with listener
func NewApplicationWithListener(listener net.Listener, handleFunc func(IOSession, interface{}, uint64) error, opts ...AppOption) (NetApplication, error) {
	s := &server{
		listener:   listener,
		handleFunc: handleFunc,
		opts: &appOptions{
			sessionOpts: &options{},
		},
		closedC: make(chan struct{}),
	}

	for _, opt := range opts {
		opt(s.opts)
	}

	s.opts.adjust()
	s.opts.logger = s.opts.logger.With(zap.String("listen-address", listener.Addr().String()))
	s.sessions = make(map[uint64]*sessionMap, s.opts.sessionBucketSize)
	for i := uint64(0); i < s.opts.sessionBucketSize; i++ {
		s.sessions[i] = &sessionMap{
			sessions: make(map[uint64]IOSession),
		}
	}
	return s, nil
}

// NewApplication returns a application
func NewApplication(address string, handleFunc func(IOSession, interface{}, uint64) error, opts ...AppOption) (NetApplication, error) {
	network, address, err := parseAdddress(address)
	if err != nil {
		return nil, err
	}

	listenConfig := &net.ListenConfig{
		Control: listenControl,
	}

	listener, err := listenConfig.Listen(context.TODO(), network, address)
	if err != nil {
		return nil, err
	}

	return NewApplicationWithListener(listener, handleFunc, opts...)
}

func (s *server) Start() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.mu.running {
		return nil
	}

	s.mu.running = true
	go s.doStart()
	s.opts.logger.Info("application started")
	return nil
}

func (s *server) Stop() error {
	s.mu.Lock()
	if !s.mu.running {
		s.mu.Unlock()
		return nil
	}
	s.mu.running = false
	s.mu.Unlock()

	s.listener.Close()
	s.opts.logger.Info("application listener closed")
	<-s.closedC

	// now no new connection will added, close all active sessions
	for _, m := range s.sessions {
		m.Lock()
		for k, rs := range m.sessions {
			delete(m.sessions, k)
			rs.Close()
		}
		m.Unlock()
	}
	s.opts.logger.Info("application stopped")
	return nil
}

func (s *server) GetSession(id uint64) (IOSession, error) {
	if !s.isStarted() {
		return nil, errors.New("server is not started")
	}

	m := s.sessions[id%s.opts.sessionBucketSize]
	m.RLock()
	session := m.sessions[id]
	m.RUnlock()
	return session, nil
}

func (s *server) Broadcast(msg interface{}) error {
	if !s.isStarted() {
		return errors.New("server is not started")
	}

	for _, m := range s.sessions {
		m.RLock()
		for _, rs := range m.sessions {
			rs.Write(msg, WriteOptions{Flush: true})
		}
		m.RUnlock()
	}

	return nil
}

func (s *server) doStart() {
	s.opts.logger.Info("application accept loop started")
	var tempDelay time.Duration
	for {
		conn, err := s.listener.Accept()
		if err != nil {
			if !s.isStarted() {
				s.opts.logger.Info("application accept loop stopped")
				close(s.closedC)
				return
			}

			if ne, ok := err.(net.Error); ok && ne.Timeout() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				time.Sleep(tempDelay)
				continue
			}
			return
		}
		tempDelay = 0

		rs := newBaseIOWithOptions(s.nextID(), conn, s.opts.sessionOpts)
		s.addSession(rs)

		go func() {
			defer func() {
				s.deleteSession(rs)
				rs.Close()
				if s.opts.aware != nil {
					s.opts.aware.Closed(rs)
				}
			}()
			if s.opts.aware != nil {
				s.opts.aware.Created(rs)
			}
			s.doConnection(rs)
		}()
	}
}

func (s *server) doConnection(rs IOSession) error {
	logger := s.opts.logger.With(zap.Uint64("session-id", rs.ID()),
		zap.String("addr", rs.RemoteAddr()))

	logger.Info("session connected")

	received := uint64(0)
	for {
		msg, err := rs.Read(ReadOptions{})
		if err != nil {
			if err == io.EOF {
				return nil
			}

			logger.Info("session read failed",
				zap.Error(err))
			return err
		}

		logger.Debug("session read", zap.Any("msg", msg))
		received++

		err = s.handleFunc(rs, msg, received)
		if err != nil {
			if s.opts.errorMsgFactory == nil {
				logger.Error("session handle failed, close this session",
					zap.Error(err))
				return err
			}

			rs.Write(s.opts.errorMsgFactory(rs, msg, err), WriteOptions{Flush: true})
		}
	}
}

func (s *server) addSession(session IOSession) {
	m := s.sessions[session.ID()%s.opts.sessionBucketSize]
	m.Lock()
	m.sessions[session.ID()] = session
	m.Unlock()
}

func (s *server) deleteSession(session IOSession) {
	m := s.sessions[session.ID()%s.opts.sessionBucketSize]
	m.Lock()
	delete(m.sessions, session.ID())
	m.Unlock()
}

func (s *server) nextID() uint64 {
	return atomic.AddUint64(&s.id, 1)
}

func (s *server) isStarted() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()

	return s.mu.running
}

func parseAdddress(address string) (string, string, error) {
	if !strings.Contains(address, "//") {
		return "tcp4", address, nil
	}

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

	if strings.ToUpper(u.Scheme) == "UNIX" {
		return u.Scheme, u.Path, nil
	}

	return u.Scheme, u.Host, nil
}
<commit_msg>fix mem alloc (#27)<commit_after>package goetty

import (
	"context"
	"errors"
	"io"
	"net"
	"net/url"
	"strings"
	"sync"
	"sync/atomic"
	"time"

	"go.uber.org/zap"
)

// NetApplication is a network based application
type NetApplication interface {
	// Start start the transport server
	Start() error
	// Stop stop the transport server
	Stop() error
	// GetSession get session
	GetSession(uint64) (IOSession, error)
	// Broadcast broadcast msg to all sessions
	Broadcast(msg interface{}) error
}

type sessionMap struct {
	sync.RWMutex
	sessions map[uint64]IOSession
}

type server struct {
	id         uint64
	opts       *appOptions
	listener   net.Listener
	closedC    chan struct{}
	sessions   map[uint64]*sessionMap
	handleFunc func(IOSession, interface{}, uint64) error

	mu struct {
		sync.RWMutex
		running bool
	}
}

// NewApplicationWithListener returns a net application with listener
func NewApplicationWithListener(listener net.Listener, handleFunc func(IOSession, interface{}, uint64) error, opts ...AppOption) (NetApplication, error) {
	s := &server{
		listener:   listener,
		handleFunc: handleFunc,
		opts: &appOptions{
			sessionOpts: &options{},
		},
		closedC: make(chan struct{}),
	}

	for _, opt := range opts {
		opt(s.opts)
	}

	s.opts.adjust()
	s.opts.logger = s.opts.logger.With(zap.String("listen-address", listener.Addr().String()))
	s.sessions = make(map[uint64]*sessionMap, s.opts.sessionBucketSize)
	for i := uint64(0); i < s.opts.sessionBucketSize; i++ {
		s.sessions[i] = &sessionMap{
			sessions: make(map[uint64]IOSession),
		}
	}
	return s, nil
}

// NewApplication returns a application
func NewApplication(address string, handleFunc func(IOSession, interface{}, uint64) error, opts ...AppOption) (NetApplication, error) {
	network, address, err := parseAdddress(address)
	if err != nil {
		return nil, err
	}

	listenConfig := &net.ListenConfig{
		Control: listenControl,
	}

	listener, err := listenConfig.Listen(context.TODO(), network, address)
	if err != nil {
		return nil, err
	}

	return NewApplicationWithListener(listener, handleFunc, opts...)
}

func (s *server) Start() error {
	s.mu.Lock()
	defer s.mu.Unlock()

	if s.mu.running {
		return nil
	}

	s.mu.running = true
	go s.doStart()
	s.opts.logger.Info("application started")
	return nil
}

func (s *server) Stop() error {
	s.mu.Lock()
	if !s.mu.running {
		s.mu.Unlock()
		return nil
	}
	s.mu.running = false
	s.mu.Unlock()

	s.listener.Close()
	s.opts.logger.Info("application listener closed")
	<-s.closedC

	// now no new connection will added, close all active sessions
	for _, m := range s.sessions {
		m.Lock()
		for k, rs := range m.sessions {
			delete(m.sessions, k)
			rs.Close()
		}
		m.Unlock()
	}
	s.opts.logger.Info("application stopped")
	return nil
}

func (s *server) GetSession(id uint64) (IOSession, error) {
	if !s.isStarted() {
		return nil, errors.New("server is not started")
	}

	m := s.sessions[id%s.opts.sessionBucketSize]
	m.RLock()
	session := m.sessions[id]
	m.RUnlock()
	return session, nil
}

func (s *server) Broadcast(msg interface{}) error {
	if !s.isStarted() {
		return errors.New("server is not started")
	}

	for _, m := range s.sessions {
		m.RLock()
		for _, rs := range m.sessions {
			rs.Write(msg, WriteOptions{Flush: true})
		}
		m.RUnlock()
	}

	return nil
}

func (s *server) doStart() {
	s.opts.logger.Info("application accept loop started")
	var tempDelay time.Duration
	for {
		conn, err := s.listener.Accept()
		if err != nil {
			if !s.isStarted() {
				s.opts.logger.Info("application accept loop stopped")
				close(s.closedC)
				return
			}

			if ne, ok := err.(net.Error); ok && ne.Timeout() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				time.Sleep(tempDelay)
				continue
			}
			return
		}
		tempDelay = 0

		rs := newBaseIOWithOptions(s.nextID(), conn, s.opts.sessionOpts)
		s.addSession(rs)

		go func() {
			defer func() {
				s.deleteSession(rs)
				rs.Close()
				if s.opts.aware != nil {
					s.opts.aware.Closed(rs)
				}
			}()
			if s.opts.aware != nil {
				s.opts.aware.Created(rs)
			}
			s.doConnection(rs)
		}()
	}
}

func (s *server) doConnection(rs IOSession) error {
	logger := s.opts.logger.With(zap.Uint64("session-id", rs.ID()),
		zap.String("addr", rs.RemoteAddr()))

	logger.Info("session connected")

	received := uint64(0)
	for {
		msg, err := rs.Read(ReadOptions{})
		if err != nil {
			if err == io.EOF {
				return nil
			}

			logger.Info("session read failed",
				zap.Error(err))
			return err
		}

		received++
		if ce := logger.Check(zap.DebugLevel, "session read message"); ce != nil {
			ce.Write(zap.Uint64("seqence", received))
		}

		err = s.handleFunc(rs, msg, received)
		if err != nil {
			if s.opts.errorMsgFactory == nil {
				logger.Error("session handle failed, close this session",
					zap.Error(err))
				return err
			}

			rs.Write(s.opts.errorMsgFactory(rs, msg, err), WriteOptions{Flush: true})
		}
	}
}

func (s *server) addSession(session IOSession) {
	m := s.sessions[session.ID()%s.opts.sessionBucketSize]
	m.Lock()
	m.sessions[session.ID()] = session
	m.Unlock()
}

func (s *server) deleteSession(session IOSession) {
	m := s.sessions[session.ID()%s.opts.sessionBucketSize]
	m.Lock()
	delete(m.sessions, session.ID())
	m.Unlock()
}

func (s *server) nextID() uint64 {
	return atomic.AddUint64(&s.id, 1)
}

func (s *server) isStarted() bool {
	s.mu.RLock()
	defer s.mu.RUnlock()

	return s.mu.running
}

func parseAdddress(address string) (string, string, error) {
	if !strings.Contains(address, "//") {
		return "tcp4", address, nil
	}

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

	if strings.ToUpper(u.Scheme) == "UNIX" {
		return u.Scheme, u.Path, nil
	}

	return u.Scheme, u.Host, nil
}
<|endoftext|>


<commit_before>package ams

import (
	"context"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
)

func TestClient_GetAsset(t *testing.T) {
	expected := testAsset("sample-id", "Sample")
	m := http.NewServeMux()
	m.HandleFunc(fmt.Sprintf("/Assets('%v')", expected.ID),
		testJSONHandler(t, http.MethodGet, false, http.StatusOK, expected),
	)

	s := httptest.NewServer(m)
	defer s.Close()

	client, err := NewClient(s.URL, testTokenSource())
	if err != nil {
		t.Fatal(err)
	}

	actual, err := client.GetAsset(context.TODO(), expected.ID)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("unexpected asset. expected: %#v, actual: %#v", expected, actual)
	}
}

func TestClient_GetAssets(t *testing.T) {
	expected := []Asset{
		testAsset("asset1", "Sample 1"),
		testAsset("asset2", "Sample 2"),
		testAsset("asset4", "Example 1"),
	}
	m := http.NewServeMux()
	m.HandleFunc("/Assets",
		testJSONHandler(t, http.MethodGet, false, http.StatusOK, testWrapValue(expected)),
	)

	s := httptest.NewServer(m)
	defer s.Close()

	client, err := NewClient(s.URL, testTokenSource())
	if err != nil {
		t.Fatal(err)
	}

	actual, err := client.GetAssets(context.TODO())
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("unexpected assets. expected: %#v, actual: %#v", expected, actual)
	}
}
<commit_msg>test: add CreateAsset test<commit_after>package ams

import (
	"context"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"reflect"
	"testing"
	"time"
)

func TestClient_GetAsset(t *testing.T) {
	expected := testAsset("sample-id", "Sample")
	m := http.NewServeMux()
	m.HandleFunc(fmt.Sprintf("/Assets('%v')", expected.ID),
		testJSONHandler(t, http.MethodGet, false, http.StatusOK, expected),
	)

	s := httptest.NewServer(m)
	defer s.Close()

	client, err := NewClient(s.URL, testTokenSource())
	if err != nil {
		t.Fatal(err)
	}

	actual, err := client.GetAsset(context.TODO(), expected.ID)
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("unexpected asset. expected: %#v, actual: %#v", expected, actual)
	}
}

func TestClient_GetAssets(t *testing.T) {
	expected := []Asset{
		testAsset("asset1", "Sample 1"),
		testAsset("asset2", "Sample 2"),
		testAsset("asset4", "Example 1"),
	}
	m := http.NewServeMux()
	m.HandleFunc("/Assets",
		testJSONHandler(t, http.MethodGet, false, http.StatusOK, testWrapValue(expected)),
	)

	s := httptest.NewServer(m)
	defer s.Close()

	client, err := NewClient(s.URL, testTokenSource())
	if err != nil {
		t.Fatal(err)
	}

	actual, err := client.GetAssets(context.TODO())
	if err != nil {
		t.Error(err)
	}
	if !reflect.DeepEqual(actual, expected) {
		t.Errorf("unexpected assets. expected: %#v, actual: %#v", expected, actual)
	}
}

func TestClient_CreateAsset(t *testing.T) {
	m := http.NewServeMux()
	m.HandleFunc("/Assets", func(w http.ResponseWriter, r *http.Request) {
		testRequestMethod(t, r, http.MethodPost)
		testAMSHeader(t, r.Header, false)

		var asset Asset
		if err := json.NewDecoder(r.Body).Decode(&asset); err != nil {
			t.Fatal(err)
		}
		if len(asset.Name) == 0 {
			t.Fatal("Name is required")
		}
		asset.ID = "created-id"
		asset.Created = formatTime(time.Now())
		asset.LastModified = formatTime(time.Now())
		asset.State = StateInitialized
		asset.FormatOption = FormatOptionNoFormat
		asset.StorageAccountName = "sampleStorage"
		asset.URI = "http://your.asset.uri"

		w.WriteHeader(http.StatusCreated)
		if err := json.NewEncoder(w).Encode(asset); err != nil {
			t.Fatal(err)
		}
	})

	s := httptest.NewServer(m)
	defer s.Close()

	client, err := NewClient(s.URL, testTokenSource())
	if err != nil {
		t.Fatal(err)
	}

	name := "sample"
	asset, err := client.CreateAsset(context.TODO(), name)
	if err != nil {
		t.Error(err)
	}
	if asset.Name != name {
		t.Errorf("unexpected Name. expected: %#v, actual: %#v", name, asset.Name)
	}
}
<|endoftext|>


<commit_before>package distro

import (
	"bytes"
	"compress/gzip"
	"compress/zlib"
	"encoding/base64"
)

type gzipTransformer struct {
	writer *gzip.Writer
}

func (gzt gzipTransformer) Transform(data []byte) []byte {
	var buf bytes.Buffer

	if gzt.writer == nil {
		gzt.writer = gzip.NewWriter(&buf)
	} else {
		gzt.writer.Reset(&buf)
	}

	gzt.writer.Write(data)
	gzt.writer.Close()

	return bytesBufferToBase64(buf)
}

type zlibTransformer struct {
	writer *zlib.Writer
}

func (zlt zlibTransformer) Transform(data []byte) []byte {
	var buf bytes.Buffer

	if zlt.writer == nil {
		zlt.writer = zlib.NewWriter(&buf)
	} else {
		zlt.writer.Reset(&buf)
	}

	zlt.writer.Write(data)
	zlt.writer.Close()

	return bytesBufferToBase64(buf)
}

func bytesBufferToBase64(buf bytes.Buffer) []byte {
	dst := make([]byte, 0, 0)

	base64.StdEncoding.Encode(dst, buf.Bytes())
	return dst
}
<commit_msg>Fix base64 encoding<commit_after>package distro

import (
	"bytes"
	"compress/gzip"
	"compress/zlib"
	"encoding/base64"
)

type gzipTransformer struct {
	writer *gzip.Writer
}

func (gzt gzipTransformer) Transform(data []byte) []byte {
	var buf bytes.Buffer

	if gzt.writer == nil {
		gzt.writer = gzip.NewWriter(&buf)
	} else {
		gzt.writer.Reset(&buf)
	}

	gzt.writer.Write(data)
	gzt.writer.Close()

	return bytesBufferToBase64(buf)
}

type zlibTransformer struct {
	writer *zlib.Writer
}

func (zlt zlibTransformer) Transform(data []byte) []byte {
	var buf bytes.Buffer

	if zlt.writer == nil {
		zlt.writer = zlib.NewWriter(&buf)
	} else {
		zlt.writer.Reset(&buf)
	}

	zlt.writer.Write(data)
	zlt.writer.Close()

	return bytesBufferToBase64(buf)
}

func bytesBufferToBase64(buf bytes.Buffer) []byte {
	dst := make([]byte, base64.StdEncoding.EncodedLen(buf.Len()))
	base64.StdEncoding.Encode(dst, buf.Bytes())
	return dst
}
<|endoftext|>


<commit_before>package tspsa

import (
	"github.com/bullapse/tspsa/sa"
	"math/rand"
)

/*
 * Create a random map for the TSP problem
 * Modifies the map in the subsequent given TSPMAP struct
 * x: Max x cord
 * y: Max y cord
 * p: Number of points
 */
func CreateRandomMAP(x int, y int, p int) []sa.Node{
	var r []sa.Node
	for i := 0; i < p; i++ {
		r = append(r, sa.NewBlankNode(rand.Intn(x), rand.Intn(y)))
	}
	return r
}
<commit_msg>add credit<commit_after>/*
 *http://www.theprojectspot.com/tutorial-post/simulated-annealing-algorithm-for-beginners/6
 */
package tspsa

import (
	"github.com/bullapse/tspsa/sa"
	"math/rand"
)

/*
 * Create a random map for the TSP problem
 * Modifies the map in the subsequent given TSPMAP struct
 * x: Max x cord
 * y: Max y cord
 * p: Number of points
 */
func CreateRandomMAP(x int, y int, p int) []sa.Node{
	var r []sa.Node
	for i := 0; i < p; i++ {
		r = append(r, sa.NewBlankNode(rand.Intn(x), rand.Intn(y)))
	}
	return r
}
<|endoftext|>


<commit_before>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package fdroidcl

import (
	"encoding/hex"
	"encoding/xml"
	"strings"
	"time"
)

type CommaList []string

func (cl *CommaList) FromString(s string) {
	*cl = strings.Split(s, ",")
}

func (cl *CommaList) String() string {
	return strings.Join(*cl, ",")
}

func (cl *CommaList) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var content string
	if err := d.DecodeElement(&content, &start); err != nil {
		return err
	}
	cl.FromString(content)
	return nil
}

func (cl *CommaList) UnmarshalText(text []byte) (err error) {
	cl.FromString(string(text))
	return nil
}

type HexHash struct {
	Type string `xml:"type,attr"`
	Data HexVal `xml:",chardata"`
}

type HexVal []byte

func (hv *HexVal) FromString(s string) error {
	b, err := hex.DecodeString(s)
	if err != nil {
		return err
	}
	*hv = b
	return nil
}

func (hv *HexVal) String() string {
	return hex.EncodeToString(*hv)
}

func (hv *HexVal) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var content string
	if err := d.DecodeElement(&content, &start); err != nil {
		return err
	}
	return hv.FromString(content)
}

func (hv *HexVal) UnmarshalText(text []byte) (err error) {
	return hv.FromString(string(text))
}

type DateVal struct {
	time.Time
}

func (dv *DateVal) FromString(s string) error {
	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return err
	}
	*dv = DateVal{t}
	return nil
}

func (dv *DateVal) String() string {
	return dv.Format("2006-01-02")
}

func (dv *DateVal) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var content string
	if err := d.DecodeElement(&content, &start); err != nil {
		return err
	}
	return dv.FromString(content)
}

func (dv *DateVal) UnmarshalText(text []byte) (err error) {
	return dv.FromString(string(text))
}
<commit_msg>Remove redundant UnmarshalXML code<commit_after>// Copyright (c) 2015, Daniel Martí <mvdan@mvdan.cc>
// See LICENSE for licensing information

package fdroidcl

import (
	"encoding/hex"
	"strings"
	"time"
)

type CommaList []string

func (cl *CommaList) FromString(s string) {
	*cl = strings.Split(s, ",")
}

func (cl *CommaList) String() string {
	return strings.Join(*cl, ",")
}

func (cl *CommaList) UnmarshalText(text []byte) (err error) {
	cl.FromString(string(text))
	return nil
}

type HexHash struct {
	Type string `xml:"type,attr"`
	Data HexVal `xml:",chardata"`
}

type HexVal []byte

func (hv *HexVal) FromString(s string) error {
	b, err := hex.DecodeString(s)
	if err != nil {
		return err
	}
	*hv = b
	return nil
}

func (hv *HexVal) String() string {
	return hex.EncodeToString(*hv)
}

func (hv *HexVal) UnmarshalText(text []byte) (err error) {
	return hv.FromString(string(text))
}

type DateVal struct {
	time.Time
}

func (dv *DateVal) FromString(s string) error {
	t, err := time.Parse("2006-01-02", s)
	if err != nil {
		return err
	}
	*dv = DateVal{t}
	return nil
}

func (dv *DateVal) String() string {
	return dv.Format("2006-01-02")
}

func (dv *DateVal) UnmarshalText(text []byte) (err error) {
	return dv.FromString(string(text))
}
<|endoftext|>


<commit_before>package cli

import (
	"fmt"
	"path/filepath"
	"sort"
	"strings"

	"github.com/rs/zerolog/log"

	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/snapshot"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	snapshotListCommand           = snapshotCommands.Command("list", "List snapshots of files and directories.").Alias("ls")
	snapshotListPath              = snapshotListCommand.Arg("source", "File or directory to show history of.").String()
	snapshotListIncludeIncomplete = snapshotListCommand.Flag("include-incomplete", "Include incomplete.").Short('i').Bool()
	snapshotListShowItemID        = snapshotListCommand.Flag("show-metadata-id", "Include metadata item ID.").Short('m').Bool()
	snapshotListShowHashCache     = snapshotListCommand.Flag("show-hashcache", "Include hashcache object ID.").Bool()
	maxResultsPerPath             = snapshotListCommand.Flag("max-results", "Maximum number of results.").Default("1000").Int()
)

func findSnapshotsForSource(mgr *snapshot.Manager, sourceInfo snapshot.SourceInfo) (manifestIDs []string, relPath string, err error) {
	for len(sourceInfo.Path) > 0 {
		list := mgr.ListSnapshotManifests(&sourceInfo)

		if len(list) > 0 {
			return list, relPath, nil
		}

		if len(relPath) > 0 {
			relPath = filepath.Base(sourceInfo.Path) + "/" + relPath
		} else {
			relPath = filepath.Base(sourceInfo.Path)
		}

		log.Printf("No snapshots of %v@%v:%v", sourceInfo.UserName, sourceInfo.Host, sourceInfo.Path)

		parentPath := filepath.Dir(sourceInfo.Path)
		if parentPath == sourceInfo.Path {
			break
		}
		sourceInfo.Path = parentPath
	}

	return nil, "", nil
}

func findManifestIDs(mgr *snapshot.Manager, source string) ([]string, string, error) {
	if source == "" {
		return mgr.ListSnapshotManifests(nil), "", nil
	}

	si, err := snapshot.ParseSourceInfo(source, getHostName(), getUserName())
	if err != nil {
		return nil, "", fmt.Errorf("invalid directory: '%s': %s", source, err)
	}

	manifestIDs, relPath, err := findSnapshotsForSource(mgr, si)
	if relPath != "" {
		relPath = "/" + relPath
	}

	return manifestIDs, relPath, err
}

func runBackupsCommand(context *kingpin.ParseContext) error {
	rep := mustOpenRepository(nil)
	defer rep.Close() //nolint: errcheck

	mgr := snapshot.NewManager(rep)

	manifestIDs, relPath, err := findManifestIDs(mgr, *snapshotListPath)
	if err != nil {
		return err
	}

	manifests, err := mgr.LoadSnapshots(manifestIDs)
	if err != nil {
		return err
	}

	sort.Sort(manifestSorter(manifests))
	outputManifests(manifests, relPath)

	return nil
}

func outputManifests(manifests []*snapshot.Manifest, relPath string) {
	var lastSource snapshot.SourceInfo
	var count int
	var lastTotalFileSize int64

	for _, m := range manifests {
		maybeIncomplete := ""
		if m.IncompleteReason != "" {
			if !*snapshotListIncludeIncomplete {
				continue
			}
			maybeIncomplete = " " + m.IncompleteReason
		}

		if m.Source != lastSource {
			fmt.Printf("\n%v\n", m.Source)
			lastSource = m.Source
			count = 0
			lastTotalFileSize = m.Stats.TotalFileSize
		}

		if count < *maxResultsPerPath {
			fmt.Printf(
				"  %v %v %v%v %10v %v%v\n",
				m.ID,
				m.StartTime.Format("2006-01-02 15:04:05 MST"),
				m.RootObjectID,
				relPath,
				units.BytesStringBase10(m.Stats.TotalFileSize),
				deltaBytes(m.Stats.TotalFileSize-lastTotalFileSize),
				maybeIncomplete,
			)
			if *snapshotListShowItemID {
				fmt.Printf("    metadata:  %v\n", m.ID)
			}
			if *snapshotListShowHashCache {
				fmt.Printf("    hashcache: %v\n", m.HashCacheID)
			}
			count++
		}

		if m.IncompleteReason == "" || !*snapshotListIncludeIncomplete {
			lastTotalFileSize = m.Stats.TotalFileSize
		}
	}
}

type manifestSorter []*snapshot.Manifest

func (b manifestSorter) Len() int { return len(b) }
func (b manifestSorter) Less(i, j int) bool {
	if c := strings.Compare(b[i].Source.String(), b[j].Source.String()); c != 0 {
		return c < 0
	}

	return b[i].StartTime.UnixNano() < b[j].StartTime.UnixNano()
}

func (b manifestSorter) Swap(i, j int) { b[i], b[j] = b[j], b[i] }

func deltaBytes(b int64) string {
	if b > 0 {
		return "(+" + units.BytesStringBase10(b) + ")"
	}

	return ""
}

func init() {
	snapshotListCommand.Action(runBackupsCommand)
}
<commit_msg>tweaked snapshot list<commit_after>package cli

import (
	"fmt"
	"path/filepath"
	"sort"
	"strings"

	"github.com/rs/zerolog/log"

	"github.com/kopia/kopia/internal/units"
	"github.com/kopia/kopia/snapshot"

	kingpin "gopkg.in/alecthomas/kingpin.v2"
)

var (
	snapshotListCommand           = snapshotCommands.Command("list", "List snapshots of files and directories.").Alias("ls")
	snapshotListPath              = snapshotListCommand.Arg("source", "File or directory to show history of.").String()
	snapshotListIncludeIncomplete = snapshotListCommand.Flag("include-incomplete", "Include incomplete.").Short('i').Bool()
	snapshotListShowItemID        = snapshotListCommand.Flag("show-metadata-id", "Include metadata item ID.").Short('m').Bool()
	snapshotListShowHashCache     = snapshotListCommand.Flag("show-hashcache", "Include hashcache object ID.").Bool()
	maxResultsPerPath             = snapshotListCommand.Flag("max-results", "Maximum number of results.").Default("1000").Int()
)

func findSnapshotsForSource(mgr *snapshot.Manager, sourceInfo snapshot.SourceInfo) (manifestIDs []string, relPath string, err error) {
	for len(sourceInfo.Path) > 0 {
		list := mgr.ListSnapshotManifests(&sourceInfo)

		if len(list) > 0 {
			return list, relPath, nil
		}

		if len(relPath) > 0 {
			relPath = filepath.Base(sourceInfo.Path) + "/" + relPath
		} else {
			relPath = filepath.Base(sourceInfo.Path)
		}

		log.Printf("No snapshots of %v@%v:%v", sourceInfo.UserName, sourceInfo.Host, sourceInfo.Path)

		parentPath := filepath.Dir(sourceInfo.Path)
		if parentPath == sourceInfo.Path {
			break
		}
		sourceInfo.Path = parentPath
	}

	return nil, "", nil
}

func findManifestIDs(mgr *snapshot.Manager, source string) ([]string, string, error) {
	if source == "" {
		return mgr.ListSnapshotManifests(nil), "", nil
	}

	si, err := snapshot.ParseSourceInfo(source, getHostName(), getUserName())
	if err != nil {
		return nil, "", fmt.Errorf("invalid directory: '%s': %s", source, err)
	}

	manifestIDs, relPath, err := findSnapshotsForSource(mgr, si)
	if relPath != "" {
		relPath = "/" + relPath
	}

	return manifestIDs, relPath, err
}

func runBackupsCommand(context *kingpin.ParseContext) error {
	rep := mustOpenRepository(nil)
	defer rep.Close() //nolint: errcheck

	mgr := snapshot.NewManager(rep)

	manifestIDs, relPath, err := findManifestIDs(mgr, *snapshotListPath)
	if err != nil {
		return err
	}

	manifests, err := mgr.LoadSnapshots(manifestIDs)
	if err != nil {
		return err
	}

	sort.Sort(manifestSorter(manifests))
	outputManifests(manifests, relPath)

	return nil
}

func outputManifests(manifests []*snapshot.Manifest, relPath string) {
	var lastSource snapshot.SourceInfo
	var count int
	var lastTotalFileSize int64

	separator := ""

	for _, m := range manifests {
		maybeIncomplete := ""
		if m.IncompleteReason != "" {
			if !*snapshotListIncludeIncomplete {
				continue
			}
			maybeIncomplete = " " + m.IncompleteReason
		}

		if m.Source != lastSource {
			fmt.Printf("%v%v\n", separator, m.Source)
			separator = "\n"
			lastSource = m.Source
			count = 0
			lastTotalFileSize = m.Stats.TotalFileSize
		}

		if count < *maxResultsPerPath {
			fmt.Printf(
				"  %v %v%v %v %v%v\n",
				m.StartTime.Format("2006-01-02 15:04:05 MST"),
				m.RootObjectID,
				relPath,
				units.BytesStringBase10(m.Stats.TotalFileSize),
				deltaBytes(m.Stats.TotalFileSize-lastTotalFileSize),
				maybeIncomplete,
			)
			if *snapshotListShowItemID {
				fmt.Printf("    metadata:  %v\n", m.ID)
			}
			if *snapshotListShowHashCache {
				fmt.Printf("    hashcache: %v\n", m.HashCacheID)
			}
			count++
		}

		if m.IncompleteReason == "" || !*snapshotListIncludeIncomplete {
			lastTotalFileSize = m.Stats.TotalFileSize
		}
	}
}

type manifestSorter []*snapshot.Manifest

func (b manifestSorter) Len() int { return len(b) }
func (b manifestSorter) Less(i, j int) bool {
	if c := strings.Compare(b[i].Source.String(), b[j].Source.String()); c != 0 {
		return c < 0
	}

	return b[i].StartTime.UnixNano() < b[j].StartTime.UnixNano()
}

func (b manifestSorter) Swap(i, j int) { b[i], b[j] = b[j], b[i] }

func deltaBytes(b int64) string {
	if b > 0 {
		return "(+" + units.BytesStringBase10(b) + ")"
	}

	return ""
}

func init() {
	snapshotListCommand.Action(runBackupsCommand)
}
<|endoftext|>


<commit_before>package actor

import (
	"log"
)

type paniced struct {
	actor Actor
}

type createRequest struct {
	name     string
	behavior Behavior
	c        chan Actor
}

type shutdown struct{}

type Supervisor interface {
	Actor
	ActorOf(Behavior, string) Actor
	Shutdown()
}

type supervisor struct {
	Actor
	children []Actor
}

func (sv *supervisor) ActorOf(behavior Behavior, name string) Actor {
	c := make(chan Actor)
	sv.Send() <- createRequest{
		name:     name,
		behavior: behavior,
		c:        c,
	}
	return <-c
}

func (sv *supervisor) Shutdown() {
	sv.Send() <- shutdown{}
}

func (sv *supervisor) Init() {
}

func (sv *supervisor) Receive(_ Actor, msg interface{}) {
	switch msg := msg.(type) {
	case paniced:
		log.Println(msg.actor.Path(), "paniced")
		msg.actor.init()
		msg.actor.start()
	case createRequest:
		a := newActor(msg.name, sv, msg.behavior)
		a.init()
		a.start()
		sv.children = append(sv.children, a)
		msg.c <- a
	case shutdown:
		for _, a := range sv.children {
			a.stop()
		}
		sv.stop()
	default:
		panic("Supervisor error: received unexpected message")
	}
}

func NewSupervisor(name string) Supervisor {
	sv := &supervisor{}
	sv.Actor = newActor(name, _guardian, sv)
	sv.start()
	return sv
}
<commit_msg>Remove children on shutdown<commit_after>package actor

import (
	"log"
)

type paniced struct {
	actor Actor
}

type createRequest struct {
	name     string
	behavior Behavior
	c        chan Actor
}

type shutdown struct{}

type Supervisor interface {
	Actor
	ActorOf(Behavior, string) Actor
	Shutdown()
}

type supervisor struct {
	Actor
	children []Actor
}

func (sv *supervisor) ActorOf(behavior Behavior, name string) Actor {
	c := make(chan Actor)
	sv.Send() <- createRequest{
		name:     name,
		behavior: behavior,
		c:        c,
	}
	return <-c
}

func (sv *supervisor) Shutdown() {
	sv.Send() <- shutdown{}
}

func (sv *supervisor) Init() {
}

func (sv *supervisor) Receive(_ Actor, msg interface{}) {
	switch msg := msg.(type) {
	case paniced:
		log.Println(msg.actor.Path(), "paniced")
		msg.actor.init()
		msg.actor.start()
	case createRequest:
		a := newActor(msg.name, sv, msg.behavior)
		a.init()
		a.start()
		sv.children = append(sv.children, a)
		msg.c <- a
	case shutdown:
		for _, a := range sv.children {
			a.stop()
		}
		sv.children = sv.children[:0]
		sv.stop()
	default:
		panic("Supervisor error: received unexpected message")
	}
}

func NewSupervisor(name string) Supervisor {
	sv := &supervisor{}
	sv.Actor = newActor(name, _guardian, sv)
	sv.start()
	return sv
}
<|endoftext|>


<commit_before>package whois

import (
	"fmt"
)

type verisignAdapter struct {
	DefaultAdapter
}

func (a *verisignAdapter) Prepare(req *Request) error {
	a.DefaultAdapter.Prepare(req)
	req.Body = []byte(fmt.Sprintf("=%s\r\n", req.Query))
	return nil
}

func init() {
	BindAdapter(
		&verisignAdapter{},
		"whois.verisign-grs.com",
		"bzwhois.verisign-grs.com",
		"ccwhois.verisign-grs.com",
		"jobswhois.verisign-grs.com",
	)
}
<commit_msg>tvwhois.verisign-grs.com host<commit_after>package whois

import (
	"fmt"
)

type verisignAdapter struct {
	DefaultAdapter
}

func (a *verisignAdapter) Prepare(req *Request) error {
	a.DefaultAdapter.Prepare(req)
	req.Body = []byte(fmt.Sprintf("=%s\r\n", req.Query))
	return nil
}

func init() {
	BindAdapter(
		&verisignAdapter{},
		"whois.verisign-grs.com",
		"bzwhois.verisign-grs.com",
		"ccwhois.verisign-grs.com",
		"tvwhois.verisign-grs.com",
		"jobswhois.verisign-grs.com",
	)
}
<|endoftext|>


<commit_before>// SPDX-License-Identifier: MIT

package assert

import (
	"errors"
	"testing"
	"time"
)

func BenchmarkGetCallerInfo(b *testing.B) {
	for i := 0; i < b.N; i++ {
		str := getCallerInfo()

		if str != "BenchmarkGetCallerInfo(assert_test.go:15)" {
			b.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
		}
	}
}

func TestGetCallerInfo(t *testing.T) {
	str := getCallerInfo()
	// NOTE:注意这里涉及到调用函数的行号信息
	if str != "TestGetCallerInfo(assert_test.go:24)" {
		t.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
	}

	// 嵌套调用，第二个参数为当前的行号
	testGetCallerInfo(t, "31")
	testGetCallerInfo(t, "32")

	// 闭合函数，line 为调用所在的行号。
	f := func(line string) {
		str := getCallerInfo()
		if str != "TestGetCallerInfo(assert_test.go:"+line+")" {
			t.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
		}
	}

	go func() {
		f("43")
	}()
	go func() {
		testGetCallerInfo(t, "46")
	}()

	// bug: 无法处理的情况，go 会新开协程，无法获取当前的行号
	//go f("50")
	//go testGetCallerInfo(t, "51")

	f("53") // 参数为当前等号
	f("54")

	ff := func(line string) {
		f(line)
	}
	go func() {
		ff("60")
	}()

	// NOTE: 无法处理的情况
	/*go func() {
		go ff("63")
	}()*/

	time.Sleep(500 * time.Microsecond)
}

// 参数 line，为调用此函数所在的行号。
func testGetCallerInfo(t *testing.T, line string) {
	str := getCallerInfo()
	if str != "TestGetCallerInfo(assert_test.go:"+line+")" {
		t.Errorf("getCallerInfo返回的信息不正确，其返回值为：%v", str)
	}
}

func TestFormatMsg(t *testing.T) {
	msg1 := []interface{}{}
	msg2 := []interface{}{[]rune("msg:%v"), 2}
	msg3 := []interface{}{"msg:%v", 3}
	msg4 := []interface{}{123, 456}
	msg5 := []interface{}{123}
	msg6 := []interface{}{errors.New("123")}

	str := formatMessage(msg1, msg2)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg1,msg2)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg2)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg1,msg2)返回信息错误:[%v]", str)
	}

	str = formatMessage(msg2, msg3)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg2,msg3)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, nil)
	if str != "<未提供任何错误信息>" {
		t.Errorf("formatMessage(nil,nil)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg4)
	if str != "123 456\n" {
		t.Errorf("formatMessage(nil,nil)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg5)
	if str != "123" {
		t.Errorf("formatMessage(nil,msg5)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg6)
	if str != "123" {
		t.Errorf("formatMessage(nil,msg5)返回信息错误:[%v]", str)
	}
}

func TestTrue(t *testing.T) {
	True(t, true)
	True(t, 1 == 1, "True(1==1) failed")
}

func TestFalse(t *testing.T) {
	False(t, false, "False failed")
	False(t, 1 == 2, "False(1==2) failed")
}

func TestNil(t *testing.T) {
	Nil(t, nil, "Nil failed")

	var v interface{}
	Nil(t, v, "Nil(v) failed")
}

func TestNotNil(t *testing.T) {
	NotNil(t, 5, "NotNil failed")

	var v interface{} = 5
	NotNil(t, v, "NotNil failed")
}

func TestEqual(t *testing.T) {
	Equal(t, 5, 5, "Equal(5,5) failed")

	var v1, v2 interface{}
	v1 = 5
	v2 = 5

	Equal(t, 5, v1)
	Equal(t, v1, v2, "Equal(v1,v2) failed")
	Equal(t, int8(126), 126)
	Equal(t, int64(126), int8(126))
	Equal(t, uint(7), int(7))
}

func TestNotEqual(t *testing.T) {
	NotEqual(t, 5, 6, "NotEqual(5,6) failed")

	var v1, v2 interface{} = 5, 6

	NotEqual(t, 5, v2, "NotEqual(5,v2) failed")
	NotEqual(t, v1, v2, "NotEqual(v1,v2) failed")
	NotEqual(t, 128, int8(127))
}

func TestEmpty(t *testing.T) {
	Empty(t, 0, "Empty(0) failed")
	Empty(t, "", "Empty(``) failed")
	Empty(t, false, "Empty(false) failed")
	Empty(t, []string{}, "Empty(slice{}) failed")
	Empty(t, []int{}, "Empty(slice{}) failed")
}

func TestNotEmpty(t *testing.T) {
	NotEmpty(t, 1, "NotEmpty(1) failed")
	NotEmpty(t, true, "NotEmpty(true) failed")
	NotEmpty(t, []string{"ab"}, "NotEmpty(slice(abc)) failed")
}

type ErrorImpl struct {
	msg string
}

func (err *ErrorImpl) Error() string {
	return err.msg
}

func TestError(t *testing.T) {
	err1 := errors.New("test")
	Error(t, err1, "Error(err) failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "Error(ErrorImpl) failed")
}

func TestErrorString(t *testing.T) {
	err1 := errors.New("test")
	ErrorString(t, err1, "test", "Error(err1) failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "msg", "Error(ErrorImpl) failed")
}

func TestErrorType(t *testing.T) {
	ErrorType(t, errors.New("abc"), errors.New("def"), "ErrorType:errors.New(abc) != errors.New(def)")

	ErrorType(t, &ErrorImpl{msg: "abc"}, &ErrorImpl{}, "ErrorType:&ErrorImpl{} != &ErrorImpl{}")
}

func TestNotError(t *testing.T) {
	NotError(t, "123", "NotError(123) failed")

	var err1 error
	NotError(t, err1, "var err1 error failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "Error(ErrorImpl) failed")
}

func TestFileExists(t *testing.T) {
	FileExists(t, "./assert.go", "FileExists() failed")
	FileExists(t, "./", "FileExists() failed")
}

func TestFileNotExists(t *testing.T) {
	FileNotExists(t, "c:/win", "FileNotExists() failed")
	FileNotExists(t, "./abcefg/", "FileNotExists() failed")
}

func TestPanic(t *testing.T) {
	f1 := func() {
		panic("panic")
	}

	Panic(t, f1)
}

func TestPanicString(t *testing.T) {
	f1 := func() {
		panic("panic")
	}

	PanicString(t, f1, "panic")
}

func TestPanicType(t *testing.T) {
	f1 := func() {
		panic("panic")
	}
	PanicType(t, f1, "abc")

	f1 = func() {
		panic(errors.New("panic"))
	}
	PanicType(t, f1, errors.New("abc"))

	f1 = func() {
		panic(&ErrorImpl{msg: "panic"})
	}
	PanicType(t, f1, &ErrorImpl{msg: "abc"})
}

func TestNotPanic(t *testing.T) {
	f1 := func() {
	}

	NotPanic(t, f1)
}

func TestContains(t *testing.T) {
	Contains(t, []int{1, 2, 3}, []int8{1, 2})
}

func TestNotContains(t *testing.T) {
	NotContains(t, []int{1, 2, 3}, []int8{1, 3})
}
<commit_msg>test: 修正测试错误<commit_after>// SPDX-License-Identifier: MIT

package assert

import (
	"errors"
	"testing"
	"time"
)

func BenchmarkGetCallerInfo(b *testing.B) {
	for i := 0; i < b.N; i++ {
		str := getCallerInfo()

		if str != "BenchmarkGetCallerInfo(assert_test.go:15)" {
			b.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
		}
	}
}

func TestGetCallerInfo(t *testing.T) {
	str := getCallerInfo()
	// NOTE:注意这里涉及到调用函数的行号信息
	if str != "TestGetCallerInfo(assert_test.go:22)" {
		t.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
	}

	// 嵌套调用，第二个参数为当前的行号
	testGetCallerInfo(t, "29")
	testGetCallerInfo(t, "30")

	// 闭合函数，line 为调用所在的行号。
	f := func(line string) {
		str := getCallerInfo()
		if str != "TestGetCallerInfo(assert_test.go:"+line+")" {
			t.Errorf("getCallerInfo 返回的信息不正确，其返回值为：%v", str)
		}
	}

	go func() {
		f("41")
	}()
	go func() {
		testGetCallerInfo(t, "44")
	}()

	// bug: 无法处理的情况，go 会新开协程，无法获取当前的行号
	//go f("50")
	//go testGetCallerInfo(t, "51")

	f("51") // 参数为当前等号
	f("52")

	ff := func(line string) {
		f(line)
	}
	go func() {
		ff("58")
	}()

	// NOTE: 无法处理的情况
	/*go func() {
		go ff("63")
	}()*/

	time.Sleep(500 * time.Microsecond)
}

// 参数 line，为调用此函数所在的行号。
func testGetCallerInfo(t *testing.T, line string) {
	str := getCallerInfo()
	if str != "TestGetCallerInfo(assert_test.go:"+line+")" {
		t.Errorf("getCallerInfo返回的信息不正确，其返回值为：%v", str)
	}
}

func TestFormatMsg(t *testing.T) {
	msg1 := []interface{}{}
	msg2 := []interface{}{[]rune("msg:%v"), 2}
	msg3 := []interface{}{"msg:%v", 3}
	msg4 := []interface{}{123, 456}
	msg5 := []interface{}{123}
	msg6 := []interface{}{errors.New("123")}

	str := formatMessage(msg1, msg2)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg1,msg2)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg2)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg1,msg2)返回信息错误:[%v]", str)
	}

	str = formatMessage(msg2, msg3)
	if str != "msg:2" {
		t.Errorf("formatMessage(msg2,msg3)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, nil)
	if str != "<未提供任何错误信息>" {
		t.Errorf("formatMessage(nil,nil)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg4)
	if str != "123 456\n" {
		t.Errorf("formatMessage(nil,nil)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg5)
	if str != "123" {
		t.Errorf("formatMessage(nil,msg5)返回信息错误:[%v]", str)
	}

	str = formatMessage(nil, msg6)
	if str != "123" {
		t.Errorf("formatMessage(nil,msg5)返回信息错误:[%v]", str)
	}
}

func TestTrue(t *testing.T) {
	True(t, true)
	True(t, 1 == 1, "True(1==1) failed")
}

func TestFalse(t *testing.T) {
	False(t, false, "False failed")
	False(t, 1 == 2, "False(1==2) failed")
}

func TestNil(t *testing.T) {
	Nil(t, nil, "Nil failed")

	var v interface{}
	Nil(t, v, "Nil(v) failed")
}

func TestNotNil(t *testing.T) {
	NotNil(t, 5, "NotNil failed")

	var v interface{} = 5
	NotNil(t, v, "NotNil failed")
}

func TestEqual(t *testing.T) {
	Equal(t, 5, 5, "Equal(5,5) failed")

	var v1, v2 interface{}
	v1 = 5
	v2 = 5

	Equal(t, 5, v1)
	Equal(t, v1, v2, "Equal(v1,v2) failed")
	Equal(t, int8(126), 126)
	Equal(t, int64(126), int8(126))
	Equal(t, uint(7), int(7))
}

func TestNotEqual(t *testing.T) {
	NotEqual(t, 5, 6, "NotEqual(5,6) failed")

	var v1, v2 interface{} = 5, 6

	NotEqual(t, 5, v2, "NotEqual(5,v2) failed")
	NotEqual(t, v1, v2, "NotEqual(v1,v2) failed")
	NotEqual(t, 128, int8(127))
}

func TestEmpty(t *testing.T) {
	Empty(t, 0, "Empty(0) failed")
	Empty(t, "", "Empty(``) failed")
	Empty(t, false, "Empty(false) failed")
	Empty(t, []string{}, "Empty(slice{}) failed")
	Empty(t, []int{}, "Empty(slice{}) failed")
}

func TestNotEmpty(t *testing.T) {
	NotEmpty(t, 1, "NotEmpty(1) failed")
	NotEmpty(t, true, "NotEmpty(true) failed")
	NotEmpty(t, []string{"ab"}, "NotEmpty(slice(abc)) failed")
}

type ErrorImpl struct {
	msg string
}

func (err *ErrorImpl) Error() string {
	return err.msg
}

func TestError(t *testing.T) {
	err1 := errors.New("test")
	Error(t, err1, "Error(err) failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "Error(ErrorImpl) failed")
}

func TestErrorString(t *testing.T) {
	err1 := errors.New("test")
	ErrorString(t, err1, "test", "Error(err1) failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "msg", "Error(ErrorImpl) failed")
}

func TestErrorType(t *testing.T) {
	ErrorType(t, errors.New("abc"), errors.New("def"), "ErrorType:errors.New(abc) != errors.New(def)")

	ErrorType(t, &ErrorImpl{msg: "abc"}, &ErrorImpl{}, "ErrorType:&ErrorImpl{} != &ErrorImpl{}")
}

func TestNotError(t *testing.T) {
	NotError(t, "123", "NotError(123) failed")

	var err1 error
	NotError(t, err1, "var err1 error failed")

	err2 := &ErrorImpl{msg: "msg"}
	Error(t, err2, "Error(ErrorImpl) failed")
}

func TestFileExists(t *testing.T) {
	FileExists(t, "./assert.go", "FileExists() failed")
	FileExists(t, "./", "FileExists() failed")
}

func TestFileNotExists(t *testing.T) {
	FileNotExists(t, "c:/win", "FileNotExists() failed")
	FileNotExists(t, "./abcefg/", "FileNotExists() failed")
}

func TestPanic(t *testing.T) {
	f1 := func() {
		panic("panic")
	}

	Panic(t, f1)
}

func TestPanicString(t *testing.T) {
	f1 := func() {
		panic("panic")
	}

	PanicString(t, f1, "panic")
}

func TestPanicType(t *testing.T) {
	f1 := func() {
		panic("panic")
	}
	PanicType(t, f1, "abc")

	f1 = func() {
		panic(errors.New("panic"))
	}
	PanicType(t, f1, errors.New("abc"))

	f1 = func() {
		panic(&ErrorImpl{msg: "panic"})
	}
	PanicType(t, f1, &ErrorImpl{msg: "abc"})
}

func TestNotPanic(t *testing.T) {
	f1 := func() {
	}

	NotPanic(t, f1)
}

func TestContains(t *testing.T) {
	Contains(t, []int{1, 2, 3}, []int8{1, 2})
}

func TestNotContains(t *testing.T) {
	NotContains(t, []int{1, 2, 3}, []int8{1, 3})
}
<|endoftext|>


<commit_before>// Package session provides a way to create service clients with shared configuration
// and handlers.
//
// Generally this package should be used instead of the `defaults` package.
//
// A session should be used to share configurations and request handlers between multiple
// service clients. When service clients need specific configuration aws.Config can be
// used to provide additional configuration directly to the service client.
package session

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/corehandlers"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/private/endpoints"
)

// A Session provides a central location to create service clients from and
// store configurations and request handlers for those services.
//
// Sessions are safe to create service clients concurrently, but it is not safe
// to mutate the session concurrently.
type Session struct {
	Config   *aws.Config
	Handlers request.Handlers
}

// New creates a new instance of the handlers merging in the provided Configs
// on top of the SDK's default configurations. Once the session is created it
// can be mutated to modify Configs or Handlers. The session is safe to be read
// concurrently, but it should not be written to concurrently.
//
// Example:
//     // Create a session with the default config and request handlers.
//     sess := session.New()
//
//     // Create a session with a custom region
//     sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
//
//     // Create a session, and add additional handlers for all service
//     // clients created with the session to inherit. Adds logging handler.
//     sess := session.New()
//     sess.Handlers.Send.PushFront(func(r *request.Request) {
//          // Log every request made and its payload
//          logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
//     })
//
//     // Create a S3 client instance from a session
//     sess := session.New()
//     svc := s3.New(sess)
func New(cfgs ...*aws.Config) *Session {
	cfg := defaults.Config()
	handlers := defaults.Handlers()

	// Apply the passed in configs so the configuration can be applied to the
	// default credential chain
	cfg.MergeIn(cfgs...)
	cfg.Credentials = defaults.CredChain(cfg, handlers)

	// Reapply any passed in configs to override credentials if set
	cfg.MergeIn(cfgs...)

	s := &Session{
		Config:   cfg,
		Handlers: handlers,
	}

	initHandlers(s)

	return s
}

func initHandlers(s *Session) {
	// Add the Validate parameter handler if it is not disabled.
	s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
	if !aws.BoolValue(s.Config.DisableParamValidation) {
		s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
	}
}

// Copy creates and returns a copy of the current session, coping the config
// and handlers. If any additional configs are provided they will be merged
// on top of the session's copied config.
//
// Example:
//     // Create a copy of the current session, configured for the us-west-2 region.
//     sess.Copy(&aws.Config{Region: aws.String("us-west-2"})
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
	newSession := &Session{
		Config:   s.Config.Copy(cfgs...),
		Handlers: s.Handlers.Copy(),
	}

	initHandlers(newSession)

	return newSession
}

// ClientConfig satisfies the client.ConfigProvider interface and is used to
// configure the service client instances. Passing the Session to the service
// client's constructor (New) will use this method to configure the client.
//
// Example:
//     sess := session.New()
//     s3.New(sess)
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
	s = s.Copy(cfgs...)
	endpoint, signingRegion := endpoints.NormalizeEndpoint(
		aws.StringValue(s.Config.Endpoint), serviceName,
		aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))

	return client.Config{
		Config:        s.Config,
		Handlers:      s.Handlers,
		Endpoint:      endpoint,
		SigningRegion: signingRegion,
	}
}
<commit_msg>Missing parenthes in docs<commit_after>// Package session provides a way to create service clients with shared configuration
// and handlers.
//
// Generally this package should be used instead of the `defaults` package.
//
// A session should be used to share configurations and request handlers between multiple
// service clients. When service clients need specific configuration aws.Config can be
// used to provide additional configuration directly to the service client.
package session

import (
	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/client"
	"github.com/aws/aws-sdk-go/aws/corehandlers"
	"github.com/aws/aws-sdk-go/aws/defaults"
	"github.com/aws/aws-sdk-go/aws/request"
	"github.com/aws/aws-sdk-go/private/endpoints"
)

// A Session provides a central location to create service clients from and
// store configurations and request handlers for those services.
//
// Sessions are safe to create service clients concurrently, but it is not safe
// to mutate the session concurrently.
type Session struct {
	Config   *aws.Config
	Handlers request.Handlers
}

// New creates a new instance of the handlers merging in the provided Configs
// on top of the SDK's default configurations. Once the session is created it
// can be mutated to modify Configs or Handlers. The session is safe to be read
// concurrently, but it should not be written to concurrently.
//
// Example:
//     // Create a session with the default config and request handlers.
//     sess := session.New()
//
//     // Create a session with a custom region
//     sess := session.New(&aws.Config{Region: aws.String("us-east-1")})
//
//     // Create a session, and add additional handlers for all service
//     // clients created with the session to inherit. Adds logging handler.
//     sess := session.New()
//     sess.Handlers.Send.PushFront(func(r *request.Request) {
//          // Log every request made and its payload
//          logger.Println("Request: %s/%s, Payload: %s", r.ClientInfo.ServiceName, r.Operation, r.Params)
//     })
//
//     // Create a S3 client instance from a session
//     sess := session.New()
//     svc := s3.New(sess)
func New(cfgs ...*aws.Config) *Session {
	cfg := defaults.Config()
	handlers := defaults.Handlers()

	// Apply the passed in configs so the configuration can be applied to the
	// default credential chain
	cfg.MergeIn(cfgs...)
	cfg.Credentials = defaults.CredChain(cfg, handlers)

	// Reapply any passed in configs to override credentials if set
	cfg.MergeIn(cfgs...)

	s := &Session{
		Config:   cfg,
		Handlers: handlers,
	}

	initHandlers(s)

	return s
}

func initHandlers(s *Session) {
	// Add the Validate parameter handler if it is not disabled.
	s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
	if !aws.BoolValue(s.Config.DisableParamValidation) {
		s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
	}
}

// Copy creates and returns a copy of the current session, coping the config
// and handlers. If any additional configs are provided they will be merged
// on top of the session's copied config.
//
// Example:
//     // Create a copy of the current session, configured for the us-west-2 region.
//     sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
func (s *Session) Copy(cfgs ...*aws.Config) *Session {
	newSession := &Session{
		Config:   s.Config.Copy(cfgs...),
		Handlers: s.Handlers.Copy(),
	}

	initHandlers(newSession)

	return newSession
}

// ClientConfig satisfies the client.ConfigProvider interface and is used to
// configure the service client instances. Passing the Session to the service
// client's constructor (New) will use this method to configure the client.
//
// Example:
//     sess := session.New()
//     s3.New(sess)
func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
	s = s.Copy(cfgs...)
	endpoint, signingRegion := endpoints.NormalizeEndpoint(
		aws.StringValue(s.Config.Endpoint), serviceName,
		aws.StringValue(s.Config.Region), aws.BoolValue(s.Config.DisableSSL))

	return client.Config{
		Config:        s.Config,
		Handlers:      s.Handlers,
		Endpoint:      endpoint,
		SigningRegion: signingRegion,
	}
}
<|endoftext|>