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

package power

import (
	"context"
	"net/http"
	"testing"
	"time"

	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/types"
	"github.com/stretchr/testify/require"
)

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

	defaultInterval := sacloud.DefaultStatePollingInterval

	sacloud.DefaultStatePollingInterval = 10 * time.Millisecond
	BootRetrySpan = time.Millisecond
	ShutdownRetrySpan = time.Millisecond
	defer func() {
		sacloud.DefaultStatePollingInterval = defaultInterval
		BootRetrySpan = DefaultBootRetrySpan
		ShutdownRetrySpan = DefaultShutdownRetrySpan
	}()

	ctx := context.Background()
	t.Run("boot", func(t *testing.T) {
		handler := &dummyPowerHandler{
			ignoreBootCount: 3,
			instanceStatus:  types.ServerInstanceStatuses.Down,
		}
		err := boot(ctx, handler)
		require.NoError(t, err)
		require.Equal(t, handler.ignoreBootCount+1, handler.bootCount)
	})
	t.Run("shutdown", func(t *testing.T) {
		handler := &dummyPowerHandler{
			ignoreShutdownCount: 3,
			instanceStatus:      types.ServerInstanceStatuses.Up,
		}
		err := shutdown(ctx, handler, true)
		require.NoError(t, err)
		require.Equal(t, handler.ignoreShutdownCount+1, handler.shutdownCount)
	})
}

type dummyPowerHandler struct {
	bootCount           int
	shutdownCount       int
	ignoreBootCount     int
	ignoreShutdownCount int
	instanceStatus      types.EServerInstanceStatus
}

func (d *dummyPowerHandler) boot() error {
	d.bootCount++
	if d.bootCount > d.ignoreBootCount {
		go d.toggleInstanceStatus()
		return sacloud.NewAPIError("DUMMY", nil, "dummy", http.StatusConflict, nil)
	}
	return nil
}
func (d *dummyPowerHandler) shutdown(force bool) error {
	d.shutdownCount++
	if d.shutdownCount > d.ignoreShutdownCount {
		go d.toggleInstanceStatus()
		return sacloud.NewAPIError("DUMMY", nil, "dummy", http.StatusConflict, nil)
	}
	return nil
}

func (d *dummyPowerHandler) read() (interface{}, error) {
	return d, nil
}

func (d *dummyPowerHandler) toggleInstanceStatus() {
	time.Sleep(100 * time.Millisecond)
	switch d.instanceStatus {
	case types.ServerInstanceStatuses.Up:
		d.instanceStatus = types.ServerInstanceStatuses.Down
	case types.ServerInstanceStatuses.Down:
		d.instanceStatus = types.ServerInstanceStatuses.Up
	}
}

// GetInstanceStatus .
func (d *dummyPowerHandler) GetInstanceStatus() types.EServerInstanceStatus {
	return d.instanceStatus
}

// SetInstanceStatus .
func (d *dummyPowerHandler) SetInstanceStatus(v types.EServerInstanceStatus) {
	d.instanceStatus = v
}
<commit_msg>Fixed race condition when running tests<commit_after>// Copyright 2016-2019 The Libsacloud Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package power

import (
	"context"
	"net/http"
	"sync"
	"testing"
	"time"

	"github.com/sacloud/libsacloud/v2/sacloud"
	"github.com/sacloud/libsacloud/v2/sacloud/types"
	"github.com/stretchr/testify/require"
)

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

	defaultInterval := sacloud.DefaultStatePollingInterval

	sacloud.DefaultStatePollingInterval = 10 * time.Millisecond
	BootRetrySpan = time.Millisecond
	ShutdownRetrySpan = time.Millisecond
	defer func() {
		sacloud.DefaultStatePollingInterval = defaultInterval
		BootRetrySpan = DefaultBootRetrySpan
		ShutdownRetrySpan = DefaultShutdownRetrySpan
	}()

	ctx := context.Background()
	t.Run("boot", func(t *testing.T) {
		handler := &dummyPowerHandler{
			ignoreBootCount: 3,
			instanceStatus:  types.ServerInstanceStatuses.Down,
		}
		err := boot(ctx, handler)
		require.NoError(t, err)
		require.Equal(t, handler.ignoreBootCount+1, handler.bootCount)
	})
	t.Run("shutdown", func(t *testing.T) {
		handler := &dummyPowerHandler{
			ignoreShutdownCount: 3,
			instanceStatus:      types.ServerInstanceStatuses.Up,
		}
		err := shutdown(ctx, handler, true)
		require.NoError(t, err)
		require.Equal(t, handler.ignoreShutdownCount+1, handler.shutdownCount)
	})
}

type dummyPowerHandler struct {
	bootCount           int
	shutdownCount       int
	ignoreBootCount     int
	ignoreShutdownCount int
	instanceStatus      types.EServerInstanceStatus

	mu sync.Mutex
}

func (d *dummyPowerHandler) boot() error {
	d.bootCount++
	if d.bootCount > d.ignoreBootCount {
		go d.toggleInstanceStatus()
		return sacloud.NewAPIError("DUMMY", nil, "dummy", http.StatusConflict, nil)
	}
	return nil
}
func (d *dummyPowerHandler) shutdown(force bool) error {
	d.shutdownCount++
	if d.shutdownCount > d.ignoreShutdownCount {
		go d.toggleInstanceStatus()
		return sacloud.NewAPIError("DUMMY", nil, "dummy", http.StatusConflict, nil)
	}
	return nil
}

func (d *dummyPowerHandler) read() (interface{}, error) {
	return d, nil
}

func (d *dummyPowerHandler) toggleInstanceStatus() {
	time.Sleep(100 * time.Millisecond)

	d.mu.Lock()
	defer d.mu.Unlock()

	switch d.instanceStatus {
	case types.ServerInstanceStatuses.Up:
		d.instanceStatus = types.ServerInstanceStatuses.Down
	case types.ServerInstanceStatuses.Down:
		d.instanceStatus = types.ServerInstanceStatuses.Up
	}
}

// GetInstanceStatus .
func (d *dummyPowerHandler) GetInstanceStatus() types.EServerInstanceStatus {
	d.mu.Lock()
	defer d.mu.Unlock()

	return d.instanceStatus
}

// SetInstanceStatus .
func (d *dummyPowerHandler) SetInstanceStatus(v types.EServerInstanceStatus) {
	d.instanceStatus = v
}
<|endoftext|>


<commit_before>package dockertest

import (
	dc "github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"fmt"
	"time"
	"github.com/cenk/backoff"
)

type Pool struct {
	Client *dc.Client
	MaxWait time.Duration
}

type Resource struct {
	Container *dc.Container
}

func (r *Resource) GetPort(id string) string {
	if r.Container == nil {
		return ""
	} else if r.Container.NetworkSettings == nil {
		return ""
	}

	m, ok := r.Container.NetworkSettings.Ports[dc.Port(id)]
	if !ok {
		return ""
	} else if len(m) == 0 {
		return ""
	}

	return m[0].HostPort
}

func NewPool(endpoint string) (*Pool, error) {
	if endpoint == "" {
		endpoint = "http://localhost:2375"
	}
	client, err := dc.NewClient(endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	return &Pool{
		Client: client,
	}, nil
}

func (d *Pool) Run(repository, tag string, env []string) (*Resource, error) {
	if tag == "" {
		tag = "latest"
	}

	if err := d.Client.PullImage(dc.PullImageOptions{
		Repository: repository,
		Tag: tag,
	}, dc.AuthConfiguration{}); err != nil {
		return nil, errors.Wrap(err, "")
	}

	c, err := d.Client.CreateContainer(dc.CreateContainerOptions{
		Config: &dc.Config{
			Image: fmt.Sprintf("%s:%s", repository, tag),
			Env: env,
		},
		HostConfig: &dc.HostConfig{
			PublishAllPorts: true,
		},
	})
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	if err := d.Client.StartContainer(c.ID, nil); err != nil {
		return nil, errors.Wrap(err, "")
	}

	c, err = d.Client.InspectContainer(c.ID)
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	return &Resource{
		Container: c,
	}, nil
}

func (d *Pool) Purge(r *Resource) error {
	if err := d.Client.KillContainer(dc.KillContainerOptions{ID: r.Container.ID}); err != nil {
		return errors.Wrap(err, "")
	}

	if err := d.Client.RemoveContainer(dc.RemoveContainerOptions{ID: r.Container.ID}); err != nil {
		return errors.Wrap(err, "")
	}

	return nil
}

func (d *Pool) Retry(op func() error) error {
	if d.MaxWait == 0 {
		d.MaxWait = time.Minute / 2
	}
	bo :=  backoff.NewExponentialBackOff()
	bo.MaxInterval = time.Second * 5
	bo.MaxElapsedTime = d.MaxWait
	return backoff.Retry(op, bo)
}
<commit_msg>purge: force removal of volumes and image<commit_after>package dockertest

import (
	"fmt"
	"github.com/cenk/backoff"
	dc "github.com/fsouza/go-dockerclient"
	"github.com/pkg/errors"
	"time"
)

type Pool struct {
	Client  *dc.Client
	MaxWait time.Duration
}

type Resource struct {
	Container *dc.Container
}

func (r *Resource) GetPort(id string) string {
	if r.Container == nil {
		return ""
	} else if r.Container.NetworkSettings == nil {
		return ""
	}

	m, ok := r.Container.NetworkSettings.Ports[dc.Port(id)]
	if !ok {
		return ""
	} else if len(m) == 0 {
		return ""
	}

	return m[0].HostPort
}

func NewPool(endpoint string) (*Pool, error) {
	if endpoint == "" {
		endpoint = "http://localhost:2375"
	}
	client, err := dc.NewClient(endpoint)
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	return &Pool{
		Client: client,
	}, nil
}

func (d *Pool) Run(repository, tag string, env []string) (*Resource, error) {
	if tag == "" {
		tag = "latest"
	}

	if err := d.Client.PullImage(dc.PullImageOptions{
		Repository: repository,
		Tag:        tag,
	}, dc.AuthConfiguration{}); err != nil {
		return nil, errors.Wrap(err, "")
	}

	c, err := d.Client.CreateContainer(dc.CreateContainerOptions{
		Config: &dc.Config{
			Image: fmt.Sprintf("%s:%s", repository, tag),
			Env:   env,
		},
		HostConfig: &dc.HostConfig{
			PublishAllPorts: true,
		},
	})
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	if err := d.Client.StartContainer(c.ID, nil); err != nil {
		return nil, errors.Wrap(err, "")
	}

	c, err = d.Client.InspectContainer(c.ID)
	if err != nil {
		return nil, errors.Wrap(err, "")
	}

	return &Resource{
		Container: c,
	}, nil
}

func (d *Pool) Purge(r *Resource) error {
	if err := d.Client.KillContainer(dc.KillContainerOptions{ID: r.Container.ID}); err != nil {
		return errors.Wrap(err, "")
	}

	if err := d.Client.RemoveContainer(dc.RemoveContainerOptions{ID: r.Container.ID, Force: true, RemoveVolumes: true}); err != nil {
		return errors.Wrap(err, "")
	}

	return nil
}

func (d *Pool) Retry(op func() error) error {
	if d.MaxWait == 0 {
		d.MaxWait = time.Minute / 2
	}
	bo := backoff.NewExponentialBackOff()
	bo.MaxInterval = time.Second * 5
	bo.MaxElapsedTime = d.MaxWait
	return backoff.Retry(op, bo)
}
<|endoftext|>


<commit_before>package http

import (
	"bufio"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"

	"v2ray.com/core/app"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/errors"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/transport/internet"
)

// Server is a HTTP proxy server.
type Server struct {
	config *ServerConfig
}

// NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
	space := app.SpaceFromContext(ctx)
	if space == nil {
		return nil, newError("no space in context.")
	}
	s := &Server{
		config: config,
	}
	return s, nil
}

func (*Server) Network() net.NetworkList {
	return net.NetworkList{
		Network: []net.Network{net.Network_TCP},
	}
}

func parseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {
	port := defaultPort
	host, rawPort, err := net.SplitHostPort(rawHost)
	if err != nil {
		if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
			host = rawHost
		} else {
			return net.Destination{}, err
		}
	} else if len(rawPort) > 0 {
		intPort, err := strconv.Atoi(rawPort)
		if err != nil {
			return net.Destination{}, err
		}
		port = net.Port(intPort)
	}

	return net.TCPDestination(net.ParseAddress(host), port), nil
}

func isTimeout(err error) bool {
	nerr, ok := err.(net.Error)
	return ok && nerr.Timeout()
}

func parseBasicAuth(auth string) (username, password string, ok bool) {
	const prefix = "Basic "
	if !strings.HasPrefix(auth, prefix) {
		return
	}
	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
	if err != nil {
		return
	}
	cs := string(c)
	s := strings.IndexByte(cs, ':')
	if s < 0 {
		return
	}
	return cs[:s], cs[s+1:], true
}

func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error {
	reader := bufio.NewReaderSize(conn, 2048)

Start:
	conn.SetReadDeadline(time.Now().Add(time.Second * 16))

	request, err := http.ReadRequest(reader)
	if err != nil {
		trace := newError("failed to read http request").Base(err)
		if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
			trace.AtWarning()
		}
		return trace
	}

	if len(s.config.Accounts) > 0 {
		user, pass, ok := parseBasicAuth(request.Header.Get("Proxy-Authorization"))
		if !ok || !s.config.HasAccount(user, pass) {
			_, err := conn.Write([]byte("HTTP/1.1 401 UNAUTHORIZED\r\n\r\n"))
			return err
		}
	}

	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
	conn.SetReadDeadline(time.Time{})

	defaultPort := net.Port(80)
	if strings.ToLower(request.URL.Scheme) == "https" {
		defaultPort = net.Port(443)
	}
	host := request.Host
	if len(host) == 0 {
		host = request.URL.Host
	}
	dest, err := parseHost(host, defaultPort)
	if err != nil {
		return newError("malformed proxy host: ", host).AtWarning().Base(err)
	}
	log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")

	if strings.ToUpper(request.Method) == "CONNECT" {
		return s.handleConnect(ctx, request, reader, conn, dest, dispatcher)
	}

	keepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive")

	err = s.handlePlainHTTP(ctx, request, reader, conn, dest, dispatcher)
	if err == errWaitAnother {
		if keepAlive {
			goto Start
		}
		err = nil
	}

	return err
}

func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	_, err := writer.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
	if err != nil {
		return newError("failed to write back OK response").Base(err)
	}

	timeout := time.Second * time.Duration(s.config.Timeout)
	if timeout == 0 {
		timeout = time.Minute * 5
	}
	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}

	requestDone := signal.ExecuteAsync(func() error {
		defer ray.InboundInput().Close()

		v2reader := buf.NewReader(reader)
		if err := buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		v2writer := buf.NewWriter(writer)
		if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
			return err
		}
		timer.SetTimeout(time.Second * 2)
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		ray.InboundInput().CloseError()
		ray.InboundOutput().CloseError()
		return newError("connection ends").Base(err)
	}

	runtime.KeepAlive(timer)

	return nil
}

// @VisibleForTesting
func StripHopByHopHeaders(header http.Header) {
	// Strip hop-by-hop header basaed on RFC:
	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do

	header.Del("Proxy-Connection")
	header.Del("Proxy-Authenticate")
	header.Del("Proxy-Authorization")
	header.Del("TE")
	header.Del("Trailers")
	header.Del("Transfer-Encoding")
	header.Del("Upgrade")

	connections := header.Get("Connection")
	header.Del("Connection")
	if len(connections) == 0 {
		return
	}
	for _, h := range strings.Split(connections, ",") {
		header.Del(strings.TrimSpace(h))
	}
}

var errWaitAnother = newError("keep alive")

func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	if len(request.URL.Host) <= 0 {
		response := &http.Response{
			Status:        "Bad Request",
			StatusCode:    400,
			Proto:         "HTTP/1.1",
			ProtoMajor:    1,
			ProtoMinor:    1,
			Header:        http.Header(make(map[string][]string)),
			Body:          nil,
			ContentLength: 0,
			Close:         true,
		}
		response.Header.Set("Proxy-Connection", "close")
		response.Header.Set("Connection", "close")
		return response.Write(writer)
	}

	request.Host = request.URL.Host
	StripHopByHopHeaders(request.Header)

	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}
	input := ray.InboundInput()
	output := ray.InboundOutput()
	defer input.Close()

	var result error = errWaitAnother

	requestDone := signal.ExecuteAsync(func() error {
		request.Header.Set("Connection", "close")

		requestWriter := buf.ToBytesWriter(ray.InboundInput())
		if err := request.Write(requestWriter); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		responseReader := bufio.NewReaderSize(buf.ToBytesReader(ray.InboundOutput()), 2048)
		response, err := http.ReadResponse(responseReader, request)
		if err == nil {
			StripHopByHopHeaders(response.Header)
			if response.ContentLength >= 0 {
				response.Header.Set("Proxy-Connection", "keep-alive")
				response.Header.Set("Connection", "keep-alive")
				response.Header.Set("Keep-Alive", "timeout=4")
				response.Close = false
			} else {
				response.Close = true
				result = nil
			}
		} else {
			log.Trace(newError("failed to read response from ", request.Host).Base(err).AtWarning())
			response = &http.Response{
				Status:        "Service Unavailable",
				StatusCode:    503,
				Proto:         "HTTP/1.1",
				ProtoMajor:    1,
				ProtoMinor:    1,
				Header:        http.Header(make(map[string][]string)),
				Body:          nil,
				ContentLength: 0,
				Close:         true,
			}
			response.Header.Set("Connection", "close")
			response.Header.Set("Proxy-Connection", "close")
		}
		if err := response.Write(writer); err != nil {
			return newError("failed to write response").Base(err)
		}
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		input.CloseError()
		output.CloseError()
		return newError("connection ends").Base(err)
	}

	return result
}

func init() {
	common.Must(common.RegisterConfig((*ServerConfig)(nil), func(ctx context.Context, config interface{}) (interface{}, error) {
		return NewServer(ctx, config.(*ServerConfig))
	}))
}
<commit_msg>Prevent UA from being set to golang's default ones<commit_after>package http

import (
	"bufio"
	"context"
	"encoding/base64"
	"io"
	"net/http"
	"runtime"
	"strconv"
	"strings"
	"time"

	"v2ray.com/core/app"
	"v2ray.com/core/app/dispatcher"
	"v2ray.com/core/app/log"
	"v2ray.com/core/common"
	"v2ray.com/core/common/buf"
	"v2ray.com/core/common/errors"
	"v2ray.com/core/common/net"
	"v2ray.com/core/common/signal"
	"v2ray.com/core/transport/internet"
)

// Server is a HTTP proxy server.
type Server struct {
	config *ServerConfig
}

// NewServer creates a new HTTP inbound handler.
func NewServer(ctx context.Context, config *ServerConfig) (*Server, error) {
	space := app.SpaceFromContext(ctx)
	if space == nil {
		return nil, newError("no space in context.")
	}
	s := &Server{
		config: config,
	}
	return s, nil
}

func (*Server) Network() net.NetworkList {
	return net.NetworkList{
		Network: []net.Network{net.Network_TCP},
	}
}

func parseHost(rawHost string, defaultPort net.Port) (net.Destination, error) {
	port := defaultPort
	host, rawPort, err := net.SplitHostPort(rawHost)
	if err != nil {
		if addrError, ok := err.(*net.AddrError); ok && strings.Contains(addrError.Err, "missing port") {
			host = rawHost
		} else {
			return net.Destination{}, err
		}
	} else if len(rawPort) > 0 {
		intPort, err := strconv.Atoi(rawPort)
		if err != nil {
			return net.Destination{}, err
		}
		port = net.Port(intPort)
	}

	return net.TCPDestination(net.ParseAddress(host), port), nil
}

func isTimeout(err error) bool {
	nerr, ok := err.(net.Error)
	return ok && nerr.Timeout()
}

func parseBasicAuth(auth string) (username, password string, ok bool) {
	const prefix = "Basic "
	if !strings.HasPrefix(auth, prefix) {
		return
	}
	c, err := base64.StdEncoding.DecodeString(auth[len(prefix):])
	if err != nil {
		return
	}
	cs := string(c)
	s := strings.IndexByte(cs, ':')
	if s < 0 {
		return
	}
	return cs[:s], cs[s+1:], true
}

func (s *Server) Process(ctx context.Context, network net.Network, conn internet.Connection, dispatcher dispatcher.Interface) error {
	reader := bufio.NewReaderSize(conn, 2048)

Start:
	conn.SetReadDeadline(time.Now().Add(time.Second * 16))

	request, err := http.ReadRequest(reader)
	if err != nil {
		trace := newError("failed to read http request").Base(err)
		if errors.Cause(err) != io.EOF && !isTimeout(errors.Cause(err)) {
			trace.AtWarning()
		}
		return trace
	}

	if len(s.config.Accounts) > 0 {
		user, pass, ok := parseBasicAuth(request.Header.Get("Proxy-Authorization"))
		if !ok || !s.config.HasAccount(user, pass) {
			_, err := conn.Write([]byte("HTTP/1.1 401 UNAUTHORIZED\r\n\r\n"))
			return err
		}
	}

	log.Trace(newError("request to Method [", request.Method, "] Host [", request.Host, "] with URL [", request.URL, "]"))
	conn.SetReadDeadline(time.Time{})

	defaultPort := net.Port(80)
	if strings.ToLower(request.URL.Scheme) == "https" {
		defaultPort = net.Port(443)
	}
	host := request.Host
	if len(host) == 0 {
		host = request.URL.Host
	}
	dest, err := parseHost(host, defaultPort)
	if err != nil {
		return newError("malformed proxy host: ", host).AtWarning().Base(err)
	}
	log.Access(conn.RemoteAddr(), request.URL, log.AccessAccepted, "")

	if strings.ToUpper(request.Method) == "CONNECT" {
		return s.handleConnect(ctx, request, reader, conn, dest, dispatcher)
	}

	keepAlive := (strings.TrimSpace(strings.ToLower(request.Header.Get("Proxy-Connection"))) == "keep-alive")

	err = s.handlePlainHTTP(ctx, request, reader, conn, dest, dispatcher)
	if err == errWaitAnother {
		if keepAlive {
			goto Start
		}
		err = nil
	}

	return err
}

func (s *Server) handleConnect(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	_, err := writer.Write([]byte("HTTP/1.1 200 Connection established\r\n\r\n"))
	if err != nil {
		return newError("failed to write back OK response").Base(err)
	}

	timeout := time.Second * time.Duration(s.config.Timeout)
	if timeout == 0 {
		timeout = time.Minute * 5
	}
	ctx, timer := signal.CancelAfterInactivity(ctx, timeout)
	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}

	requestDone := signal.ExecuteAsync(func() error {
		defer ray.InboundInput().Close()

		v2reader := buf.NewReader(reader)
		if err := buf.Copy(v2reader, ray.InboundInput(), buf.UpdateActivity(timer)); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		v2writer := buf.NewWriter(writer)
		if err := buf.Copy(ray.InboundOutput(), v2writer, buf.UpdateActivity(timer)); err != nil {
			return err
		}
		timer.SetTimeout(time.Second * 2)
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		ray.InboundInput().CloseError()
		ray.InboundOutput().CloseError()
		return newError("connection ends").Base(err)
	}

	runtime.KeepAlive(timer)

	return nil
}

// @VisibleForTesting
func StripHopByHopHeaders(header http.Header) {
	// Strip hop-by-hop header basaed on RFC:
	// http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.5.1
	// https://www.mnot.net/blog/2011/07/11/what_proxies_must_do

	header.Del("Proxy-Connection")
	header.Del("Proxy-Authenticate")
	header.Del("Proxy-Authorization")
	header.Del("TE")
	header.Del("Trailers")
	header.Del("Transfer-Encoding")
	header.Del("Upgrade")

	connections := header.Get("Connection")
	header.Del("Connection")
	if len(connections) == 0 {
		return
	}
	for _, h := range strings.Split(connections, ",") {
		header.Del(strings.TrimSpace(h))
	}

	// Prevent UA from being set to golang's default ones
	if len(header.Get("User-Agent")) == 0 {
		header.Set("User-Agent", "")
	}
}

var errWaitAnother = newError("keep alive")

func (s *Server) handlePlainHTTP(ctx context.Context, request *http.Request, reader io.Reader, writer io.Writer, dest net.Destination, dispatcher dispatcher.Interface) error {
	if len(request.URL.Host) <= 0 {
		response := &http.Response{
			Status:        "Bad Request",
			StatusCode:    400,
			Proto:         "HTTP/1.1",
			ProtoMajor:    1,
			ProtoMinor:    1,
			Header:        http.Header(make(map[string][]string)),
			Body:          nil,
			ContentLength: 0,
			Close:         true,
		}
		response.Header.Set("Proxy-Connection", "close")
		response.Header.Set("Connection", "close")
		return response.Write(writer)
	}

	request.Host = request.URL.Host
	StripHopByHopHeaders(request.Header)

	ray, err := dispatcher.Dispatch(ctx, dest)
	if err != nil {
		return err
	}
	input := ray.InboundInput()
	output := ray.InboundOutput()
	defer input.Close()

	var result error = errWaitAnother

	requestDone := signal.ExecuteAsync(func() error {
		request.Header.Set("Connection", "close")

		requestWriter := buf.ToBytesWriter(ray.InboundInput())
		if err := request.Write(requestWriter); err != nil {
			return err
		}
		return nil
	})

	responseDone := signal.ExecuteAsync(func() error {
		responseReader := bufio.NewReaderSize(buf.ToBytesReader(ray.InboundOutput()), 2048)
		response, err := http.ReadResponse(responseReader, request)
		if err == nil {
			StripHopByHopHeaders(response.Header)
			if response.ContentLength >= 0 {
				response.Header.Set("Proxy-Connection", "keep-alive")
				response.Header.Set("Connection", "keep-alive")
				response.Header.Set("Keep-Alive", "timeout=4")
				response.Close = false
			} else {
				response.Close = true
				result = nil
			}
		} else {
			log.Trace(newError("failed to read response from ", request.Host).Base(err).AtWarning())
			response = &http.Response{
				Status:        "Service Unavailable",
				StatusCode:    503,
				Proto:         "HTTP/1.1",
				ProtoMajor:    1,
				ProtoMinor:    1,
				Header:        http.Header(make(map[string][]string)),
				Body:          nil,
				ContentLength: 0,
				Close:         true,
			}
			response.Header.Set("Connection", "close")
			response.Header.Set("Proxy-Connection", "close")
		}
		if err := response.Write(writer); err != nil {
			return newError("failed to write response").Base(err)
		}
		return nil
	})

	if err := signal.ErrorOrFinish2(ctx, requestDone, responseDone); err != nil {
		input.CloseError()
		output.CloseError()
		return newError("connection ends").Base(err)
	}

	return result
}

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


<commit_before>package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"regexp"

	"github.com/ActiveState/tail"
)

var follow = false
const version = "v0.1.0"

func main() {
	matchers := processArgs()

	appLog := os.Getenv("BOXEN_APPLICATION_LOG")
	if appLog == "" {
		appLog = os.Getenv("APPLICATION_LOG")
	}
	if appLog == "" {
		appLog = "/var/log/application.log"
	}

	t, err := tail.TailFile(appLog, tail.Config{
		Follow: follow,
		ReOpen: follow,
		MustExist: true,
	})

	if err != nil {
		log.Fatal(err.Error())
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)

	go func(t *tail.Tail) {
		sig := <-ch
		fmt.Println("received", sig)
		t.Stop()
	}(t)

	for line := range t.Lines {
		matched := true

		for _, matcher := range matchers {
			if matched == false {
				break
			} else {
				matched, err = regexp.MatchString(matcher, line.Text)
				if err != nil {
					log.Fatal(err.Error())
				}
			}
		}

		if matched == true {
			fmt.Println(line.Text)
		}
	}
}

func processArgs() (matchers []string) {
	for _, arg := range os.Args[1:] {
		switch arg {
		case "--version", "-v":
			fmt.Println("log-me", version)
			os.Exit(0)
		case "--tail", "-t":
			follow = true
		default:
			matchers = append(matchers, massageMatcher(arg))
		}
	}
	return
}

func massageMatcher(matcher string) (massaged string) {
	massager, err := regexp.Compile("\\*")
	if err != nil {
		log.Fatal(err.Error())
	}

	massaged = massager.ReplaceAllLiteralString(matcher, ".*")
	return
}<commit_msg>v0.1.1<commit_after>package main

import (
	"fmt"
	"log"
	"os"
	"os/signal"
	"regexp"

	"github.com/ActiveState/tail"
)

var follow = false
const version = "v0.1.1"

func main() {
	matchers := processArgs()

	appLog := os.Getenv("BOXEN_APPLICATION_LOG")
	if appLog == "" {
		appLog = os.Getenv("APPLICATION_LOG")
	}
	if appLog == "" {
		appLog = "/var/log/application.log"
	}

	t, err := tail.TailFile(appLog, tail.Config{
		Follow: follow,
		ReOpen: follow,
		MustExist: true,
	})

	if err != nil {
		log.Fatal(err.Error())
	}

	ch := make(chan os.Signal, 1)
	signal.Notify(ch, os.Interrupt)

	go func(t *tail.Tail) {
		sig := <-ch
		fmt.Println("received", sig)
		t.Stop()
	}(t)

	for line := range t.Lines {
		matched := true

		for _, matcher := range matchers {
			if matched == false {
				break
			} else {
				matched, err = regexp.MatchString(matcher, line.Text)
				if err != nil {
					log.Fatal(err.Error())
				}
			}
		}

		if matched == true {
			fmt.Println(line.Text)
		}
	}
}

func processArgs() (matchers []string) {
	for _, arg := range os.Args[1:] {
		switch arg {
		case "--version", "-v":
			fmt.Println("log-me", version)
			os.Exit(0)
		case "--tail", "-t":
			follow = true
		default:
			matchers = append(matchers, massageMatcher(arg))
		}
	}
	return
}

func massageMatcher(matcher string) (massaged string) {
	massager, err := regexp.Compile("\\*")
	if err != nil {
		log.Fatal(err.Error())
	}

	massaged = massager.ReplaceAllLiteralString(matcher, ".*")
	return
}<|endoftext|>


<commit_before>package main

import (
	"encoding/json"
	"os"
	"fmt"
	"strconv"
	_ "github.com/lib/pq"
	"database/sql"
	"log"
)

type Test struct {
	Queries	[]string
	Count	interface{}
}

type Configuration struct {
	Host	string
	Port	int
	DbName	string
	Tests	[]Test
}

func main() {
	// Get DB username and password from environment variables
	dbuser := os.Getenv("DBUSER")
	dbpass := os.Getenv("DBPASS")

	// Read the configuration file
	file, err := os.Open("test.json")
	if err != nil {
		fmt.Println("error reading file:", err)
	}

	decoder := json.NewDecoder(file)
	configuration := Configuration{}

	err = decoder.Decode(&configuration)
	if err != nil {
		fmt.Println("error:", err)
	}

	conn_string := "host=" + configuration.Host
	conn_string += " port=" + strconv.Itoa(configuration.Port)
	conn_string += " dbname=" + configuration.DbName
	conn_string += " user=" + dbuser
	conn_string += " password=" + dbpass

	db, err := sql.Open("postgres", conn_string)
	if err != nil {
		log.Fatal(err)
	}

	defer db.Close()

	for _, test := range configuration.Tests {
		for _, query := range test.Queries {
			var cnt int
			err = db.QueryRow(query).Scan(&cnt)
			switch {
			case err == sql.ErrNoRows:
				log.Printf("No rows returned")
			case err != nil:
				log.Fatal(err)
			default:
				fmt.Printf("Count:%d\n",cnt)
			}
		}
	}

}
<commit_msg>End of day commit<commit_after>package main

import (
	"encoding/json"
	"os"
	"fmt"
	"strconv"
	_ "github.com/lib/pq"
	"database/sql"
	"log"
)

type Test struct {
	Name    string
	Queries	[]string
	Count	interface{}
}

type Configuration struct {
	Host	string
	Port	int
	DbName	string
	Tests	[]Test
}

func main() {
	// Get DB username and password from environment variables
	dbuser := os.Getenv("DBUSER")
	dbpass := os.Getenv("DBPASS")

	// Read the configuration file
	file, err := os.Open("test.json")
	if err != nil {
		fmt.Println("error reading file:", err)
	}

	decoder := json.NewDecoder(file)
	configuration := Configuration{}

	err = decoder.Decode(&configuration)
	if err != nil {
		fmt.Println("error:", err)
	}

	conn_string := "host=" + configuration.Host
	conn_string += " port=" + strconv.Itoa(configuration.Port)
	conn_string += " dbname=" + configuration.DbName
	conn_string += " user=" + dbuser
	conn_string += " password=" + dbpass

	db, err := sql.Open("postgres", conn_string)
	if err != nil {
		log.Fatal(err)
	}

	defer db.Close()

	for _, test := range configuration.Tests {
		if len(test.Queries) == 1 {
			query := test.Queries[0]
			var cnt int
			err = db.QueryRow(query).Scan(&cnt)
			switch {
			case err != nil:
				log.Fatal(err)
			default:
				if cnt != test.Count {
					log.Fatal("Test %s failed. Expected count %d, received count %d", test.Name, test.Count, cnt)
				}
			}

		} else if len(test.Queries) == 2 {

			var op string
			switch v := test.Count.(type) {
			case string:
				op = test.Count
			default:
				log.Fatal("Invalid operator type specified")
			}

			query1 := test.Queries[0]
			query2 := test.Queries[1]

			var cnt1, cnt2 int

			err = db.QueryRow(query1).Scan(&cnt1)
			switch {
			case err != nil:
				log.Fatal(err)
			default:
			}

			err = db.QueryRow(query2).Scan(&cnt2)
			switch {
			case err != nil:
				log.Fatal(err)
			default:
				if
			}

		}

		} else {
				log.Fatal("Incorrect number of queries in test %s\n", test.Name)
		}

	}

}
<|endoftext|>


<commit_before>package console

import (
	"fmt"
	"github.com/cheggaaa/pb"
	"github.com/smira/aptly/aptly"
	"github.com/wsxiaoys/terminal/color"
	"strings"
)

const (
	codePrint = iota
	codeProgress
	codeHideProgress
)

type printTask struct {
	code    int
	message string
}

// Progress is a progress displaying subroutine, it allows to show download and other operations progress
// mixed with progress bar
type Progress struct {
	stop     chan bool
	stopped  chan bool
	queue    chan printTask
	bar      *pb.ProgressBar
	barShown bool
}

// Check interface
var (
	_ aptly.Progress = (*Progress)(nil)
)

// NewProgress creates new progress instance
func NewProgress() *Progress {
	return &Progress{
		stop:    make(chan bool),
		stopped: make(chan bool),
		queue:   make(chan printTask, 100),
	}
}

// Start makes progress start its work
func (p *Progress) Start() {
	go p.worker()
}

// Shutdown shuts down progress display
func (p *Progress) Shutdown() {
	p.ShutdownBar()
	p.stop <- true
	<-p.stopped
}

// InitBar starts progressbar for count bytes or count items
func (p *Progress) InitBar(count int64, isBytes bool) {
	if p.bar != nil {
		panic("bar already initialized")
	}
	if RunningOnTerminal() {
		p.bar = pb.New(0)
		p.bar.Total = count
		p.bar.NotPrint = true
		p.bar.Callback = func(out string) {
			p.queue <- printTask{code: codeProgress, message: out}
		}

		if isBytes {
			p.bar.SetUnits(pb.U_BYTES)
			p.bar.ShowSpeed = true
		}
		p.bar.Start()
	}
}

// ShutdownBar stops progress bar and hides it
func (p *Progress) ShutdownBar() {
	if p.bar == nil {
		return
	}
	p.bar.Finish()
	p.bar = nil
	p.queue <- printTask{code: codeHideProgress}
}

// Write is implementation of io.Writer to support updating of progress bar
func (p *Progress) Write(s []byte) (int, error) {
	if p.bar != nil {
		p.bar.Add(len(s))
	}
	return len(s), nil
}

// AddBar increments progress for progress bar
func (p *Progress) AddBar(count int) {
	if p.bar != nil {
		p.bar.Add(count)
	}
}

// Printf does printf but in safe manner: not overwriting progress bar
func (p *Progress) Printf(msg string, a ...interface{}) {
	p.queue <- printTask{code: codePrint, message: fmt.Sprintf(msg, a...)}
}

// ColoredPrintf does printf in colored way + newline
func (p *Progress) ColoredPrintf(msg string, a ...interface{}) {
	if RunningOnTerminal() {
		p.queue <- printTask{code: codePrint, message: color.Sprintf(msg, a...) + "\n"}
	} else {
		// stip color marks
		var prev rune
		msg = strings.Map(func(r rune) rune {
			if prev == '@' {
				prev = 0
				if r == '@' {
					return r
				}
				return -1
			}
			prev = r
			if r == '@' {
				return -1

			}

			return r
		}, msg)

		p.Printf(msg+"\n", a...)
	}
}

func (p *Progress) worker() {
	for {
		select {
		case task := <-p.queue:
			switch task.code {
			case codePrint:
				if p.barShown {
					fmt.Print("\r\033[2K")
					p.barShown = false
				}
				fmt.Print(task.message)
			case codeProgress:
				if p.bar != nil {
					fmt.Print("\r" + task.message)
					p.barShown = true
				}
			case codeHideProgress:
				if p.barShown {
					fmt.Print("\r\033[2K")
					p.barShown = false
				}
			}
		case <-p.stop:
			p.stopped <- true
			return
		}
	}
}
<commit_msg>Fix race in Progress shutdown where some messages could have been lost.<commit_after>package console

import (
	"fmt"
	"github.com/cheggaaa/pb"
	"github.com/smira/aptly/aptly"
	"github.com/wsxiaoys/terminal/color"
	"strings"
)

const (
	codePrint = iota
	codeProgress
	codeHideProgress
	codeStop
)

type printTask struct {
	code    int
	message string
}

// Progress is a progress displaying subroutine, it allows to show download and other operations progress
// mixed with progress bar
type Progress struct {
	stop     chan bool
	stopped  chan bool
	queue    chan printTask
	bar      *pb.ProgressBar
	barShown bool
}

// Check interface
var (
	_ aptly.Progress = (*Progress)(nil)
)

// NewProgress creates new progress instance
func NewProgress() *Progress {
	return &Progress{
		stopped: make(chan bool),
		queue:   make(chan printTask, 100),
	}
}

// Start makes progress start its work
func (p *Progress) Start() {
	go p.worker()
}

// Shutdown shuts down progress display
func (p *Progress) Shutdown() {
	p.ShutdownBar()
	p.queue <- printTask{code: codeStop}
	<-p.stopped
}

// InitBar starts progressbar for count bytes or count items
func (p *Progress) InitBar(count int64, isBytes bool) {
	if p.bar != nil {
		panic("bar already initialized")
	}
	if RunningOnTerminal() {
		p.bar = pb.New(0)
		p.bar.Total = count
		p.bar.NotPrint = true
		p.bar.Callback = func(out string) {
			p.queue <- printTask{code: codeProgress, message: out}
		}

		if isBytes {
			p.bar.SetUnits(pb.U_BYTES)
			p.bar.ShowSpeed = true
		}
		p.bar.Start()
	}
}

// ShutdownBar stops progress bar and hides it
func (p *Progress) ShutdownBar() {
	if p.bar == nil {
		return
	}
	p.bar.Finish()
	p.bar = nil
	p.queue <- printTask{code: codeHideProgress}
}

// Write is implementation of io.Writer to support updating of progress bar
func (p *Progress) Write(s []byte) (int, error) {
	if p.bar != nil {
		p.bar.Add(len(s))
	}
	return len(s), nil
}

// AddBar increments progress for progress bar
func (p *Progress) AddBar(count int) {
	if p.bar != nil {
		p.bar.Add(count)
	}
}

// Printf does printf but in safe manner: not overwriting progress bar
func (p *Progress) Printf(msg string, a ...interface{}) {
	p.queue <- printTask{code: codePrint, message: fmt.Sprintf(msg, a...)}
}

// ColoredPrintf does printf in colored way + newline
func (p *Progress) ColoredPrintf(msg string, a ...interface{}) {
	if RunningOnTerminal() {
		p.queue <- printTask{code: codePrint, message: color.Sprintf(msg, a...) + "\n"}
	} else {
		// stip color marks
		var prev rune
		msg = strings.Map(func(r rune) rune {
			if prev == '@' {
				prev = 0
				if r == '@' {
					return r
				}
				return -1
			}
			prev = r
			if r == '@' {
				return -1

			}

			return r
		}, msg)

		p.Printf(msg+"\n", a...)
	}
}

func (p *Progress) worker() {
	for {
		task := <-p.queue
		switch task.code {
		case codePrint:
			if p.barShown {
				fmt.Print("\r\033[2K")
				p.barShown = false
			}
			fmt.Print(task.message)
		case codeProgress:
			if p.bar != nil {
				fmt.Print("\r" + task.message)
				p.barShown = true
			}
		case codeHideProgress:
			if p.barShown {
				fmt.Print("\r\033[2K")
				p.barShown = false
			}
		case codeStop:
			p.stopped <- true
			return
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

// Package logger provides a simple logging interface that supports multiple
// levels of logging. It goes up to 11.
package logger

import (
	"fmt"
	"log"

	"github.com/mgutz/ansi"
)

const (
	// Silent logs no output at all.
	Silent = iota

	// Error logs only errors.
	Error = iota

	// Blocked logs blocking calls and lower.
	Blocked = iota

	// Warn logs warnings and lower.
	Warn = iota

	// Reject logs rejections (e.g., in a firewall) and lower.
	Reject = iota

	// Listen logs listeners and lower.
	Listen = iota

	// Install logs install notifications and lower.
	Install = iota

	// Init logs initialization notifications and lower.
	Init = iota

	// Request logs incoming requests and lower.
	Request = iota

	// Info logs info output and lower.
	Info = iota

	// Verbose logs all verbose output and lower.
	Verbose = iota

	// Debug logs all log output.
	Debug = iota

	max = iota
)

// Logger only outputs log messages that are equal or lower than its log level.
type Logger struct{ level int }

// LogLevel translates human-readable log level names to their int values.
var LogLevel = map[string]int{
	"silent":  Silent,
	"error":   Error,
	"blocked": Blocked,
	"warn":    Warn,
	"reject":  Reject,
	"listen":  Listen,
	"install": Install,
	"init":    Init,
	"request": Request,
	"info":    Info,
	"verbose": Verbose,
	"debug":   Debug}

var prefixes = [...]string{
	"",
	ansi.Color("[***error***]", "black:red"),
	ansi.Color("[**blocked**]", "255+b:165"),
	ansi.Color("[**warning**]", "red:yellow+h"),
	ansi.Color("[ rejection ]", "125+b:208"),
	ansi.Color("[ listening ]", "black:cyan+h"),
	/*      */ "[ installed ]",
	/*      */ "[initialized]",
	/*      */ "[  request  ]",
	/*      */ "[information]",
	/*      */ "[  verbose  ]",
	/*      */ "[   debug   ]"}

func out(loggerLevel, messageLevel int, format string, v ...interface{}) {
	if loggerLevel == Silent || messageLevel == Silent {
		return
	}
	message := fmt.Sprintf(format, v...)
	if messageLevel > Silent && messageLevel <= loggerLevel {
		log.Printf("%s %s", prefixes[messageLevel], message)
	}
}

// Level returns a logger instance's log level if logger level allows.
func (l *Logger) Level() int { return l.level }

// SetLevel sets a logger instance's log level if logger level allows.
func (l *Logger) SetLevel(level int) error {
	if level > Debug || level < Silent {
		return fmt.Errorf("logger level must be >= %d and < %d", Silent, max)
	}
	l.level = level
	return nil
}

// Error logs an error if logger level allows.
func (l *Logger) Error(format string, v ...interface{}) {
	out(l.level, Error, format, v...)
}

// Blocked logs a blocked message if logger level allows.
func (l *Logger) Blocked(format string, v ...interface{}) {
	out(l.level, Blocked, format, v...)
}

// Warn logs a warning if logger level allows.
func (l *Logger) Warn(format string, v ...interface{}) {
	out(l.level, Warn, format, v...)
}

// Reject logs a rejection if logger level allows.
func (l *Logger) Reject(format string, v ...interface{}) {
	out(l.level, Reject, format, v...)
}

// Listen logs a listener message if logger level allows.
func (l *Logger) Listen(format string, v ...interface{}) {
	out(l.level, Listen, format, v...)
}

// Install logs an install message if logger level allows.
func (l *Logger) Install(format string, v ...interface{}) {
	out(l.level, Install, format, v...)
}

// Init logs an initialization message if logger level allows.
func (l *Logger) Init(format string, v ...interface{}) {
	out(l.level, Init, format, v...)
}

// Request logs a request if logger level allows.
func (l *Logger) Request(format string, v ...interface{}) {
	out(l.level, Request, format, v...)
}

// Info logs an info message if logger level allows.
func (l *Logger) Info(format string, v ...interface{}) {
	out(l.level, Info, format, v...)
}

// Verbose logs a verbose message if logger level allows.
func (l *Logger) Verbose(format string, v ...interface{}) {
	out(l.level, Verbose, format, v...)
}

// Debug logs a debug message if logger level allows.
func (l *Logger) Debug(format string, v ...interface{}) {
	out(l.level, Debug, format, v...)
}

// MustError logs an error.
func MustError(format string, v ...interface{}) {
	out(max, Error, format, v...)
}

// MustBlocked logs a blocked message.
func MustBlocked(format string, v ...interface{}) {
	out(max, Blocked, format, v...)
}

// MustWarn logs a warning.
func MustWarn(format string, v ...interface{}) {
	out(max, Warn, format, v...)
}

// MustReject logs a rejection.
func MustReject(format string, v ...interface{}) {
	out(max, Reject, format, v...)
}

// MustListen logs a listener message.
func MustListen(format string, v ...interface{}) {
	out(max, Listen, format, v...)
}

// MustInstall logs an install message.
func MustInstall(format string, v ...interface{}) {
	out(max, Install, format, v...)
}

// MustInit logs an initialization message.
func MustInit(format string, v ...interface{}) {
	out(max, Init, format, v...)
}

// MustRequest logs a request.
func MustRequest(format string, v ...interface{}) {
	out(max, Request, format, v...)
}

// MustInfo logs an info message.
func MustInfo(format string, v ...interface{}) {
	out(max, Info, format, v...)
}

// MustVerbose logs a verbose message.
func MustVerbose(format string, v ...interface{}) {
	out(max, Verbose, format, v...)
}

// MustDebug logs a debug message.
func MustDebug(format string, v ...interface{}) {
	out(max, Debug, format, v...)
}

// New instantiates a Logger and sets its level. If the level is invalid, it
// returns an error.
func New(level int) (*Logger, error) {
	l := new(Logger)
	if err := l.SetLevel(level); err != nil {
		return nil, err
	}
	return l, nil
}
<commit_msg>add Unblocked<commit_after>// Copyright 2016 Afshin Darian. All rights reserved.
// Use of this source code is governed by The MIT License
// that can be found in the LICENSE file.

// Package logger provides a simple logging interface that supports multiple
// levels of logging. It goes up to 11.
package logger

import (
	"fmt"
	"log"

	"github.com/mgutz/ansi"
)

const (
	// Silent logs no output at all.
	Silent = iota

	// Error logs only errors.
	Error = iota

	// Blocked logs blocking calls and lower.
	Blocked = iota

	// Unblocked logs all unblocked notifications and lower.
	Unblocked = iota

	// Warn logs warnings and lower.
	Warn = iota

	// Reject logs rejections (e.g., in a firewall) and lower.
	Reject = iota

	// Listen logs listeners and lower.
	Listen = iota

	// Install logs install notifications and lower.
	Install = iota

	// Init logs initialization notifications and lower.
	Init = iota

	// Request logs incoming requests and lower.
	Request = iota

	// Info logs info output and lower.
	Info = iota

	// Debug logs all log output.
	Debug = iota

	max = iota
)

// Logger only outputs log messages that are equal or lower than its log level.
type Logger struct{ level int }

// LogLevel translates human-readable log level names to their int values.
var LogLevel = map[string]int{
	"silent":    Silent,
	"error":     Error,
	"blocked":   Blocked,
	"unblocked": Unblocked,
	"warn":      Warn,
	"reject":    Reject,
	"listen":    Listen,
	"install":   Install,
	"init":      Init,
	"request":   Request,
	"info":      Info,
	"debug":     Debug}

var prefixes = [...]string{
	"",
	ansi.Color("[***error***]", "black:red"),
	ansi.Color("[**blocked**]", "255+b:165"),
	ansi.Color("[*unblocked*]", "255+b:165"),
	ansi.Color("[**warning**]", "red:yellow+h"),
	ansi.Color("[ rejection ]", "125+b:208"),
	ansi.Color("[ listening ]", "black:cyan+h"),
	/*      */ "[ installed ]",
	/*      */ "[initialized]",
	/*      */ "[  request  ]",
	/*      */ "[information]",
	/*      */ "[   debug   ]"}

func out(loggerLevel, messageLevel int, format string, v ...interface{}) {
	if loggerLevel == Silent || messageLevel == Silent {
		return
	}
	message := fmt.Sprintf(format, v...)
	if messageLevel > Silent && messageLevel <= loggerLevel {
		log.Printf("%s %s", prefixes[messageLevel], message)
	}
}

// Level returns a logger instance's log level if logger level allows.
func (l *Logger) Level() int { return l.level }

// SetLevel sets a logger instance's log level if logger level allows.
func (l *Logger) SetLevel(level int) error {
	if level > Debug || level < Silent {
		return fmt.Errorf("logger level must be >= %d and < %d", Silent, max)
	}
	l.level = level
	return nil
}

// Error logs an error if logger level allows.
func (l *Logger) Error(format string, v ...interface{}) {
	out(l.level, Error, format, v...)
}

// Blocked logs a blocked message if logger level allows.
func (l *Logger) Blocked(format string, v ...interface{}) {
	out(l.level, Blocked, format, v...)
}

// Unblocked logs an unblocked notification if logger level allows.
func (l *Logger) Unblocked(format string, v ...interface{}) {
	out(l.level, Unblocked, format, v...)
}

// Warn logs a warning if logger level allows.
func (l *Logger) Warn(format string, v ...interface{}) {
	out(l.level, Warn, format, v...)
}

// Reject logs a rejection if logger level allows.
func (l *Logger) Reject(format string, v ...interface{}) {
	out(l.level, Reject, format, v...)
}

// Listen logs a listener message if logger level allows.
func (l *Logger) Listen(format string, v ...interface{}) {
	out(l.level, Listen, format, v...)
}

// Install logs an install message if logger level allows.
func (l *Logger) Install(format string, v ...interface{}) {
	out(l.level, Install, format, v...)
}

// Init logs an initialization message if logger level allows.
func (l *Logger) Init(format string, v ...interface{}) {
	out(l.level, Init, format, v...)
}

// Request logs a request if logger level allows.
func (l *Logger) Request(format string, v ...interface{}) {
	out(l.level, Request, format, v...)
}

// Info logs an info message if logger level allows.
func (l *Logger) Info(format string, v ...interface{}) {
	out(l.level, Info, format, v...)
}

// Debug logs a debug message if logger level allows.
func (l *Logger) Debug(format string, v ...interface{}) {
	out(l.level, Debug, format, v...)
}

// MustError logs an error.
func MustError(format string, v ...interface{}) {
	out(max, Error, format, v...)
}

// MustBlocked logs a blocked message.
func MustBlocked(format string, v ...interface{}) {
	out(max, Blocked, format, v...)
}

// MustUnblocked logs an unblocked message.
func MustUnblocked(format string, v ...interface{}) {
	out(max, Unblocked, format, v...)
}

// MustWarn logs a warning.
func MustWarn(format string, v ...interface{}) {
	out(max, Warn, format, v...)
}

// MustReject logs a rejection.
func MustReject(format string, v ...interface{}) {
	out(max, Reject, format, v...)
}

// MustListen logs a listener message.
func MustListen(format string, v ...interface{}) {
	out(max, Listen, format, v...)
}

// MustInstall logs an install message.
func MustInstall(format string, v ...interface{}) {
	out(max, Install, format, v...)
}

// MustInit logs an initialization message.
func MustInit(format string, v ...interface{}) {
	out(max, Init, format, v...)
}

// MustRequest logs a request.
func MustRequest(format string, v ...interface{}) {
	out(max, Request, format, v...)
}

// MustInfo logs an info message.
func MustInfo(format string, v ...interface{}) {
	out(max, Info, format, v...)
}

// MustDebug logs a debug message.
func MustDebug(format string, v ...interface{}) {
	out(max, Debug, format, v...)
}

// New instantiates a Logger and sets its level. If the level is invalid, it
// returns an error.
func New(level int) (*Logger, error) {
	l := new(Logger)
	if err := l.SetLevel(level); err != nil {
		return nil, err
	}
	return l, nil
}
<|endoftext|>


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

package indexers

import (
	"errors"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/database"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcutil/gcs"
	"github.com/btcsuite/btcutil/gcs/builder"
	"github.com/btcsuite/btcd/wire"
)

const (
	// cfIndexName is the human-readable name for the index.
	cfIndexName = "committed filter index"
)

// Committed filters come in two flavours: basic and extended. They are
// generated and dropped in pairs, and both are indexed by a block's hash.
// Besides holding different content, they also live in different buckets.
var (
	// cfIndexParentBucketKey is the name of the parent bucket used to house
	// the index. The rest of the buckets live below this bucket.
	cfIndexParentBucketKey = []byte("cfindexparentbucket")

	// cfIndexKeys is an array of db bucket names used to house indexes of
	// block hashes to cfilters.
	cfIndexKeys = [][]byte{
		[]byte("cf0byhashidx"),
		[]byte("cf1byhashidx"),
	}

	// cfHeaderKeys is an array of db bucket names used to house indexes of
	// block hashes to cf headers.
	cfHeaderKeys = [][]byte{
		[]byte("cf0headerbyhashidx"),
		[]byte("cf1headerbyhashidx"),
	}

	// cfHashKeys is an array of db bucket names used to house indexes of
	// block hashes to cf hashes.
	cfHashKeys = [][]byte{
		[]byte("cf0hashbyhashidx"),
		[]byte("cf1hashbyhashidx"),
	}

	maxFilterType = uint8(len(cfHeaderKeys) - 1)

	// zeroHash is the chainhash.Hash value of all zero bytes, defined here for
	// convenience.
	zeroHash chainhash.Hash
)

// dbFetchFilterIdxEntry retrieves a data blob from the filter index database.
// An entry's absence is not considered an error.
func dbFetchFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Get(h[:]), nil
}

// dbStoreFilterIdxEntry stores a data blob in the filter index database.
func dbStoreFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Put(h[:], f)
}

// dbDeleteFilterIdxEntry deletes a data blob from the filter index database.
func dbDeleteFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) error {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Delete(h[:])
}

// CfIndex implements a committed filter (cf) by hash index.
type CfIndex struct {
	db          database.DB
	chainParams *chaincfg.Params
}

// Ensure the CfIndex type implements the Indexer interface.
var _ Indexer = (*CfIndex)(nil)

// Init initializes the hash-based cf index. This is part of the Indexer
// interface.
func (idx *CfIndex) Init() error {
	return nil // Nothing to do.
}

// Key returns the database key to use for the index as a byte slice. This is
// part of the Indexer interface.
func (idx *CfIndex) Key() []byte {
	return cfIndexParentBucketKey
}

// Name returns the human-readable name of the index. This is part of the
// Indexer interface.
func (idx *CfIndex) Name() string {
	return cfIndexName
}

// Create is invoked when the indexer manager determines the index needs to
// be created for the first time. It creates buckets for the two hash-based cf
// indexes (simple, extended).
func (idx *CfIndex) Create(dbTx database.Tx) error {
	meta := dbTx.Metadata()

	cfIndexParentBucket, err := meta.CreateBucket(cfIndexParentBucketKey)
	if err != nil {
		return err
	}

	for _, bucketName := range cfIndexKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	for _, bucketName := range cfHeaderKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	for _, bucketName := range cfHashKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	return nil
}

// storeFilter stores a given filter, and performs the steps needed to
// generate the filter's header.
func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter,
	filterType wire.FilterType) error {
	if uint8(filterType) > maxFilterType {
		return errors.New("unsupported filter type")
	}

	// Figure out which buckets to use.
	fkey := cfIndexKeys[filterType]
	hkey := cfHeaderKeys[filterType]
	hashkey := cfHashKeys[filterType]

	// Start by storing the filter.
	h := block.Hash()
	var basicFilterBytes []byte
	if f != nil {
		basicFilterBytes = f.NBytes()
	}
	err = dbStoreFilterIdxEntry(dbTx, fkey, h, filterBytes)
	if err != nil {
		return err
	}

	// Next store the filter hash.
	filterHash, err := builder.GetFilterHash(f)
	if err != nil {
		return err
	}
	err = dbStoreFilterIdxEntry(dbTx, hashkey, h, filterHash[:])
	if err != nil {
		return err
	}

	// Then fetch the previous block's filter header.
	var prevHeader *chainhash.Hash
	ph := &block.MsgBlock().Header.PrevBlock
	if ph.IsEqual(&zeroHash) {
		prevHeader = &zeroHash
	} else {
		pfh, err := dbFetchFilterIdxEntry(dbTx, hkey, ph)
		if err != nil {
			return err
		}

		// Construct the new block's filter header, and store it.
		prevHeader, err = chainhash.NewHash(pfh)
		if err != nil {
			return err
		}
	}

	fh, err := builder.MakeHeaderForFilter(f, *prevHeader)
	if err != nil {
		return err
	}
	return dbStoreFilterIdxEntry(dbTx, hkey, h, fh[:])
}

// ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain. This indexer adds a hash-to-cf mapping for
// every passed block. This is part of the Indexer interface.
func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
	view *blockchain.UtxoViewpoint) error {

	f, err := builder.BuildBasicFilter(block.MsgBlock())
	if err != nil && err != gcs.ErrNoData {
		return err
	}

	err = storeFilter(dbTx, block, f, wire.GCSFilterRegular)
	if err != nil {
		return err
	}

	f, err = builder.BuildExtFilter(block.MsgBlock())
	if err != nil && err != gcs.ErrNoData {
		return err
	}

	return storeFilter(dbTx, block, f, wire.GCSFilterExtended)
}

// DisconnectBlock is invoked by the index manager when a block has been
// disconnected from the main chain.  This indexer removes the hash-to-cf
// mapping for every passed block. This is part of the Indexer interface.
func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
	view *blockchain.UtxoViewpoint) error {

	for _, key := range cfIndexKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	for _, key := range cfHeaderKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	for _, key := range cfHashKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	return nil
}

// entryByBlockHash fetches a filter index entry of a particular type
// (eg. filter, filter header, etc) for a filter type and block hash.
func (idx *CfIndex) entryByBlockHash(filterTypeKeys [][]byte,
	filterType wire.FilterType, h *chainhash.Hash) ([]byte, error) {

	if uint8(filterType) > maxFilterType {
		return nil, errors.New("unsupported filter type")
	}
	key := filterTypeKeys[filterType]

	var entry []byte
	err := idx.db.View(func(dbTx database.Tx) error {
		var err error
		entry, err = dbFetchFilterIdxEntry(dbTx, key, h)
		return err
	})
	return entry, err
}

// entriesByBlockHashes batch fetches a filter index entry of a particular type
// (eg. filter, filter header, etc) for a filter type and slice of block hashes.
func (idx *CfIndex) entriesByBlockHashes(filterTypeKeys [][]byte,
	filterType wire.FilterType, blockHashes []*chainhash.Hash) ([][]byte, error) {

	if uint8(filterType) > maxFilterType {
		return nil, errors.New("unsupported filter type")
	}
	key := filterTypeKeys[filterType]

	entries := make([][]byte, 0, len(blockHashes))
	err := idx.db.View(func(dbTx database.Tx) error {
		for _, blockHash := range blockHashes {
			entry, err := dbFetchFilterIdxEntry(dbTx, key, blockHash)
			if err != nil {
				return err
			}
			entries = append(entries, entry)
		}
		return nil
	})
	return entries, err
}

// FilterByBlockHash returns the serialized contents of a block's basic or
// extended committed filter.
func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfIndexKeys, filterType, h)
}

// FiltersByBlockHashes returns the serialized contents of a block's basic or
// extended committed filter for a set of blocks by hash.
func (idx *CfIndex) FiltersByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfIndexKeys, filterType, blockHashes)
}

// FilterHeaderByBlockHash returns the serialized contents of a block's basic
// or extended committed filter header.
func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfHeaderKeys, filterType, h)
}

// FilterHeadersByBlockHashes returns the serialized contents of a block's basic
// or extended committed filter header for a set of blocks by hash.
func (idx *CfIndex) FilterHeadersByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfHeaderKeys, filterType, blockHashes)
}

// FilterHashByBlockHash returns the serialized contents of a block's basic
// or extended committed filter hash.
func (idx *CfIndex) FilterHashByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfHashKeys, filterType, h)
}

// FilterHashesByBlockHashes returns the serialized contents of a block's basic
// or extended committed filter hash for a set of blocks by hash.
func (idx *CfIndex) FilterHashesByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfHashKeys, filterType, blockHashes)
}

// NewCfIndex returns a new instance of an indexer that is used to create a
// mapping of the hashes of all blocks in the blockchain to their respective
// committed filters.
//
// It implements the Indexer interface which plugs into the IndexManager that
// in turn is used by the blockchain package. This allows the index to be
// seamlessly maintained along with the chain.
func NewCfIndex(db database.DB, chainParams *chaincfg.Params) *CfIndex {
	return &CfIndex{db: db, chainParams: chainParams}
}

// DropCfIndex drops the CF index from the provided database if exists.
func DropCfIndex(db database.DB, interrupt <-chan struct{}) error {
	return dropIndex(db, cfIndexParentBucketKey, cfIndexName, interrupt)
}
<commit_msg>blockchain/indexers: use latest API for cf indexing<commit_after>// Copyright (c) 2017 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package indexers

import (
	"errors"

	"github.com/btcsuite/btcd/blockchain"
	"github.com/btcsuite/btcd/chaincfg"
	"github.com/btcsuite/btcd/chaincfg/chainhash"
	"github.com/btcsuite/btcd/database"
	"github.com/btcsuite/btcd/wire"
	"github.com/btcsuite/btcutil"
	"github.com/btcsuite/btcutil/gcs"
	"github.com/btcsuite/btcutil/gcs/builder"
)

const (
	// cfIndexName is the human-readable name for the index.
	cfIndexName = "committed filter index"
)

// Committed filters come in two flavours: basic and extended. They are
// generated and dropped in pairs, and both are indexed by a block's hash.
// Besides holding different content, they also live in different buckets.
var (
	// cfIndexParentBucketKey is the name of the parent bucket used to house
	// the index. The rest of the buckets live below this bucket.
	cfIndexParentBucketKey = []byte("cfindexparentbucket")

	// cfIndexKeys is an array of db bucket names used to house indexes of
	// block hashes to cfilters.
	cfIndexKeys = [][]byte{
		[]byte("cf0byhashidx"),
		[]byte("cf1byhashidx"),
	}

	// cfHeaderKeys is an array of db bucket names used to house indexes of
	// block hashes to cf headers.
	cfHeaderKeys = [][]byte{
		[]byte("cf0headerbyhashidx"),
		[]byte("cf1headerbyhashidx"),
	}

	// cfHashKeys is an array of db bucket names used to house indexes of
	// block hashes to cf hashes.
	cfHashKeys = [][]byte{
		[]byte("cf0hashbyhashidx"),
		[]byte("cf1hashbyhashidx"),
	}

	maxFilterType = uint8(len(cfHeaderKeys) - 1)

	// zeroHash is the chainhash.Hash value of all zero bytes, defined here for
	// convenience.
	zeroHash chainhash.Hash
)

// dbFetchFilterIdxEntry retrieves a data blob from the filter index database.
// An entry's absence is not considered an error.
func dbFetchFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) ([]byte, error) {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Get(h[:]), nil
}

// dbStoreFilterIdxEntry stores a data blob in the filter index database.
func dbStoreFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash, f []byte) error {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Put(h[:], f)
}

// dbDeleteFilterIdxEntry deletes a data blob from the filter index database.
func dbDeleteFilterIdxEntry(dbTx database.Tx, key []byte, h *chainhash.Hash) error {
	idx := dbTx.Metadata().Bucket(cfIndexParentBucketKey).Bucket(key)
	return idx.Delete(h[:])
}

// CfIndex implements a committed filter (cf) by hash index.
type CfIndex struct {
	db          database.DB
	chainParams *chaincfg.Params
}

// Ensure the CfIndex type implements the Indexer interface.
var _ Indexer = (*CfIndex)(nil)

// Init initializes the hash-based cf index. This is part of the Indexer
// interface.
func (idx *CfIndex) Init() error {
	return nil // Nothing to do.
}

// Key returns the database key to use for the index as a byte slice. This is
// part of the Indexer interface.
func (idx *CfIndex) Key() []byte {
	return cfIndexParentBucketKey
}

// Name returns the human-readable name of the index. This is part of the
// Indexer interface.
func (idx *CfIndex) Name() string {
	return cfIndexName
}

// Create is invoked when the indexer manager determines the index needs to
// be created for the first time. It creates buckets for the two hash-based cf
// indexes (simple, extended).
func (idx *CfIndex) Create(dbTx database.Tx) error {
	meta := dbTx.Metadata()

	cfIndexParentBucket, err := meta.CreateBucket(cfIndexParentBucketKey)
	if err != nil {
		return err
	}

	for _, bucketName := range cfIndexKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	for _, bucketName := range cfHeaderKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	for _, bucketName := range cfHashKeys {
		_, err = cfIndexParentBucket.CreateBucket(bucketName)
		if err != nil {
			return err
		}
	}

	return nil
}

// storeFilter stores a given filter, and performs the steps needed to
// generate the filter's header.
func storeFilter(dbTx database.Tx, block *btcutil.Block, f *gcs.Filter,
	filterType wire.FilterType) error {
	if uint8(filterType) > maxFilterType {
		return errors.New("unsupported filter type")
	}

	// Figure out which buckets to use.
	fkey := cfIndexKeys[filterType]
	hkey := cfHeaderKeys[filterType]
	hashkey := cfHashKeys[filterType]

	// Start by storing the filter.
	h := block.Hash()
	filterBytes, err := f.NBytes()
	if err != nil {
		return err
	}
	err = dbStoreFilterIdxEntry(dbTx, fkey, h, filterBytes)
	if err != nil {
		return err
	}

	// Next store the filter hash.
	filterHash, err := builder.GetFilterHash(f)
	if err != nil {
		return err
	}
	err = dbStoreFilterIdxEntry(dbTx, hashkey, h, filterHash[:])
	if err != nil {
		return err
	}

	// Then fetch the previous block's filter header.
	var prevHeader *chainhash.Hash
	ph := &block.MsgBlock().Header.PrevBlock
	if ph.IsEqual(&zeroHash) {
		prevHeader = &zeroHash
	} else {
		pfh, err := dbFetchFilterIdxEntry(dbTx, hkey, ph)
		if err != nil {
			return err
		}

		// Construct the new block's filter header, and store it.
		prevHeader, err = chainhash.NewHash(pfh)
		if err != nil {
			return err
		}
	}

	fh, err := builder.MakeHeaderForFilter(f, *prevHeader)
	if err != nil {
		return err
	}
	return dbStoreFilterIdxEntry(dbTx, hkey, h, fh[:])
}

// ConnectBlock is invoked by the index manager when a new block has been
// connected to the main chain. This indexer adds a hash-to-cf mapping for
// every passed block. This is part of the Indexer interface.
func (idx *CfIndex) ConnectBlock(dbTx database.Tx, block *btcutil.Block,
	view *blockchain.UtxoViewpoint) error {

	f, err := builder.BuildBasicFilter(block.MsgBlock())
	if err != nil {
		return err
	}

	err = storeFilter(dbTx, block, f, wire.GCSFilterRegular)
	if err != nil {
		return err
	}

	f, err = builder.BuildExtFilter(block.MsgBlock())
	if err != nil {
		return err
	}

	return storeFilter(dbTx, block, f, wire.GCSFilterExtended)
}

// DisconnectBlock is invoked by the index manager when a block has been
// disconnected from the main chain.  This indexer removes the hash-to-cf
// mapping for every passed block. This is part of the Indexer interface.
func (idx *CfIndex) DisconnectBlock(dbTx database.Tx, block *btcutil.Block,
	view *blockchain.UtxoViewpoint) error {

	for _, key := range cfIndexKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	for _, key := range cfHeaderKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	for _, key := range cfHashKeys {
		err := dbDeleteFilterIdxEntry(dbTx, key, block.Hash())
		if err != nil {
			return err
		}
	}

	return nil
}

// entryByBlockHash fetches a filter index entry of a particular type
// (eg. filter, filter header, etc) for a filter type and block hash.
func (idx *CfIndex) entryByBlockHash(filterTypeKeys [][]byte,
	filterType wire.FilterType, h *chainhash.Hash) ([]byte, error) {

	if uint8(filterType) > maxFilterType {
		return nil, errors.New("unsupported filter type")
	}
	key := filterTypeKeys[filterType]

	var entry []byte
	err := idx.db.View(func(dbTx database.Tx) error {
		var err error
		entry, err = dbFetchFilterIdxEntry(dbTx, key, h)
		return err
	})
	return entry, err
}

// entriesByBlockHashes batch fetches a filter index entry of a particular type
// (eg. filter, filter header, etc) for a filter type and slice of block hashes.
func (idx *CfIndex) entriesByBlockHashes(filterTypeKeys [][]byte,
	filterType wire.FilterType, blockHashes []*chainhash.Hash) ([][]byte, error) {

	if uint8(filterType) > maxFilterType {
		return nil, errors.New("unsupported filter type")
	}
	key := filterTypeKeys[filterType]

	entries := make([][]byte, 0, len(blockHashes))
	err := idx.db.View(func(dbTx database.Tx) error {
		for _, blockHash := range blockHashes {
			entry, err := dbFetchFilterIdxEntry(dbTx, key, blockHash)
			if err != nil {
				return err
			}
			entries = append(entries, entry)
		}
		return nil
	})
	return entries, err
}

// FilterByBlockHash returns the serialized contents of a block's basic or
// extended committed filter.
func (idx *CfIndex) FilterByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfIndexKeys, filterType, h)
}

// FiltersByBlockHashes returns the serialized contents of a block's basic or
// extended committed filter for a set of blocks by hash.
func (idx *CfIndex) FiltersByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfIndexKeys, filterType, blockHashes)
}

// FilterHeaderByBlockHash returns the serialized contents of a block's basic
// or extended committed filter header.
func (idx *CfIndex) FilterHeaderByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfHeaderKeys, filterType, h)
}

// FilterHeadersByBlockHashes returns the serialized contents of a block's basic
// or extended committed filter header for a set of blocks by hash.
func (idx *CfIndex) FilterHeadersByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfHeaderKeys, filterType, blockHashes)
}

// FilterHashByBlockHash returns the serialized contents of a block's basic
// or extended committed filter hash.
func (idx *CfIndex) FilterHashByBlockHash(h *chainhash.Hash,
	filterType wire.FilterType) ([]byte, error) {
	return idx.entryByBlockHash(cfHashKeys, filterType, h)
}

// FilterHashesByBlockHashes returns the serialized contents of a block's basic
// or extended committed filter hash for a set of blocks by hash.
func (idx *CfIndex) FilterHashesByBlockHashes(blockHashes []*chainhash.Hash,
	filterType wire.FilterType) ([][]byte, error) {
	return idx.entriesByBlockHashes(cfHashKeys, filterType, blockHashes)
}

// NewCfIndex returns a new instance of an indexer that is used to create a
// mapping of the hashes of all blocks in the blockchain to their respective
// committed filters.
//
// It implements the Indexer interface which plugs into the IndexManager that
// in turn is used by the blockchain package. This allows the index to be
// seamlessly maintained along with the chain.
func NewCfIndex(db database.DB, chainParams *chaincfg.Params) *CfIndex {
	return &CfIndex{db: db, chainParams: chainParams}
}

// DropCfIndex drops the CF index from the provided database if exists.
func DropCfIndex(db database.DB, interrupt <-chan struct{}) error {
	return dropIndex(db, cfIndexParentBucketKey, cfIndexName, interrupt)
}
<|endoftext|>


<commit_before>package websocketproxy

import (
	"log"
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/gorilla/websocket"
)

var (
	serverURL  = "ws://127.0.0.1:7777"
	backendURL = "ws://127.0.0.1:8888"
)

func ProxyFunc(w http.ResponseWriter, r *http.Request) {
	u, _ := url.Parse("ws://127.0.0.1:8888")
	ProxyHandler(u).ServeHTTP(w, r)
}

func TestProxy(t *testing.T) {
	// websocket proxy
	mux := http.NewServeMux()
	mux.HandleFunc("/proxy", ProxyFunc)
	go func() {
		if err := http.ListenAndServe(":7777", mux); err != nil {
			t.Fatal("ListenAndServe: ", err)
		}
	}()

	time.Sleep(time.Millisecond * 100)

	// backend echo server
	go func() {
		mux2 := http.NewServeMux()
		mux2.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			conn, err := DefaultUpgrader.Upgrade(w, r, nil)
			if err != nil {
				log.Println(err)
				return
			}

			messageType, p, err := conn.ReadMessage()
			if err != nil {
				return
			}

			if err = conn.WriteMessage(messageType, p); err != nil {
				return
			}
		})

		err := http.ListenAndServe(":8888", mux2)
		if err != nil {
			t.Fatal("ListenAndServe: ", err)
		}
	}()

	time.Sleep(time.Millisecond * 100)

	// frontend server, dial now our proxy, which will reverse proxy our
	// message to the backend websocket server.
	conn, _, err := websocket.DefaultDialer.Dial(serverURL+"/proxy", nil)
	if err != nil {
		t.Fatal(err)
	}

	msg := "hello kite"
	err = conn.WriteMessage(websocket.TextMessage, []byte(msg))
	if err != nil {
		t.Error(err)
	}

	messageType, p, err := conn.ReadMessage()
	if err != nil {
		t.Error(err)
	}

	if messageType != websocket.TextMessage {
		t.Error("incoming message type is not Text")
	}

	if msg != string(p) {
		t.Error("expecting: %s, got: %s", msg, string(p))
	}
}
<commit_msg>Fix errorf formatting<commit_after>package websocketproxy

import (
	"log"
	"net/http"
	"net/url"
	"testing"
	"time"

	"github.com/gorilla/websocket"
)

var (
	serverURL  = "ws://127.0.0.1:7777"
	backendURL = "ws://127.0.0.1:8888"
)

func ProxyFunc(w http.ResponseWriter, r *http.Request) {
	u, _ := url.Parse("ws://127.0.0.1:8888")
	ProxyHandler(u).ServeHTTP(w, r)
}

func TestProxy(t *testing.T) {
	// websocket proxy
	mux := http.NewServeMux()
	mux.HandleFunc("/proxy", ProxyFunc)
	go func() {
		if err := http.ListenAndServe(":7777", mux); err != nil {
			t.Fatal("ListenAndServe: ", err)
		}
	}()

	time.Sleep(time.Millisecond * 100)

	// backend echo server
	go func() {
		mux2 := http.NewServeMux()
		mux2.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
			conn, err := DefaultUpgrader.Upgrade(w, r, nil)
			if err != nil {
				log.Println(err)
				return
			}

			messageType, p, err := conn.ReadMessage()
			if err != nil {
				return
			}

			if err = conn.WriteMessage(messageType, p); err != nil {
				return
			}
		})

		err := http.ListenAndServe(":8888", mux2)
		if err != nil {
			t.Fatal("ListenAndServe: ", err)
		}
	}()

	time.Sleep(time.Millisecond * 100)

	// frontend server, dial now our proxy, which will reverse proxy our
	// message to the backend websocket server.
	conn, _, err := websocket.DefaultDialer.Dial(serverURL+"/proxy", nil)
	if err != nil {
		t.Fatal(err)
	}

	msg := "hello kite"
	err = conn.WriteMessage(websocket.TextMessage, []byte(msg))
	if err != nil {
		t.Error(err)
	}

	messageType, p, err := conn.ReadMessage()
	if err != nil {
		t.Error(err)
	}

	if messageType != websocket.TextMessage {
		t.Error("incoming message type is not Text")
	}

	if msg != string(p) {
		t.Errorf("expecting: %s, got: %s", msg, string(p))
	}
}
<|endoftext|>


<commit_before>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// The gen_fake_config command converts a hardcoded fake.proto message into a
// textual protobuf. The source code is intended to be modified manually to
// generate a valid text proto, instead of writing it by hand.
package main

import (
	"io/ioutil"
	"os"

	log "github.com/golang/glog"
	"github.com/golang/protobuf/proto"

	fpb "github.com/openconfig/gnmi/testing/fake/proto"
)

// Modify the config below to change generated output.
var (
	outputPath = "config.pb.txt"

	config = &fpb.Config{
		Target: "fake target name",
		Seed:   12345,
		Values: []*fpb.Value{
			{
				Path:   []string{"a", "b"},
				Repeat: 3,
				Value:  &fpb.Value_IntValue{&fpb.IntValue{Value: 4}},
			},
			{
				Path:   []string{"b", "c"},
				Repeat: 5,
				Value:  &fpb.Value_StringValue{&fpb.StringValue{Value: "foo"}},
			},
		},
		DisableSync: false,
		DisableEof:  false,
		EnableDelay: false,
		ClientType:  fpb.Config_GRPC_GNMI,
	}
)

func main() {
	flag.Parse()
	out := proto.MarshalTextString(config)
	if err := ioutil.WriteFile(outputPath, []byte(out), os.ModePerm); err != nil {
		log.Exit(err)
	}
}
<commit_msg>Remove flag.Parse from gen_config.go since it doesn't have any flags<commit_after>/*
Copyright 2017 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// The gen_fake_config command converts a hardcoded fake.proto message into a
// textual protobuf. The source code is intended to be modified manually to
// generate a valid text proto, instead of writing it by hand.
package main

import (
	"io/ioutil"
	"os"

	log "github.com/golang/glog"
	"github.com/golang/protobuf/proto"

	fpb "github.com/openconfig/gnmi/testing/fake/proto"
)

// Modify the config below to change generated output.
var (
	outputPath = "config.pb.txt"

	config = &fpb.Config{
		Target: "fake target name",
		Seed:   12345,
		Values: []*fpb.Value{
			{
				Path:   []string{"a", "b"},
				Repeat: 3,
				Value:  &fpb.Value_IntValue{&fpb.IntValue{Value: 4}},
			},
			{
				Path:   []string{"b", "c"},
				Repeat: 5,
				Value:  &fpb.Value_StringValue{&fpb.StringValue{Value: "foo"}},
			},
		},
		DisableSync: false,
		DisableEof:  false,
		EnableDelay: false,
		ClientType:  fpb.Config_GRPC_GNMI,
	}
)

func main() {
	out := proto.MarshalTextString(config)
	if err := ioutil.WriteFile(outputPath, []byte(out), os.ModePerm); err != nil {
		log.Exit(err)
	}
}
<|endoftext|>


<commit_before>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package testing

import (
	"sort"
	"sync"
	"time"

	"github.com/juju/utils/clock"
)

// Clock implements a mock clock.Clock for testing purposes.
type Clock struct {
	mu             sync.Mutex
	now            time.Time
	alarms         []alarm
	currentAlarmID int
}

// Timer implements a mock clock.Timer for testing purposes.
// It's Reset and Stop functions might alter the contents
// of clock by changing the alarm with id ID.
type Timer struct {
	clock *Clock
	ID    int
}

// Reset is part of the clock.Timer interface
func (t *Timer) Reset(d time.Duration) bool {
	t.clock.mu.Lock()
	defer t.clock.mu.Unlock()

	for i, alarm := range t.clock.alarms {
		if t.ID == alarm.ID {
			t.clock.alarms[i].time = t.clock.now.Add(d)
			sort.Sort(byTime(t.clock.alarms))
			return true
		}
	}
	return false
}

// Stop is part of the clock.Timer interface
func (t *Timer) Stop() bool {
	t.clock.mu.Lock()
	defer t.clock.mu.Unlock()

	for i, alarm := range t.clock.alarms {
		if t.ID == alarm.ID {
			t.clock.alarms = removeFromSlice(t.clock.alarms, i)
			return true
		}
	}
	return false
}

// NewClock returns a new clock set to the supplied time.
func NewClock(now time.Time) *Clock {
	return &Clock{now: now}
}

// Now is part of the clock.Clock interface.
func (clock *Clock) Now() time.Time {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	return clock.now
}

// After is part of the clock.Clock interface.
func (clock *Clock) After(d time.Duration) <-chan time.Time {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	notify := make(chan time.Time, 1)
	if d <= 0 {
		notify <- clock.now
	} else {
		clock.setAlarm(clock.now.Add(d), func() { notify <- clock.now })
		clock.currentAlarmID = clock.currentAlarmID + 1
	}
	return notify
}

// AfterFunc is part of the clock.Clock interface.
func (clock *Clock) AfterFunc(d time.Duration, f func()) clock.Timer {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	if d <= 0 {
		f()
	} else {
		clock.setAlarm(clock.now.Add(d), f)
	}

	// If d <= we're sending an id that's not attached to any alarm
	// which is what's intended
	clock.currentAlarmID = clock.currentAlarmID + 1
	t := &Timer{clock, clock.currentAlarmID}
	return t
}

func (clock *Clock) setAlarm(t time.Time, trigger func()) {
	alarm := alarm{
		time:    t,
		trigger: trigger,
		ID:      clock.currentAlarmID,
	}
	clock.alarms = append(clock.alarms, alarm)
	sort.Sort(byTime(clock.alarms))
}

// Advance advances the result of Now by the supplied duration, and sends
// the "current" time on all alarms which are no longer "in the future".
func (clock *Clock) Advance(d time.Duration) {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	clock.now = clock.now.Add(d)
	rung := 0
	for _, alarm := range clock.alarms {
		if clock.now.Before(alarm.time) {
			break
		}
		alarm.trigger()
		rung++
	}
	clock.alarms = clock.alarms[rung:]
}

// alarm records the time at which we're expected to execute trigger.
type alarm struct {
	time    time.Time
	trigger func()
	ID      int
}

// removeFromSlice removes item at the specified index from the slice
// It exists to make the append train clearer
// This doesn't check that index is valid, so the caller needs to check that.
func removeFromSlice(sl []alarm, index int) []alarm {
	return append(sl[:index], sl[index+1:]...)
}

// byTime is used to sort alarms by time.
type byTime []alarm

func (a byTime) Len() int           { return len(a) }
func (a byTime) Less(i, j int) bool { return a[i].time.Before(a[j].time) }
func (a byTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
<commit_msg>testing/clock: refactored code a bit: added a timerClock interface and created a noop stoppedTimer struct to simplify logic.<commit_after>// Copyright 2015 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.

package testing

import (
	"sort"
	"sync"
	"time"

	"github.com/juju/utils/clock"
)

// Clock implements a mock clock.Clock for testing purposes.
type Clock struct {
	mu             sync.Mutex
	now            time.Time
	alarms         []alarm
	currentAlarmID int
}

// timerClock gives timer access to some of clock's internals.
type timerClock interface {
	reset(id int, d time.Duration) bool
	stop(id int) bool
}

// Timer implements a mock clock.Timer for testing purposes.
type Timer struct {
	ID    int
	clock timerClock
}

// reset is a bridge method for timer. It basically
// implements clock.Timer, but it needs access to clock's internals
// so the access is somewhat restricted
func (clock *Clock) reset(id int, d time.Duration) bool {
	clock.mu.Lock()
	defer clock.mu.Unlock()

	for i, alarm := range clock.alarms {
		if id == alarm.ID {
			clock.alarms[i].time = clock.now.Add(d)
			sort.Sort(byTime(clock.alarms))
			return true
		}
	}
	return false
}

// Reset is part of the clock.Timer interface
func (t *Timer) Reset(d time.Duration) bool {
	return t.clock.reset(t.ID, d)
}

// stop is a bridge method for timer. It basically
// implements clock.Timer, but it needs access to clock's internals
// so the access is somewhat restricted
func (clock *Clock) stop(id int) bool {
	clock.mu.Lock()
	defer clock.mu.Unlock()

	for i, alarm := range clock.alarms {
		if id == alarm.ID {
			clock.alarms = removeFromSlice(clock.alarms, i)
			return true
		}
	}
	return false
}

// Stop is part of the clock.Timer interface
func (t *Timer) Stop() bool {
	return t.clock.stop(t.ID)
}

// stoppedTimer is a noop implementation for timer
type stoppedTimer struct{}

func (stoppedTimer) Reset(time.Duration) bool { return false }
func (stoppedTimer) Stop() bool               { return false }

// NewClock returns a new clock set to the supplied time.
func NewClock(now time.Time) *Clock {
	return &Clock{now: now}
}

// Now is part of the clock.Clock interface.
func (clock *Clock) Now() time.Time {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	return clock.now
}

// After is part of the clock.Clock interface.
func (clock *Clock) After(d time.Duration) <-chan time.Time {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	notify := make(chan time.Time, 1)
	if d <= 0 {
		notify <- clock.now
	} else {
		clock.setAlarm(clock.now.Add(d), func() { notify <- clock.now })
	}
	return notify
}

// AfterFunc is part of the clock.Clock interface.
func (clock *Clock) AfterFunc(d time.Duration, f func()) clock.Timer {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	if d <= 0 {
		f()
		return &stoppedTimer{}
	}
	id := clock.setAlarm(clock.now.Add(d), f)
	return &Timer{id, clock}
}

// setAlarm adds an alarm at time t.
// It also sorts the alarms and increments the current ID by 1.
func (clock *Clock) setAlarm(t time.Time, trigger func()) int {
	alarm := alarm{
		time:    t,
		trigger: trigger,
		ID:      clock.currentAlarmID,
	}
	clock.alarms = append(clock.alarms, alarm)
	sort.Sort(byTime(clock.alarms))
	clock.currentAlarmID = clock.currentAlarmID + 1
	return alarm.ID
}

// Advance advances the result of Now by the supplied duration, and sends
// the "current" time on all alarms which are no longer "in the future".
func (clock *Clock) Advance(d time.Duration) {
	clock.mu.Lock()
	defer clock.mu.Unlock()
	clock.now = clock.now.Add(d)
	rung := 0
	for _, alarm := range clock.alarms {
		if clock.now.Before(alarm.time) {
			break
		}
		alarm.trigger()
		rung++
	}
	clock.alarms = clock.alarms[rung:]
}

// alarm records the time at which we're expected to execute trigger.
type alarm struct {
	ID      int
	time    time.Time
	trigger func()
}

// removeFromSlice removes item at the specified index from the slice
// It exists to make the append train clearer
// This doesn't check that index is valid, so the caller needs to check that.
func removeFromSlice(sl []alarm, index int) []alarm {
	return append(sl[:index], sl[index+1:]...)
}

// byTime is used to sort alarms by time.
type byTime []alarm

func (a byTime) Len() int           { return len(a) }
func (a byTime) Less(i, j int) bool { return a[i].time.Before(a[j].time) }
func (a byTime) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
<|endoftext|>