<commit_before>// Package dht implements a distributed hash table that satisfies the ipfs routing
// interface. This DHT is modeled after kademlia with Coral and S/Kademlia modifications.
package dht

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	pb "github.com/libp2p/go-libp2p-kad-dht/pb"
	providers "github.com/libp2p/go-libp2p-kad-dht/providers"
	routing "github.com/libp2p/go-libp2p-routing"

	proto "github.com/gogo/protobuf/proto"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	ci "github.com/libp2p/go-libp2p-crypto"
	host "github.com/libp2p/go-libp2p-host"
	kb "github.com/libp2p/go-libp2p-kbucket"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	protocol "github.com/libp2p/go-libp2p-protocol"
	record "github.com/libp2p/go-libp2p-record"
	recpb "github.com/libp2p/go-libp2p-record/pb"
	base32 "github.com/whyrusleeping/base32"
)

var log = logging.Logger("dht")

var ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0"
var ProtocolDHTOld protocol.ID = "/ipfs/dht"

// NumBootstrapQueries defines the number of random dht queries to do to
// collect members of the routing table.
const NumBootstrapQueries = 5

// TODO. SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-dht/index.js

// IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
// It is used to implement the base IpfsRouting module.
type IpfsDHT struct {
	host      host.Host        // the network services we need
	self      peer.ID          // Local peer (yourself)
	peerstore pstore.Peerstore // Peer Registry

	datastore ds.Datastore // Local data

	routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
	providers    *providers.ProviderManager

	birth    time.Time  // When this peer started up
	diaglock sync.Mutex // lock to make diagnostics work better

	Validator record.Validator // record validator funcs
	Selector  record.Selector  // record selection funcs

	ctx  context.Context
	proc goprocess.Process

	clientOnly bool

	strmap map[peer.ID]*messageSender
	smlk   sync.Mutex
}

// NewDHT creates a new DHT object with the given peer as the 'local' host
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
	h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	return &IpfsDHT{
		datastore:    dstore,
		self:         h.ID(),
		peerstore:    h.Peerstore(),
		host:         h,
		strmap:       make(map[peer.ID]*messageSender),
		ctx:          ctx,
		providers:    providers.NewProviderManager(ctx, h.ID(), dstore),
		birth:        time.Now(),
		routingTable: kb.NewRoutingTable(KValue, kb.ConvertPeerID(h.ID()), time.Minute, h.Peerstore()),

		Validator: make(record.Validator),
		Selector:  make(record.Selector),
	}
}

// putValueToPeer stores the given key/value pair at the peer 'p'
func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
	key string, rec *recpb.Record) error {

	pmes := pb.NewMessage(pb.Message_PUT_VALUE, key, 0)
	pmes.Record = rec
	rpmes, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return err
	case nil:
		break
	}

	if err != nil {
		return err
	}

	if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
		return errors.New("value not put correctly")
	}
	return nil
}

var errInvalidRecord = errors.New("received invalid record")

// getValueOrPeers queries a particular peer p for the value for
// key. It returns either the value or a list of closer peers.
// NOTE: It will update the dht's peerstore with any new addresses
// it finds for the given peer.
func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []pstore.PeerInfo, error) {

	pmes, err := dht.getValueSingle(ctx, p, key)
	if err != nil {
		return nil, nil, err
	}

	// Perhaps we were given closer peers
	peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())

	if record := pmes.GetRecord(); record != nil {
		// Success! We were given the value
		log.Debug("getValueOrPeers: got value")

		// make sure record is valid.
		err = dht.verifyRecordOnline(ctx, record)
		if err != nil {
			log.Info("Received invalid record! (discarded)")
			// return a sentinal to signify an invalid record was received
			err = errInvalidRecord
			record = new(recpb.Record)
		}
		return record, peers, err
	}

	if len(peers) > 0 {
		log.Debug("getValueOrPeers: peers")
		return nil, peers, nil
	}

	log.Warning("getValueOrPeers: routing.ErrNotFound")
	return nil, nil, routing.ErrNotFound
}

// getValueSingle simply performs the get value RPC with the given parameters
func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID, key string) (*pb.Message, error) {
	meta := logging.LoggableMap{
		"key":  key,
		"peer": p,
	}

	defer log.EventBegin(ctx, "getValueSingle", meta).Done()

	pmes := pb.NewMessage(pb.Message_GET_VALUE, key, 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// getLocal attempts to retrieve the value from the datastore
func (dht *IpfsDHT) getLocal(key string) (*recpb.Record, error) {
	log.Debugf("getLocal %s", key)

	v, err := dht.datastore.Get(mkDsKey(key))
	if err != nil {
		return nil, err
	}
	log.Debugf("found %s in local datastore")

	byt, ok := v.([]byte)
	if !ok {
		return nil, errors.New("value stored in datastore not []byte")
	}
	rec := new(recpb.Record)
	err = proto.Unmarshal(byt, rec)
	if err != nil {
		return nil, err
	}

	err = dht.verifyRecordLocally(rec)
	if err != nil {
		log.Debugf("local record verify failed: %s (discarded)", err)
		return nil, err
	}

	return rec, nil
}

// getOwnPrivateKey attempts to load the local peers private
// key from the peerstore.
func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
	sk := dht.peerstore.PrivKey(dht.self)
	if sk == nil {
		log.Warningf("%s dht cannot get own private key!", dht.self)
		return nil, fmt.Errorf("cannot get private key to sign record!")
	}
	return sk, nil
}

// putLocal stores the key value pair in the datastore
func (dht *IpfsDHT) putLocal(key string, rec *recpb.Record) error {
	data, err := proto.Marshal(rec)
	if err != nil {
		return err
	}

	return dht.datastore.Put(mkDsKey(key), data)
}

// Update signals the routingTable to Update its last-seen status
// on the given peer.
func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
	log.Event(ctx, "updatePeer", p)
	dht.routingTable.Update(p)
}

// FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
func (dht *IpfsDHT) FindLocal(id peer.ID) pstore.PeerInfo {
	p := dht.routingTable.Find(id)
	if p != "" {
		return dht.peerstore.PeerInfo(p)
	}
	return pstore.PeerInfo{}
}

// findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findPeerSingle", p, id).Done()

	pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), id)
		fallthrough
	default:
		return nil, err
	}
}

func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key *cid.Cid) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findProvidersSingle", p, key).Done()

	pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, key.KeyString(), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// nearestPeersToQuery returns the routing tables closest peers.
func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
	closer := dht.routingTable.NearestPeers(kb.ConvertKey(pmes.GetKey()), count)
	return closer
}

// betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID {
	closer := dht.nearestPeersToQuery(pmes, count)

	// no node? nil
	if closer == nil {
		return nil
	}

	// == to self? thats bad
	for _, p := range closer {
		if p == dht.self {
			log.Debug("attempted to return self! this shouldn't happen...")
			return nil
		}
	}

	var filtered []peer.ID
	for _, clp := range closer {
		// Dont send a peer back themselves
		if p == clp {
			continue
		}

		filtered = append(filtered, clp)
	}

	// ok seems like closer nodes
	return filtered
}

// Context return dht's context
func (dht *IpfsDHT) Context() context.Context {
	return dht.ctx
}

// Process return dht's process
func (dht *IpfsDHT) Process() goprocess.Process {
	return dht.proc
}

// Close calls Process Close
func (dht *IpfsDHT) Close() error {
	return dht.proc.Close()
}

func mkDsKey(s string) ds.Key {
	return ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte(s)))
}
<commit_msg>DRY up NewDHT<commit_after>// Package dht implements a distributed hash table that satisfies the ipfs routing
// interface. This DHT is modeled after kademlia with Coral and S/Kademlia modifications.
package dht

import (
	"bytes"
	"context"
	"errors"
	"fmt"
	"sync"
	"time"

	pb "github.com/libp2p/go-libp2p-kad-dht/pb"
	providers "github.com/libp2p/go-libp2p-kad-dht/providers"
	routing "github.com/libp2p/go-libp2p-routing"

	proto "github.com/gogo/protobuf/proto"
	cid "github.com/ipfs/go-cid"
	ds "github.com/ipfs/go-datastore"
	logging "github.com/ipfs/go-log"
	goprocess "github.com/jbenet/goprocess"
	goprocessctx "github.com/jbenet/goprocess/context"
	ci "github.com/libp2p/go-libp2p-crypto"
	host "github.com/libp2p/go-libp2p-host"
	kb "github.com/libp2p/go-libp2p-kbucket"
	peer "github.com/libp2p/go-libp2p-peer"
	pstore "github.com/libp2p/go-libp2p-peerstore"
	protocol "github.com/libp2p/go-libp2p-protocol"
	record "github.com/libp2p/go-libp2p-record"
	recpb "github.com/libp2p/go-libp2p-record/pb"
	base32 "github.com/whyrusleeping/base32"
)

var log = logging.Logger("dht")

var ProtocolDHT protocol.ID = "/ipfs/kad/1.0.0"
var ProtocolDHTOld protocol.ID = "/ipfs/dht"

// NumBootstrapQueries defines the number of random dht queries to do to
// collect members of the routing table.
const NumBootstrapQueries = 5

// TODO. SEE https://github.com/jbenet/node-ipfs/blob/master/submodules/ipfs-dht/index.js

// IpfsDHT is an implementation of Kademlia with Coral and S/Kademlia modifications.
// It is used to implement the base IpfsRouting module.
type IpfsDHT struct {
	host      host.Host        // the network services we need
	self      peer.ID          // Local peer (yourself)
	peerstore pstore.Peerstore // Peer Registry

	datastore ds.Datastore // Local data

	routingTable *kb.RoutingTable // Array of routing tables for differently distanced nodes
	providers    *providers.ProviderManager

	birth    time.Time  // When this peer started up
	diaglock sync.Mutex // lock to make diagnostics work better

	Validator record.Validator // record validator funcs
	Selector  record.Selector  // record selection funcs

	ctx  context.Context
	proc goprocess.Process

	clientOnly bool

	strmap map[peer.ID]*messageSender
	smlk   sync.Mutex
}

// NewDHT creates a new DHT object with the given peer as the 'local' host
func NewDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := NewDHTClient(ctx, h, dstore)

	h.SetStreamHandler(ProtocolDHT, dht.handleNewStream)
	h.SetStreamHandler(ProtocolDHTOld, dht.handleNewStream)

	return dht
}

// NewDHTClient creates a new DHT object with the given peer as the 'local' host
func NewDHTClient(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	dht := makeDHT(ctx, h, dstore)

	// register for network notifs.
	dht.host.Network().Notify((*netNotifiee)(dht))

	dht.proc = goprocessctx.WithContextAndTeardown(ctx, func() error {
		// remove ourselves from network notifs.
		dht.host.Network().StopNotify((*netNotifiee)(dht))
		return nil
	})

	dht.proc.AddChild(dht.providers.Process())

	dht.Validator["pk"] = record.PublicKeyValidator
	dht.Selector["pk"] = record.PublicKeySelector

	return dht
}

func makeDHT(ctx context.Context, h host.Host, dstore ds.Batching) *IpfsDHT {
	return &IpfsDHT{
		datastore:    dstore,
		self:         h.ID(),
		peerstore:    h.Peerstore(),
		host:         h,
		strmap:       make(map[peer.ID]*messageSender),
		ctx:          ctx,
		providers:    providers.NewProviderManager(ctx, h.ID(), dstore),
		birth:        time.Now(),
		routingTable: kb.NewRoutingTable(KValue, kb.ConvertPeerID(h.ID()), time.Minute, h.Peerstore()),

		Validator: make(record.Validator),
		Selector:  make(record.Selector),
	}
}

// putValueToPeer stores the given key/value pair at the peer 'p'
func (dht *IpfsDHT) putValueToPeer(ctx context.Context, p peer.ID,
	key string, rec *recpb.Record) error {

	pmes := pb.NewMessage(pb.Message_PUT_VALUE, key, 0)
	pmes.Record = rec
	rpmes, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return err
	case nil:
		break
	}

	if err != nil {
		return err
	}

	if !bytes.Equal(rpmes.GetRecord().Value, pmes.GetRecord().Value) {
		return errors.New("value not put correctly")
	}
	return nil
}

var errInvalidRecord = errors.New("received invalid record")

// getValueOrPeers queries a particular peer p for the value for
// key. It returns either the value or a list of closer peers.
// NOTE: It will update the dht's peerstore with any new addresses
// it finds for the given peer.
func (dht *IpfsDHT) getValueOrPeers(ctx context.Context, p peer.ID, key string) (*recpb.Record, []pstore.PeerInfo, error) {

	pmes, err := dht.getValueSingle(ctx, p, key)
	if err != nil {
		return nil, nil, err
	}

	// Perhaps we were given closer peers
	peers := pb.PBPeersToPeerInfos(pmes.GetCloserPeers())

	if record := pmes.GetRecord(); record != nil {
		// Success! We were given the value
		log.Debug("getValueOrPeers: got value")

		// make sure record is valid.
		err = dht.verifyRecordOnline(ctx, record)
		if err != nil {
			log.Info("Received invalid record! (discarded)")
			// return a sentinal to signify an invalid record was received
			err = errInvalidRecord
			record = new(recpb.Record)
		}
		return record, peers, err
	}

	if len(peers) > 0 {
		log.Debug("getValueOrPeers: peers")
		return nil, peers, nil
	}

	log.Warning("getValueOrPeers: routing.ErrNotFound")
	return nil, nil, routing.ErrNotFound
}

// getValueSingle simply performs the get value RPC with the given parameters
func (dht *IpfsDHT) getValueSingle(ctx context.Context, p peer.ID, key string) (*pb.Message, error) {
	meta := logging.LoggableMap{
		"key":  key,
		"peer": p,
	}

	defer log.EventBegin(ctx, "getValueSingle", meta).Done()

	pmes := pb.NewMessage(pb.Message_GET_VALUE, key, 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// getLocal attempts to retrieve the value from the datastore
func (dht *IpfsDHT) getLocal(key string) (*recpb.Record, error) {
	log.Debugf("getLocal %s", key)

	v, err := dht.datastore.Get(mkDsKey(key))
	if err != nil {
		return nil, err
	}
	log.Debugf("found %s in local datastore")

	byt, ok := v.([]byte)
	if !ok {
		return nil, errors.New("value stored in datastore not []byte")
	}
	rec := new(recpb.Record)
	err = proto.Unmarshal(byt, rec)
	if err != nil {
		return nil, err
	}

	err = dht.verifyRecordLocally(rec)
	if err != nil {
		log.Debugf("local record verify failed: %s (discarded)", err)
		return nil, err
	}

	return rec, nil
}

// getOwnPrivateKey attempts to load the local peers private
// key from the peerstore.
func (dht *IpfsDHT) getOwnPrivateKey() (ci.PrivKey, error) {
	sk := dht.peerstore.PrivKey(dht.self)
	if sk == nil {
		log.Warningf("%s dht cannot get own private key!", dht.self)
		return nil, fmt.Errorf("cannot get private key to sign record!")
	}
	return sk, nil
}

// putLocal stores the key value pair in the datastore
func (dht *IpfsDHT) putLocal(key string, rec *recpb.Record) error {
	data, err := proto.Marshal(rec)
	if err != nil {
		return err
	}

	return dht.datastore.Put(mkDsKey(key), data)
}

// Update signals the routingTable to Update its last-seen status
// on the given peer.
func (dht *IpfsDHT) Update(ctx context.Context, p peer.ID) {
	log.Event(ctx, "updatePeer", p)
	dht.routingTable.Update(p)
}

// FindLocal looks for a peer with a given ID connected to this dht and returns the peer and the table it was found in.
func (dht *IpfsDHT) FindLocal(id peer.ID) pstore.PeerInfo {
	p := dht.routingTable.Find(id)
	if p != "" {
		return dht.peerstore.PeerInfo(p)
	}
	return pstore.PeerInfo{}
}

// findPeerSingle asks peer 'p' if they know where the peer with id 'id' is
func (dht *IpfsDHT) findPeerSingle(ctx context.Context, p peer.ID, id peer.ID) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findPeerSingle", p, id).Done()

	pmes := pb.NewMessage(pb.Message_FIND_NODE, string(id), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), id)
		fallthrough
	default:
		return nil, err
	}
}

func (dht *IpfsDHT) findProvidersSingle(ctx context.Context, p peer.ID, key *cid.Cid) (*pb.Message, error) {
	defer log.EventBegin(ctx, "findProvidersSingle", p, key).Done()

	pmes := pb.NewMessage(pb.Message_GET_PROVIDERS, key.KeyString(), 0)
	resp, err := dht.sendRequest(ctx, p, pmes)
	switch err {
	case nil:
		return resp, nil
	case ErrReadTimeout:
		log.Warningf("read timeout: %s %s", p.Pretty(), key)
		fallthrough
	default:
		return nil, err
	}
}

// nearestPeersToQuery returns the routing tables closest peers.
func (dht *IpfsDHT) nearestPeersToQuery(pmes *pb.Message, count int) []peer.ID {
	closer := dht.routingTable.NearestPeers(kb.ConvertKey(pmes.GetKey()), count)
	return closer
}

// betterPeerToQuery returns nearestPeersToQuery, but iff closer than self.
func (dht *IpfsDHT) betterPeersToQuery(pmes *pb.Message, p peer.ID, count int) []peer.ID {
	closer := dht.nearestPeersToQuery(pmes, count)

	// no node? nil
	if closer == nil {
		return nil
	}

	// == to self? thats bad
	for _, p := range closer {
		if p == dht.self {
			log.Debug("attempted to return self! this shouldn't happen...")
			return nil
		}
	}

	var filtered []peer.ID
	for _, clp := range closer {
		// Dont send a peer back themselves
		if p == clp {
			continue
		}

		filtered = append(filtered, clp)
	}

	// ok seems like closer nodes
	return filtered
}

// Context return dht's context
func (dht *IpfsDHT) Context() context.Context {
	return dht.ctx
}

// Process return dht's process
func (dht *IpfsDHT) Process() goprocess.Process {
	return dht.proc
}

// Close calls Process Close
func (dht *IpfsDHT) Close() error {
	return dht.proc.Close()
}

func mkDsKey(s string) ds.Key {
	return ds.NewKey(base32.RawStdEncoding.EncodeToString([]byte(s)))
}
<|endoftext|>


<commit_before>// Copyright 2014 JustAdam (adambell7@gmail.com).  All rights reserved.
// License: MIT

// Docker log file client for logentries.
// All containers need to log to stdout/stderr.  Don't forget logrotation.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/BurntSushi/toml"
	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
)

const (
	// Only SSL connections are supported
	defaultLogEntriesHost string = "data.logentries.com:20000"
)

var (
	logEntriesHost string
	// Log to this token for all unknown containers
	defaultLogKey      string
	configFileLocation string
	// Location to Docker's container logs
	logDirectory string
	// Parse the JSON stored in Docker's log files
	parseDockerLogFormat bool
	// Location to Docker containers directory
	watchLogDirectory bool
	// Our own log level
	outputLogLevel string
	// Pattern to find Docker container log files
	LogFilePattern string = "*/*.log"

	tailConfig = tail.Config{
		Follow: true,
		ReOpen: true,
		Location: &tail.SeekInfo{
			Offset: 0,
			Whence: 2,
		},
		Logger: tail.DiscardingLogger,
	}

	watchLogs *WatchLogs
	logLines  chan *LogLine
)

type WatchLogs struct {
	sync.Mutex
	Containers map[string]*LogWatch `toml:"container"`
	Ignore     []string
}

type LogWatch struct {
	Key  string
	File string
	Name string
	Quit chan bool `toml:"-"`
}

type LogLine struct {
	Line *tail.Line
	Key  string
	Name string
}

type DockerLogEntry struct {
	Log    string
	Stream string
	// ignoring time for now
}

func (dl *DockerLogEntry) String() string {
	return fmt.Sprintf("(%s) %s", dl.Stream, dl.Log)
}

func init() {
	var tmp string

	tmp = os.Getenv("DLE_CONFIG_FILE")
	if tmp == "" {
		tmp = "config.toml"
	}
	flag.StringVar(&configFileLocation, "config", tmp, "Location of configuration file")

	flag.StringVar(&defaultLogKey, "default-log-key", os.Getenv("DLE_DEFAULT_LOG_KEY"), "Default log entries key to use for undefined containers")

	flag.StringVar(&logDirectory, "log-directory", os.Getenv("DLE_LOG_DIRECTORY"), "Path to Docker containers directory")

	tmpb, err := strconv.ParseBool(os.Getenv("DLE_WATCH_LOG_DIRECTORY"))
	if err != nil {
		tmpb = false
	}
	flag.BoolVar(&watchLogDirectory, "watch-ld", tmpb, "Watch the Docker containers directory for new/removed containers")

	tmpb, err = strconv.ParseBool(os.Getenv("DLE_PARSE_DOCKER_LOGS"))
	if err != nil {
		tmpb = true
	}
	flag.BoolVar(&parseDockerLogFormat, "parse-docker-logs", tmpb, "Parse the Docker log format (false will send the raw log entry)")

	tmp = os.Getenv("DLE_CONFIG_FILE")
	if tmp == "" {
		tmp = defaultLogEntriesHost
	}
	flag.StringVar(&logEntriesHost, "le-host", tmp, "host:port address to logentries")

	tmp = os.Getenv("DLE_LOG_LEVEL")
	if tmp == "" {
		tmp = "fatal"
	}
	flag.StringVar(&outputLogLevel, "log-level", tmp, "Log level verbosity (debug, info, warn, fatal, panic)")

	level, err := log.ParseLevel(outputLogLevel)
	if err != nil {
		level = log.FatalLevel
	}
	log.SetLevel(level)
}

func main() {
	flag.Parse()

	if flag.Arg(0) == "help" {
		flag.Usage()
		os.Exit(0)
	}

	if defaultLogKey == "" {
		fmt.Println("Required --default-log-key missing.")
		flag.Usage()
		os.Exit(1)
	}

	if logDirectory == "" {
		fmt.Println("Required --log-directory missing.")
		flag.Usage()
		os.Exit(1)
	}

	if logEntriesHost == "" {
		fmt.Println("Required --le-host missing.")
		flag.Usage()
		os.Exit(1)
	}

	// check logDirectory exists - hopefully it is the Docker log directory :)
	if ok, err := isDir(logDirectory); ok == false {
		if err != nil {
			log.Fatal(err)
		}
		log.Fatal(logDirectory, "is not a directory")
	}

	go signalHandler()

	watchLogs = NewWatchLogs(configFileLocation)

	lec := &LogEntriesConnection{}
	if err := lec.Connect(logEntriesHost); err != nil {
		log.Fatal("Unable to connect to logentries:", err)
	}
	defer lec.Close()

	logLines = make(chan *LogLine)

	if watchLogDirectory {
		go WatchDockerLogDirectory()
	}

	startWatchLogs()

	for {
		select {
		case line := <-logLines:
			fmt.Fprintln(lec.conn, line)
		}
	}
}

func NewWatchLogs(file string) (watchLog *WatchLogs) {
	watchLog = new(WatchLogs)
	watchLog.Lock()
	if _, err := toml.DecodeFile(file, watchLog); err != nil {
		log.Fatal("Unable to open config file:", err)
	}

	// Find all Docker log files
	files, err := filepath.Glob(filepath.Join(logDirectory, LogFilePattern))
	if err != nil {
		log.Fatal("Unable to open log directory:", err)
	}

	// Match up files against config settings
	for _, file := range files {
		watchLog.AddLog(file)
	}

	// Remove ignored containers
	for _, cid := range watchLog.Ignore {
		if _, ok := watchLog.Containers[cid]; ok {
			delete(watchLog.Containers, cid)
			log.WithFields(log.Fields{
				"container": cid,
			}).Info("Ignoring container")
		}
	}

	// Remove container logs which don't exist.
	// These IDs were specified in the config file, but no container was found
	for k, cl := range watchLog.Containers {
		if cl.File == "" {
			delete(watchLog.Containers, k)
			log.WithFields(log.Fields{
				"container": k,
			}).Warn("Container doesn't exist")
		}
	}

	watchLog.Unlock()
	return
}

func (wl *WatchLogs) AddLog(file string) {

	var logKey string
	var logName string
	var containerID string

	filename := filepath.Base(file)

	for start, c := range wl.Containers {
		if match, _ := filepath.Match(start+"*", filename); match {
			containerID = start
			logKey = c.Key
			logName = c.Name
			break
		}
	}

	// Use full container ID if no match found
	if containerID == "" {
		containerID = filepath.Base(filepath.Dir(file))
	}

	// Log against default key if none found
	if logKey == "" {
		logKey = defaultLogKey
	}

	wl.Containers[containerID] = &LogWatch{
		Key:  logKey,
		Name: logName,
		File: file,
		Quit: make(chan bool),
	}
}

func startWatchLogs() {
	for _, container := range watchLogs.Containers {
		go Watch(logLines, container)
	}
}

func Watch(logline chan<- *LogLine, logfile *LogWatch) {
	if logfile.File == "" {
		log.WithFields(log.Fields{
			"key": logfile.Key,
		}).Warn("Can't watch empty logfile")
		return
	}

	t, err := tail.TailFile(logfile.File, tailConfig)
	if err != nil {
		log.WithFields(log.Fields{
			"file": logfile.File,
		}).Warn("Unable to tail file:", err)
	}

	log.WithFields(log.Fields{
		"name": logfile.Name,
		"file": logfile.File,
	}).Info("Watching file")

	for {
		select {
		case line := <-t.Lines:
			ll := &LogLine{
				Key:  logfile.Key,
				Name: logfile.Name,
				Line: line,
			}
			logline <- ll
		case <-logfile.Quit:
			log.WithFields(log.Fields{
				"name": logfile.Name,
				"file": logfile.File,
			}).Info("Stopping tail")
			t.Stop()
			logfile.Quit <- true
			return
		}
	}
}

func signalHandler() {
	sigDie := make(chan os.Signal, 1)
	signal.Notify(sigDie, syscall.SIGINT, syscall.SIGTERM)
	sigReload := make(chan os.Signal, 1)
	signal.Notify(sigReload, syscall.SIGHUP)

	for {
		select {
		case <-sigDie:
			tailCleanup()
			os.Exit(0)
		case <-sigReload:
			tailCleanup()
			watchLogs = nil
			watchLogs = NewWatchLogs(configFileLocation)
			startWatchLogs()
		}
	}
}

func tailCleanup() {
	for _, container := range watchLogs.Containers {
		container.Quit <- true
		<-container.Quit
	}
	tail.Cleanup()
}

func (ll *LogLine) String() string {
	var line string
	if parseDockerLogFormat {
		var dlog DockerLogEntry
		if err := json.Unmarshal([]byte(ll.Line.Text), &dlog); err != nil {
			log.Warn("Error decoding log:", err)
			return ""
		}
		line = dlog.String()
	} else {
		line = ll.Line.Text
	}
	return fmt.Sprintf("%s %s %s", ll.Key, ll.Name, line)
}

func isDir(name string) (bool, error) {
	fi, err := os.Stat(name)
	if err != nil {
		return false, err
	}

	if !fi.IsDir() {
		return false, nil
	}

	return true, nil
}

func WatchDockerLogDirectory() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	watcher.Add(logDirectory)

	log.WithFields(log.Fields{
		"dir": logDirectory,
	}).Info("Watching docker logs directory")

	quit := make(chan bool, 1)

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				switch {
				case event.Op&fsnotify.Create == fsnotify.Create:
					// @todo refactor - removal of dupe code
					if ok, _ := isDir(event.Name); ok {

						log.WithFields(log.Fields{
							"watch": logDirectory,
						}).Debug("New directory creation detected")

						cid := filepath.Base(event.Name)
						addFile := true

						// check if container is ignored
						for _, icid := range watchLogs.Ignore {
							if cid == icid {
								log.WithFields(log.Fields{
									"container": cid,
								}).Info("Ignoring container")
								addFile = false
								continue
							}
						}

						if addFile {
							file := filepath.Join(event.Name, cid+"-json.log")
							if err != nil {
								log.WithFields(log.Fields{
									"file": file,
									"cid":  cid,
								}).Warn("Error finding log")
							} else {
								watchLogs.Lock()
								watchLogs.AddLog(file)
								watchLogs.Unlock()
								go Watch(logLines, watchLogs.Containers[cid])
							}
						}
					}
				case event.Op&fsnotify.Remove == fsnotify.Remove:

					log.WithFields(log.Fields{
						"watch": logDirectory,
					}).Debug("Removal detected")

					cid := filepath.Base(event.Name)

					if c, ok := watchLogs.Containers[cid]; ok {
						c.Quit <- true
						<-c.Quit
						watchLogs.Lock()
						delete(watchLogs.Containers, cid)
						watchLogs.Unlock()
						log.WithFields(log.Fields{
							"cid": cid,
						}).Debug("Container log watch removed")
					}
				}
			case err := <-watcher.Errors:
				log.WithFields(log.Fields{
					"func": "DockerLogDirectoryWatch",
				}).Warn(err)
			}
		}
	}()

	<-quit
}
<commit_msg>code cleanup start<commit_after>// Copyright 2014 JustAdam (adambell7@gmail.com).  All rights reserved.
// License: MIT

// Docker log file client for logentries.
// All containers need to log to stdout/stderr.  Don't forget logrotation.
package main

import (
	"encoding/json"
	"flag"
	"fmt"
	"github.com/ActiveState/tail"
	"github.com/BurntSushi/toml"
	log "github.com/Sirupsen/logrus"
	"gopkg.in/fsnotify.v1"
	"os"
	"os/signal"
	"path/filepath"
	"strconv"
	"sync"
	"syscall"
)

const (
	// Only SSL connections are supported
	defaultLogEntriesHost string = "data.logentries.com:20000"
)

var (
	logEntriesHost string
	// Log to this token for all unknown containers
	defaultLogKey      string
	configFileLocation string
	// Location to Docker's container logs
	logDirectory string
	// Parse the JSON stored in Docker's log files
	parseDockerLogFormat bool
	// Location to Docker containers directory
	watchLogDirectory bool
	// Our own log level
	outputLogLevel string
	// Pattern to find Docker container log files
	LogFilePattern string = "*/*.log"

	tailConfig = tail.Config{
		Follow: true,
		ReOpen: true,
		Location: &tail.SeekInfo{
			Offset: 0,
			Whence: 2,
		},
		Logger: tail.DiscardingLogger,
	}

	watchLogs *WatchLogs
	logLines  chan *LogLine
)

type WatchLogs struct {
	sync.Mutex
	Containers map[string]*LogWatch `toml:"container"`
	Ignore     []string
}

type LogWatch struct {
	Key  string
	File string
	Name string
	Quit chan bool `toml:"-"`
}

type LogLine struct {
	Line *tail.Line
	Key  string
	Name string
}

type DockerLogEntry struct {
	Log    string
	Stream string
	// ignoring time for now
}

func (dl *DockerLogEntry) String() string {
	return fmt.Sprintf("(%s) %s", dl.Stream, dl.Log)
}

func init() {
	var tmp string

	tmp = os.Getenv("DLE_CONFIG_FILE")
	if tmp == "" {
		tmp = "config.toml"
	}
	flag.StringVar(&configFileLocation, "config", tmp, "Location of configuration file")

	flag.StringVar(&defaultLogKey, "default-log-key", os.Getenv("DLE_DEFAULT_LOG_KEY"), "Default log entries key to use for undefined containers")

	flag.StringVar(&logDirectory, "log-directory", os.Getenv("DLE_LOG_DIRECTORY"), "Path to Docker containers directory")

	tmpb, err := strconv.ParseBool(os.Getenv("DLE_WATCH_LOG_DIRECTORY"))
	if err != nil {
		tmpb = false
	}
	flag.BoolVar(&watchLogDirectory, "watch-ld", tmpb, "Watch the Docker containers directory for new/removed containers")

	tmpb, err = strconv.ParseBool(os.Getenv("DLE_PARSE_DOCKER_LOGS"))
	if err != nil {
		tmpb = true
	}
	flag.BoolVar(&parseDockerLogFormat, "parse-docker-logs", tmpb, "Parse the Docker log format (false will send the raw log entry)")

	tmp = os.Getenv("DLE_CONFIG_FILE")
	if tmp == "" {
		tmp = defaultLogEntriesHost
	}
	flag.StringVar(&logEntriesHost, "le-host", tmp, "host:port address to logentries")

	tmp = os.Getenv("DLE_LOG_LEVEL")
	if tmp == "" {
		tmp = "fatal"
	}
	flag.StringVar(&outputLogLevel, "log-level", tmp, "Log level verbosity (debug, info, warn, fatal, panic)")

	level, err := log.ParseLevel(outputLogLevel)
	if err != nil {
		level = log.FatalLevel
	}
	log.SetLevel(level)
}

func main() {
	flag.Parse()

	if flag.Arg(0) == "help" {
		flag.Usage()
		os.Exit(0)
	}

	if defaultLogKey == "" {
		fmt.Println("Required --default-log-key missing.")
		flag.Usage()
		os.Exit(1)
	}

	if logDirectory == "" {
		fmt.Println("Required --log-directory missing.")
		flag.Usage()
		os.Exit(1)
	}

	if logEntriesHost == "" {
		fmt.Println("Required --le-host missing.")
		flag.Usage()
		os.Exit(1)
	}

	// check logDirectory exists - hopefully it is the Docker log directory :)
	if ok, err := isDir(logDirectory); ok == false {
		if err != nil {
			log.Fatal(err)
		}
		log.Fatal(logDirectory, "is not a directory")
	}

	go signalHandler()

	watchLogs = New(configFileLocation)

	lec := &LogEntriesConnection{}
	if err := lec.Connect(logEntriesHost); err != nil {
		log.Fatal("Unable to connect to logentries:", err)
	}
	defer lec.Close()

	logLines = make(chan *LogLine)

	if watchLogDirectory {
		go WatchDockerLogDirectory()
	}

	watchLogs.Start()

	for {
		select {
		case line := <-logLines:
			fmt.Fprintln(lec.conn, line)
		}
	}
}

func New(file string) (watchLog *WatchLogs) {
	watchLog = new(WatchLogs)
	watchLog.Lock()
	if _, err := toml.DecodeFile(file, watchLog); err != nil {
		log.Fatal("Unable to open config file:", err)
	}

	// Find all Docker log files
	files, err := filepath.Glob(filepath.Join(logDirectory, LogFilePattern))
	if err != nil {
		log.Fatal("Unable to open log directory:", err)
	}

	// Match up files against config settings
	for _, file := range files {
		watchLog.AddLog(file)
	}

	// Remove ignored containers
	for _, cid := range watchLog.Ignore {
		if _, ok := watchLog.Containers[cid]; ok {
			delete(watchLog.Containers, cid)
			log.WithFields(log.Fields{
				"container": cid,
			}).Info("Ignoring container")
		}
	}

	// Remove container logs which don't exist.
	// These IDs were specified in the config file, but no container was found
	for k, cl := range watchLog.Containers {
		if cl.File == "" {
			delete(watchLog.Containers, k)
			log.WithFields(log.Fields{
				"container": k,
			}).Warn("Container doesn't exist")
		}
	}

	watchLog.Unlock()
	return
}

func (wl *WatchLogs) AddLog(file string) {

	var logKey string
	var logName string
	var containerID string

	filename := filepath.Base(file)

	for start, c := range wl.Containers {
		if match, _ := filepath.Match(start+"*", filename); match {
			containerID = start
			logKey = c.Key
			logName = c.Name
			break
		}
	}

	// Use full container ID if no match found
	if containerID == "" {
		containerID = filepath.Base(filepath.Dir(file))
	}

	// Log against default key if none found
	if logKey == "" {
		logKey = defaultLogKey
	}

	wl.Containers[containerID] = &LogWatch{
		Key:  logKey,
		Name: logName,
		File: file,
		Quit: make(chan bool),
	}
}

func (wl *WatchLogs) Start() {
	for _, container := range wl.Containers {
		go Watch(logLines, container)
	}
}

func Watch(logline chan<- *LogLine, logfile *LogWatch) {
	if logfile.File == "" {
		log.WithFields(log.Fields{
			"key": logfile.Key,
		}).Warn("Can't watch empty logfile")
		return
	}

	t, err := tail.TailFile(logfile.File, tailConfig)
	if err != nil {
		log.WithFields(log.Fields{
			"file": logfile.File,
		}).Warn("Unable to tail file:", err)
	}

	log.WithFields(log.Fields{
		"name": logfile.Name,
		"file": logfile.File,
	}).Info("Watching file")

	for {
		select {
		case line := <-t.Lines:
			ll := &LogLine{
				Key:  logfile.Key,
				Name: logfile.Name,
				Line: line,
			}
			logline <- ll
		case <-logfile.Quit:
			log.WithFields(log.Fields{
				"name": logfile.Name,
				"file": logfile.File,
			}).Info("Stopping tail")
			t.Stop()
			logfile.Quit <- true
			return
		}
	}
}

func signalHandler() {
	sigDie := make(chan os.Signal, 1)
	signal.Notify(sigDie, syscall.SIGINT, syscall.SIGTERM)
	sigReload := make(chan os.Signal, 1)
	signal.Notify(sigReload, syscall.SIGHUP)

	for {
		select {
		case <-sigDie:
			watchLogs.cleanup()
			os.Exit(0)
		case <-sigReload:
			watchLogs.cleanup()
			watchLogs = nil
			watchLogs = New(configFileLocation)
			watchLogs.Start()
		}
	}
}

func (wl *WatchLogs) cleanup() {
	for _, container := range wl.Containers {
		container.Quit <- true
		<-container.Quit
	}
	tail.Cleanup()
}

func (ll *LogLine) String() string {
	var line string
	if parseDockerLogFormat {
		var dlog DockerLogEntry
		if err := json.Unmarshal([]byte(ll.Line.Text), &dlog); err != nil {
			log.Warn("Error decoding log:", err)
			return ""
		}
		line = dlog.String()
	} else {
		line = ll.Line.Text
	}
	return fmt.Sprintf("%s %s %s", ll.Key, ll.Name, line)
}

func isDir(name string) (bool, error) {
	fi, err := os.Stat(name)
	if err != nil {
		return false, err
	}

	if !fi.IsDir() {
		return false, nil
	}

	return true, nil
}

func WatchDockerLogDirectory() {
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		log.Fatal(err)
	}
	defer watcher.Close()

	watcher.Add(logDirectory)

	log.WithFields(log.Fields{
		"dir": logDirectory,
	}).Info("Watching docker logs directory")

	quit := make(chan bool, 1)

	go func() {
		for {
			select {
			case event := <-watcher.Events:
				switch {
				case event.Op&fsnotify.Create == fsnotify.Create:
					// @todo refactor - removal of dupe code
					if ok, _ := isDir(event.Name); ok {

						log.WithFields(log.Fields{
							"watch": logDirectory,
						}).Debug("New directory creation detected")

						cid := filepath.Base(event.Name)
						addFile := true

						// check if container is ignored
						for _, icid := range watchLogs.Ignore {
							if cid == icid {
								log.WithFields(log.Fields{
									"container": cid,
								}).Info("Ignoring container")
								addFile = false
								continue
							}
						}

						if addFile {
							file := filepath.Join(event.Name, cid+"-json.log")
							if err != nil {
								log.WithFields(log.Fields{
									"file": file,
									"cid":  cid,
								}).Warn("Error finding log")
							} else {
								watchLogs.Lock()
								watchLogs.AddLog(file)
								watchLogs.Unlock()
								go Watch(logLines, watchLogs.Containers[cid])
							}
						}
					}
				case event.Op&fsnotify.Remove == fsnotify.Remove:

					log.WithFields(log.Fields{
						"watch": logDirectory,
					}).Debug("Removal detected")

					cid := filepath.Base(event.Name)

					if c, ok := watchLogs.Containers[cid]; ok {
						c.Quit <- true
						<-c.Quit
						watchLogs.Lock()
						delete(watchLogs.Containers, cid)
						watchLogs.Unlock()
						log.WithFields(log.Fields{
							"cid": cid,
						}).Debug("Container log watch removed")
					}
				}
			case err := <-watcher.Errors:
				log.WithFields(log.Fields{
					"func": "DockerLogDirectoryWatch",
				}).Warn(err)
			}
		}
	}()

	<-quit
}
<|endoftext|>


<commit_before>/*
package zkteco parses the output files from zkteco device.
*/
package zkteco
<commit_msg>Fix language problem<commit_after>/*
Package zkteco parses the output files from zkteco device.
*/
package zkteco
<|endoftext|>


<commit_before>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gorilla/sessions provides cookie and filesystem sessions and
infrastructure for custom session backends.

The key features are:

	* Simple API: use it as an easy way to set signed (and optionally
	  encrypted) cookies.
	* Built-in backends to store sessions in cookies or the filesystem.
	* Flash messages: session values that last until read.
	* Convenient way to switch session persistency (aka "remember me") and set
	  other attributes.
	* Mechanism to rotate authentication and encryption keys.
	* Multiple sessions per request, even using different backends.
	* Interfaces and infrastructure for custom session backends: sessions from
	  different stores can be retrieved and batch-saved using a common API.

Let's start with an example that shows the sessions API in a nutshell:

	import (
		"net/http"
		"github.com/gorilla/sessions"
	)

	var store = sessions.NewCookieStore([]byte("something-very-secret"))

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session. We're ignoring the error resulted from decoding an
		// existing session: Get() always returns a session, even if empty.
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		// Set some session values.
		session.Values["foo"] = "bar"
		session.Values[42] = 43
		// Save it before we write to the response/return from the handler.
		session.Save(r, w)
	}

First we initialize a session store calling NewCookieStore() and passing a
secret key used to authenticate the session. Inside the handler, we call
store.Get() to retrieve an existing session or a new one. Then we set some
session values in session.Values, which is a map[interface{}]interface{}.
And finally we call session.Save() to save the session in the response.

Note that in production code, we should check for errors when calling
session.Save(r, w), and either display an error message or otherwise handle it.

Save must be called before writing to the response, otherwise the session
cookie will not be sent to the client.

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
with context.ClearHandler as or else you will leak memory! An easy way to do this
is to wrap the top-level mux when calling http.ListenAndServe:

    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))

The ClearHandler function is provided by the gorilla/context package.

That's all you need to know for the basic usage. Let's take a look at other
options, starting with flash messages.

Flash messages are session values that last until read. The term appeared with
Ruby On Rails a few years back. When we request a flash message, it is removed
from the session. To add a flash, call session.AddFlash(), and to get all
flashes, call session.Flashes(). Here is an example:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session.
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		// Get the previously flashes, if any.
		if flashes := session.Flashes(); len(flashes) > 0 {
			// Use the flash values.
		} else {
			// Set a new flash.
			session.AddFlash("Hello, flash messages world!")
		}
		session.Save(r, w)
	}

Flash messages are useful to set information to be read after a redirection,
like after form submissions.

There may also be cases where you want to store a complex datatype within a
session, such as a struct. Sessions are serialised using the encoding/gob package,
so it is easy to register new datatypes for storage in sessions:

	import(
		"encoding/gob"
		"github.com/gorilla/sessions"
	)

	type Person struct {
		FirstName	string
		LastName 	string
		Email		string
		Age			int
	}

	type M map[string]interface{}

	func init() {

		gob.Register(&Person{})
		gob.Register(&M{})
	}

As it's not possible to pass a raw type as a parameter to a function, gob.Register()
relies on us passing it an empty pointer to the type as a parameter. In the example
above we've passed it a pointer to a struct and a pointer to a custom type
representing a map[string]interface. This will then allow us to serialise/deserialise
values of those types to and from our sessions.

Note that because session values are stored in a map[string]interface{}, there's
a need to type-assert data when retrieving it. We'll use the Person struct we registered above:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), 500)
			return
		}

		// Retrieve our struct and type-assert it
		val := session.Values["person"]
		var person = &Person{}
		if person, ok := val.(*Person); !ok {
			// Handle the case that it's not an expected type
		}

		// Now we can use our person object
	}

By default, session cookies last for a month. This is probably too long for
some cases, but it is easy to change this and other attributes during
runtime. Sessions can be configured individually or the store can be
configured and then all sessions saved using it will use that configuration.
We access session.Options or store.Options to set a new configuration. The
fields are basically a subset of http.Cookie fields. Let's change the
maximum age of a session to one week:

	session.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7,
		HttpOnly: true,
	}

Sometimes we may want to change authentication and/or encryption keys without
breaking existing sessions. The CookieStore supports key rotation, and to use
it you just need to set multiple authentication and encryption keys, in pairs,
to be tested in order:

	var store = sessions.NewCookieStore(
		[]byte("new-authentication-key"),
		[]byte("new-encryption-key"),
		[]byte("old-authentication-key"),
		[]byte("old-encryption-key"),
	)

New sessions will be saved using the first pair. Old sessions can still be
read because the first pair will fail, and the second will be tested. This
makes it easy to "rotate" secret keys and still be able to validate existing
sessions. Note: for all pairs the encryption key is optional; set it to nil
or omit it and and encryption won't be used.

Multiple sessions can be used in the same request, even with different
session backends. When this happens, calling Save() on each session
individually would be cumbersome, so we have a way to save all sessions
at once: it's sessions.Save(). Here's an example:

	var store = sessions.NewCookieStore([]byte("something-very-secret"))

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session and set a value.
		session1, _ := store.Get(r, "session-one")
		session1.Values["foo"] = "bar"
		// Get another session and set another value.
		session2, _ := store.Get(r, "session-two")
		session2.Values[42] = 43
		// Save all sessions.
		sessions.Save(r, w)
	}

This is possible because when we call Get() from a session store, it adds the
session to a common registry. Save() uses it to save all registered sessions.
*/
package sessions
<commit_msg>Use http.StatusInternalServerError instead of 500 (#74)<commit_after>// Copyright 2012 The Gorilla Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
Package gorilla/sessions provides cookie and filesystem sessions and
infrastructure for custom session backends.

The key features are:

	* Simple API: use it as an easy way to set signed (and optionally
	  encrypted) cookies.
	* Built-in backends to store sessions in cookies or the filesystem.
	* Flash messages: session values that last until read.
	* Convenient way to switch session persistency (aka "remember me") and set
	  other attributes.
	* Mechanism to rotate authentication and encryption keys.
	* Multiple sessions per request, even using different backends.
	* Interfaces and infrastructure for custom session backends: sessions from
	  different stores can be retrieved and batch-saved using a common API.

Let's start with an example that shows the sessions API in a nutshell:

	import (
		"net/http"
		"github.com/gorilla/sessions"
	)

	var store = sessions.NewCookieStore([]byte("something-very-secret"))

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session. We're ignoring the error resulted from decoding an
		// existing session: Get() always returns a session, even if empty.
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Set some session values.
		session.Values["foo"] = "bar"
		session.Values[42] = 43
		// Save it before we write to the response/return from the handler.
		session.Save(r, w)
	}

First we initialize a session store calling NewCookieStore() and passing a
secret key used to authenticate the session. Inside the handler, we call
store.Get() to retrieve an existing session or a new one. Then we set some
session values in session.Values, which is a map[interface{}]interface{}.
And finally we call session.Save() to save the session in the response.

Note that in production code, we should check for errors when calling
session.Save(r, w), and either display an error message or otherwise handle it.

Save must be called before writing to the response, otherwise the session
cookie will not be sent to the client.

Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
with context.ClearHandler as or else you will leak memory! An easy way to do this
is to wrap the top-level mux when calling http.ListenAndServe:

    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))

The ClearHandler function is provided by the gorilla/context package.

That's all you need to know for the basic usage. Let's take a look at other
options, starting with flash messages.

Flash messages are session values that last until read. The term appeared with
Ruby On Rails a few years back. When we request a flash message, it is removed
from the session. To add a flash, call session.AddFlash(), and to get all
flashes, call session.Flashes(). Here is an example:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session.
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Get the previously flashes, if any.
		if flashes := session.Flashes(); len(flashes) > 0 {
			// Use the flash values.
		} else {
			// Set a new flash.
			session.AddFlash("Hello, flash messages world!")
		}
		session.Save(r, w)
	}

Flash messages are useful to set information to be read after a redirection,
like after form submissions.

There may also be cases where you want to store a complex datatype within a
session, such as a struct. Sessions are serialised using the encoding/gob package,
so it is easy to register new datatypes for storage in sessions:

	import(
		"encoding/gob"
		"github.com/gorilla/sessions"
	)

	type Person struct {
		FirstName	string
		LastName 	string
		Email		string
		Age			int
	}

	type M map[string]interface{}

	func init() {

		gob.Register(&Person{})
		gob.Register(&M{})
	}

As it's not possible to pass a raw type as a parameter to a function, gob.Register()
relies on us passing it an empty pointer to the type as a parameter. In the example
above we've passed it a pointer to a struct and a pointer to a custom type
representing a map[string]interface. This will then allow us to serialise/deserialise
values of those types to and from our sessions.

Note that because session values are stored in a map[string]interface{}, there's
a need to type-assert data when retrieving it. We'll use the Person struct we registered above:

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		session, err := store.Get(r, "session-name")
		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}

		// Retrieve our struct and type-assert it
		val := session.Values["person"]
		var person = &Person{}
		if person, ok := val.(*Person); !ok {
			// Handle the case that it's not an expected type
		}

		// Now we can use our person object
	}

By default, session cookies last for a month. This is probably too long for
some cases, but it is easy to change this and other attributes during
runtime. Sessions can be configured individually or the store can be
configured and then all sessions saved using it will use that configuration.
We access session.Options or store.Options to set a new configuration. The
fields are basically a subset of http.Cookie fields. Let's change the
maximum age of a session to one week:

	session.Options = &sessions.Options{
		Path:     "/",
		MaxAge:   86400 * 7,
		HttpOnly: true,
	}

Sometimes we may want to change authentication and/or encryption keys without
breaking existing sessions. The CookieStore supports key rotation, and to use
it you just need to set multiple authentication and encryption keys, in pairs,
to be tested in order:

	var store = sessions.NewCookieStore(
		[]byte("new-authentication-key"),
		[]byte("new-encryption-key"),
		[]byte("old-authentication-key"),
		[]byte("old-encryption-key"),
	)

New sessions will be saved using the first pair. Old sessions can still be
read because the first pair will fail, and the second will be tested. This
makes it easy to "rotate" secret keys and still be able to validate existing
sessions. Note: for all pairs the encryption key is optional; set it to nil
or omit it and and encryption won't be used.

Multiple sessions can be used in the same request, even with different
session backends. When this happens, calling Save() on each session
individually would be cumbersome, so we have a way to save all sessions
at once: it's sessions.Save(). Here's an example:

	var store = sessions.NewCookieStore([]byte("something-very-secret"))

	func MyHandler(w http.ResponseWriter, r *http.Request) {
		// Get a session and set a value.
		session1, _ := store.Get(r, "session-one")
		session1.Values["foo"] = "bar"
		// Get another session and set another value.
		session2, _ := store.Get(r, "session-two")
		session2.Values[42] = 43
		// Save all sessions.
		sessions.Save(r, w)
	}

This is possible because when we call Get() from a session store, it adds the
session to a common registry. Save() uses it to save all registered sessions.
*/
package sessions
<|endoftext|>


<commit_before>// Copyright 2014 github.com/Shaked Author. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

/*
Package Shaked/getpocket is an implementation for Getpocket.com's API.
The Package is documented at:

	http://godoc.org/github.com/Shaked/getpocket

Let's start with authenticating to Getpocket using Shaked/getpocket package:

	type Page struct {
        auth *auth.Auth
    }

    var (
        redirectURI     = "https://localhost:10443/authcheck"
        consumerKey     = "yourconsumerkeyhere"
        ssl_certificate = "ssl/server.crt"
        ssl_key         = "ssl/server.key"
    )

    func main() {
        var e *utils.RequestError
        a, e := auth.Factory(consumerKey, redirectURI)
        if nil != e {
            log.Fatal(e)
        }
        log.Printf("Listen on 10443")
        p := &Page{auth: a}
        http.HandleFunc("/auth", p.Auth)
        http.HandleFunc("/authcheck", p.AuthCheck)

        err := http.ListenAndServeTLS(":10443", ssl_certificate, ssl_key, nil)
        if err != nil {
            log.Fatal(err)
        }
    }

    func (p *Page) Auth(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Referer(), "Example Handler, Should connect and request app permissions")
        requestToken, err := p.auth.Connect()
        if nil != err {
            fmt.Fprintf(w, "Token error %s (%d)", err.Error(), err.ErrorCode())
        }

        p.auth.RequestPermissions(requestToken, w, r)
    }

    func (p *Page) AuthCheck(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Referer(), "GetPocket connection check, should get the username and access token")
        requestToken := r.URL.Query().Get("requestToken")
        if "" == requestToken {
            fmt.Fprintf(w, "Request token is invalid")
            return
        }
        user, err := p.auth.User(requestToken)
        if nil != err {
            fmt.Fprintf(w, "%s (%d)", err.Error(), err.ErrorCode())
            return
        }
        fmt.Fprintf(w, "%#v", user)
    }

Later on we can apply Getpocket's commands.

Add:

	c := commands.New(user, consumerKey)
	u := "http://confreaks.com/videos/3432-gophercon2014-go-from-c-to-go"
	add := commands.NewAdd(u)
	add.SetTitle("Some cool title").SetTags("Shaked,Blog")
	resp1, e := c.Exec(add)
	if nil != e {
	    fmt.Fprintf(w, "ERROR%s\n", e)
	    return
	}

Retrieve:

	retrieve := commands.NewRetrieve()
    resp2, e := c.Exec(retrieve)
    if nil != e {
        fmt.Fprintf(w, "ERROR%s\n", e)
        return
    }

Modify:

	id := 12345678
	favorite := modify.FactoryFavorite(id)
	unfavorite := modify.FactoryUnfavorite(id)
	add := modify.FactoryAdd(id)
	add.SetTags([]string{"go", "programming", "blog"})
	actions := []modify.Action{
		add,
		favorite,
		unfavorite,
	}
	modify := commands.NewModify(actions)
	c := commands.New(user, consumerKey)
	resp1, e := c.Exec(modify)
	if nil != e {
		fmt.Fprintf(w, "ERROR%s\n", e)
	}

The modify command contains the following actions:

	add
	archive
	delete
	favorite
	unfavorite
	readd
	tag_add
	tag_clear
	tag_remove
	tag_rename
	tag_replace

Check the repository for more details and examples:

	https://www.github.com/Shaked/getpocket

*/
package getpocket
<commit_msg>text alignment<commit_after>// Copyright 2014 github.com/Shaked Author. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

/*
Package Shaked/getpocket is an implementation for Getpocket.com's API.
The Package is documented at:

	http://godoc.org/github.com/Shaked/getpocket

Let's start with authenticating to Getpocket using Shaked/getpocket package:

	type Page struct {
        auth *auth.Auth
    }

    var (
        redirectURI     = "https://localhost:10443/authcheck"
        consumerKey     = "yourconsumerkeyhere"
        ssl_certificate = "ssl/server.crt"
        ssl_key         = "ssl/server.key"
    )

    func main() {
        var e *utils.RequestError
        a, e := auth.Factory(consumerKey, redirectURI)
        if nil != e {
            log.Fatal(e)
        }
        log.Printf("Listen on 10443")
        p := &Page{auth: a}
        http.HandleFunc("/auth", p.Auth)
        http.HandleFunc("/authcheck", p.AuthCheck)

        err := http.ListenAndServeTLS(":10443", ssl_certificate, ssl_key, nil)
        if err != nil {
            log.Fatal(err)
        }
    }

    func (p *Page) Auth(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Referer(), "Example Handler, Should connect and request app permissions")
        requestToken, err := p.auth.Connect()
        if nil != err {
            fmt.Fprintf(w, "Token error %s (%d)", err.Error(), err.ErrorCode())
        }

        p.auth.RequestPermissions(requestToken, w, r)
    }

    func (p *Page) AuthCheck(w http.ResponseWriter, r *http.Request) {
        log.Println(r.Referer(), "GetPocket connection check, should get the username and access token")
        requestToken := r.URL.Query().Get("requestToken")
        if "" == requestToken {
            fmt.Fprintf(w, "Request token is invalid")
            return
        }
        user, err := p.auth.User(requestToken)
        if nil != err {
            fmt.Fprintf(w, "%s (%d)", err.Error(), err.ErrorCode())
            return
        }
        fmt.Fprintf(w, "%#v", user)
    }

Later on we can apply Getpocket's commands.

Add:

	c := commands.New(user, consumerKey)
	u := "http://confreaks.com/videos/3432-gophercon2014-go-from-c-to-go"
	add := commands.NewAdd(u)
	add.SetTitle("Some cool title").SetTags("Shaked,Blog")
	resp, e := c.Exec(add)
	if nil != e {
	    fmt.Fprintf(w, "ERROR%s\n", e)
	    return
	}

Retrieve:

	retrieve := commands.NewRetrieve()
	resp, e := c.Exec(retrieve)
	if nil != e {
	    fmt.Fprintf(w, "ERROR%s\n", e)
	    return
	}

Modify:

	id := 12345678
	favorite := modify.FactoryFavorite(id)
	unfavorite := modify.FactoryUnfavorite(id)
	add := modify.FactoryAdd(id)
	add.SetTags([]string{"go", "programming", "blog"})
	actions := []modify.Action{
		add,
		favorite,
		unfavorite,
	}
	modify := commands.NewModify(actions)
	c := commands.New(user, consumerKey)
	resp, e := c.Exec(modify)
	if nil != e {
		fmt.Fprintf(w, "ERROR%s\n", e)
	}

The modify command contains the following actions:

	add
	archive
	delete
	favorite
	unfavorite
	readd
	tag_add
	tag_clear
	tag_remove
	tag_rename
	tag_replace

Check the repository for more details and examples:

	https://www.github.com/Shaked/getpocket

*/
package getpocket
<|endoftext|>


<commit_before>// Copyright 2017 Roberto Virga. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	A package to solve Cryptica puzzle games.

	Context

	Cryptica is a mobile game developed by Pixibots. I have no affiliation
	with the company other than being a satisfied customer. Solving a
	puzzle in Cryptica involves moving tiles on a 7x5 board to match a
	desired configuration. All tiles move symultaneously; their movements
	are, however, constrained by the board edges, and possibly also by
	some additional (unmovable) barriers.

	Description

	This Go package can search efficiently for solutions of Cryptica and
	Cryptica-like puzzles, in either depth-first or breadth-first fashion.
	Moreover, it can work on boards of arbitrary size (with some caveats).

	History

	I wrote this software in early 2017 as part of a hands-on effort to
	learn Go and its development tools. I would like to thank Wojciech
	Smalinski at Google for introducing me to this weird but powerful
	programming language.
*/
package cryptica
<commit_msg>formatting<commit_after>// Copyright 2017 Roberto Virga. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/*
	A package to solve Cryptica puzzle games.

	Context

	Cryptica is a mobile game developed by Pixibots. I have no affiliation
	with the company other than being a satisfied customer. Solving a
	puzzle in Cryptica involves moving tiles on a 7x5 board to match a
	desired configuration. All tiles move symultaneously; their movements
	are, however, constrained by the board edges, and possibly also by
	some additional (unmovable) barriers.

	Description

	This Go package can search efficiently for solutions of Cryptica and
	Cryptica-like puzzles, in either depth-first or breadth-first fashion.
	Moreover, it can work on boards of arbitrary size (with some caveats).

	History

	I wrote this software in early 2017 as part of a hands-on effort to
	learn Go and its development tools. I would like to thank Wojciech
	Smalinski at Google for introducing me to this weird but powerful
	programming language.
*/
package cryptica
<|endoftext|>


<commit_before>// Copyright 2018, OpenCensus 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 aws provides Exporter support for AWS XRay for traces.
package aws // import "go.opencensus.io/exporter/aws"
<commit_msg>Remove vanity URL enforcement for now (#4)<commit_after>// Copyright 2018, OpenCensus 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 aws provides Exporter support for AWS XRay for traces.
package aws
<|endoftext|>


<commit_before>/*

Package cdp provides type-safe bindings for the Chrome Debugging
Protocol (CDP) and can be used with any debug target that implements it.

The cdp Client requires an rpcc connection (*rpcc.Conn):

	conn, err := rpcc.Dial("ws://127.0.0.1:9222/f39a3624-e972-4a77-8a5f-6f8c42ef5129")
	if err != nil {
		// Handle error.
	}
	defer conn.Close()
	c := cdp.NewClient(conn)
	// ...

The devtool package can be used for finding the websocket URL:

	devt := devtool.New("http://127.0.0.1:9222")
	pageTarget, err := devtool.Get(context.Background(), devtool.Page)
	if err != nil {
		// Handle error.
	}
	conn, err := rpcc.Dial(pageTarget.WebSocketDebuggerURL)
	// ...

Domain methods

Methods can be invoked from the Client:

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()

	c := cdp.NewClient(conn)
	nav, err := c.Page.Navigate(ctx, page.NewNavigateArgs("https://www.google.com"))
	if err != nil {
		// Handle error.
	}
	// ...

Domain events

Events are received with an event client:

	// DOMContentEventFired = DOMContentLoaded.
	domContentEventFired, err := c.Page.DOMContentEventFired(ctx)
	if err != nil {
		// Handle error.
	}
	ev, err := domContentEventFired.Recv()
	if err != nil {
		// Handle error.
	}
	// ...

Enable must be called before events are triggered for the domain:

	err := c.Page.Enable(ctx)
	if err != nil {
		// Handle error.
	}
	// ...

Some events are sent immediately after the call to Enable, it is a good
idea to create event clients beforehand. The rpcc.Stream will buffer the
events until they are ready to be received via Recv.

*/
package cdp

// Generate protcol definition using cdpgen.
//go:generate go install github.com/mafredri/cdp/cmd/cdpgen
//go:generate cdpgen -dest-pkg github.com/mafredri/cdp -browser-proto ./cmd/cdpgen/protodef/browser_protocol.json -js-proto ./cmd/cdpgen/protodef/js_protocol.json
<commit_msg>Update documentation, mention Ready() for events<commit_after>/*

Package cdp provides type-safe bindings for the Chrome Debugging
Protocol (CDP) and can be used with any debug target that implements it.

The cdp Client requires an rpcc connection (*rpcc.Conn):

	ctx, cancel := context.WithCancel(context.TODO())
	defer cancel()

	conn, err := rpcc.DialContext(ctx, "ws://127.0.0.1:9222/f39a3624-e972-4a77-8a5f-6f8c42ef5129")
	if err != nil {
		// Handle error.
	}
	defer conn.Close()

	c := cdp.NewClient(conn)
	// ...

The devtool package can be used for finding the websocket URL (see
devtool documentation for more):

	devt := devtool.New("http://127.0.0.1:9222")
	pg, err := devtool.Get(ctx, devtool.Page)
	if err != nil {
		// Handle error.
	}
	conn, err := rpcc.Dial(pg.WebSocketDebuggerURL)
	// ...

Domain methods

Domain methods are used to perform actions or request data over the
Chrome Debugging Protocol.

Methods can be invoked from the Client:

	c := cdp.NewClient(conn)
	nav, err := c.Page.Navigate(ctx, page.NewNavigateArgs("https://www.google.com"))
	if err != nil {
		// Handle error.
	}
	// ...

Domain events

Event clients are used to handle events sent over the protocol. A client
will buffer all events, preserving order, after creation until it is
closed, context done or connection closed. Under the hood, an event
client is a rpcc.Stream.

Create an event client for the DOMContentEventFired event. Call Close
when the client is no longer used to avoid leaking memory. The client
will remain active for the duration of the context or until it is
closed:

	// DOMContentEventFired = DOMContentLoaded.
	domContentEventFired, err := c.Page.DOMContentEventFired(ctx)
	if err != nil {
		// Handle error.
	}
	defer domContentEventFired.Close()
	// ...

Enable (if available) must be called before events are transmitted over
the Chrome Debugging Protocol:

	err := c.Page.Enable(ctx)
	if err != nil {
		// Handle error.
	}
	// ...

Calling Enable can result in immediate event transmissions. If these
events are important, an event client should be created before calling
Enable.

Wait for an event by calling Recv:

	ev, err := domContentEventFired.Recv()
	if err != nil {
		// Handle error.
	}
	// ...

The Ready channel can be used to check for pending events or managing
multiple event handlers:

	go func() {
		select {
		case <-domContentEventFired.Ready():
			_, err := domContentEventFired.Recv() // Does not block here.
			if err != nil {
				// Handle error.
			}
		case <-loadEventFired.Ready():
			// Handle loadEventFired.
		}
	}()
	// ...

Calling Close on the event client will also close the Ready channel.

*/
package cdp

// Generate protcol definition using cdpgen.
//go:generate go install github.com/mafredri/cdp/cmd/cdpgen
//go:generate cdpgen -dest-pkg github.com/mafredri/cdp -browser-proto ./cmd/cdpgen/protodef/browser_protocol.json -js-proto ./cmd/cdpgen/protodef/js_protocol.json
<|endoftext|>


<commit_before>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package dig provides an opinionated way of resolving object dependencies.
//
// Status
//
// STABLE. No breaking changes will be made in this major version.
//
// Container
//
// Dig exposes type Container as an object capable of resolving a directed
// acyclic dependency graph. Use the New function to create one.
//
//   c := dig.New()
//
// Provide
//
// Constructors for different types are added to the container by using the
// Provide method. A constructor can declare a dependency on another type by
// simply adding it as a function parameter. Dependencies for a type can be
// added to the graph both, before and after the type was added.
//
//   err := c.Provide(func(conn *sql.DB) (*UserGateway, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   if err := c.Provide(newDBConnection); err != nil {
//     // ...
//   }
//
// Multiple constructors can rely on the same type. The container creates a
// singleton for each retained type, instantiating it at most once when
// requested directly or as a dependency of another type.
//
//   err := c.Provide(func(conn *sql.DB) *CommentGateway {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Constructors can declare any number of dependencies as parameters and
// optionally, return errors.
//
//   err := c.Provide(func(u *UserGateway, c *CommentGateway) (*RequestHandler, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   if err := c.Provide(newHTTPServer); err != nil {
//     // ...
//   }
//
// Constructors can also return multiple results to add multiple types to the
// container.
//
//   err := c.Provide(func(conn *sql.DB) (*UserGateway, *CommentGateway, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Constructors that accept a variadic number of arguments are treated as if
// they don't have those arguments. That is,
//
//   func NewVoteGateway(db *sql.DB, options ...Option) *VoteGateway
//
// Is treated the same as,
//
//   func NewVoteGateway(db *sql.DB) *VoteGateway
//
// The constructor will be called with all other dependencies and no variadic
// arguments.
//
// Invoke
//
// Types added to to the container may be consumed by using the Invoke method.
// Invoke accepts any function that accepts one or more parameters and
// optionally, returns an error. Dig calls the function with the requested
// type, instantiating only those types that were requested by the function.
// The call fails if any type or its dependencies (both direct and transitive)
// were not available in the container.
//
//   err := c.Invoke(func(l *log.Logger) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   err := c.Invoke(func(server *http.Server) error {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Any error returned by the invoked function is propagated back to the
// caller.
//
// Parameter Objects
//
// Constructors declare their dependencies as function parameters. This can
// very quickly become unreadable if the constructor has a lot of
// dependencies.
//
//   func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
//     // ...
//   }
//
// A pattern employed to improve readability in a situation like this is to
// create a struct that lists all the parameters of the function as fields and
// changing the function to accept that struct instead. This is referred to as
// a parameter object.
//
// Dig has first class support for parameter objects: any struct embedding
// dig.In gets treated as a parameter object. The following is equivalent to
// the constructor above.
//
//   type HandlerParams struct {
//     dig.In
//
//     Users    *UserGateway
//     Comments *CommentGateway
//     Posts    *PostGateway
//     Votes    *VoteGateway
//     AuthZ    *AuthZGateway
//   }
//
//   func NewHandler(p HandlerParams) *Handler {
//     // ...
//   }
//
// Handlers can receive any combination of parameter objects and parameters.
//
//   func NewHandler(p HandlerParams, l *log.Logger) *Handler {
//     // ...
//   }
//
// Result Objects
//
// Result objects are the flip side of parameter objects. These are structs
// that represent multiple outputs from a single function as fields in the
// struct. Structs embedding dig.Out get treated as result objects.
//
//   func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
//     // ...
//   }
//
// The above is equivalent to,
//
//  type Gateways struct {
//    dig.Out
//
//    Users    *UserGateway
//    Comments *CommentGateway
//    Posts    *PostGateway
//  }
//
//  func SetupGateways(conn *sql.DB) (Gateways, error) {
//    // ...
//  }
//
// Optional Dependencies
//
// Constructors often don't have a hard dependency on some types and
// are able to operate in a degraded state when that dependency is missing.
// Dig supports declaring dependencies as optional by adding an
// `optional:"true"` tag to fields of a dig.In struct.
//
// Fields in a dig.In structs that have the `optional:"true"` tag are treated
// as optional by Dig.
//
//   type UserGatewayParams struct {
//     dig.In
//
//     Conn  *sql.DB
//     Cache *redis.Client `optional:"true"`
//   }
//
// If an optional field is not available in the container, the constructor
// will receive a zero value for the field.
//
//   func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
//     if p.Cache != nil {
//       log.Print("Logging disabled")
//     }
//     // ...
//   }
//
// Constructors that declare dependencies as optional MUST handle the case of
// those dependencies being absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// Named Values
//
// Some use cases call for multiple values of the same type. Dig allows adding
// multiple values of the same type to the container with the use of
// `name:".."` tags on fields of dig.In and dig.Out structs.
//
// A constructor that produces a dig.Out struct can tag any field with
// `name:".."` to have the corresponding value added to the graph under the
// specified name.
//
//   type ConnectionResult struct {
//     dig.Out
//
//     ReadWrite *sql.DB `name:"rw"`
//     ReadOnly  *sql.DB `name:"ro"`
//   }
//
//   func ConnectToDatabase(...) (ConnectionResult, error) {
//     // ...
//     return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil
//   }
//
// Another constructor can consume these values by adding fields to a dig.In
// struct with the same name AND type.
//
//   type GatewayParams struct {
//     dig.In
//
//     WriteToConn  *sql.DB `name:"rw"`
//     ReadFromConn *sql.DB `name:"ro"`
//   }
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
//   type GatewayParams struct {
//     dig.In
//
//     WriteToConn  *sql.DB `name:"rw"`
//     ReadFromConn *sql.DB `name:"ro" optional:"true"`
//   }
//
//   func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
//     if p.ReadFromConn == nil {
//       log.Print("Warning: Using RW connection for reads")
//       p.ReadFromConn = p.WriteToConn
//     }
//     // ...
//   }
//
// Value Groups
//
// Dig provides value groups to allow producing and consuming many values of
// the same type. Value groups allow constructors to send values to a named,
// unordered collection in the container. Other constructors can request all
// values in this collection as a slice.
//
// Constructors can send values into value groups by returning a dig.Out
// struct tagged with `group:".."`.
//
//   type HandlerResult struct {
//     dig.Out
//
//     Handler Handler `group:"server"`
//   }
//
//   func NewHelloHandler() HandlerResult {
//     ..
//   }
//
//   func NewEchoHandler() HandlerResult {
//     ..
//   }
//
// Any number of constructors may provide values to this named collection.
// Other constructors can request all values for this collection by requesting
// a slice tagged with `group:".."`. This will execute all constructors that
// provide a value to that group in an unspecified order.
//
//   type ServerParams struct {
//     dig.In
//
//     Handlers []Handler `group:"server"`
//   }
//
//   func NewServer(p ServerParams) *Server {
//     server := newServer()
//     for _, h := range p.Handlers {
//       server.Register(h)
//     }
//     return server
//   }
//
// Note that values in a value group are unordered. Dig makes no guarantees
// about the order in which these values will be produced.
package dig
<commit_msg>doc: Value groups: Mention version (#169)<commit_after>// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

// Package dig provides an opinionated way of resolving object dependencies.
//
// Status
//
// STABLE. No breaking changes will be made in this major version.
//
// Container
//
// Dig exposes type Container as an object capable of resolving a directed
// acyclic dependency graph. Use the New function to create one.
//
//   c := dig.New()
//
// Provide
//
// Constructors for different types are added to the container by using the
// Provide method. A constructor can declare a dependency on another type by
// simply adding it as a function parameter. Dependencies for a type can be
// added to the graph both, before and after the type was added.
//
//   err := c.Provide(func(conn *sql.DB) (*UserGateway, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   if err := c.Provide(newDBConnection); err != nil {
//     // ...
//   }
//
// Multiple constructors can rely on the same type. The container creates a
// singleton for each retained type, instantiating it at most once when
// requested directly or as a dependency of another type.
//
//   err := c.Provide(func(conn *sql.DB) *CommentGateway {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Constructors can declare any number of dependencies as parameters and
// optionally, return errors.
//
//   err := c.Provide(func(u *UserGateway, c *CommentGateway) (*RequestHandler, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   if err := c.Provide(newHTTPServer); err != nil {
//     // ...
//   }
//
// Constructors can also return multiple results to add multiple types to the
// container.
//
//   err := c.Provide(func(conn *sql.DB) (*UserGateway, *CommentGateway, error) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Constructors that accept a variadic number of arguments are treated as if
// they don't have those arguments. That is,
//
//   func NewVoteGateway(db *sql.DB, options ...Option) *VoteGateway
//
// Is treated the same as,
//
//   func NewVoteGateway(db *sql.DB) *VoteGateway
//
// The constructor will be called with all other dependencies and no variadic
// arguments.
//
// Invoke
//
// Types added to to the container may be consumed by using the Invoke method.
// Invoke accepts any function that accepts one or more parameters and
// optionally, returns an error. Dig calls the function with the requested
// type, instantiating only those types that were requested by the function.
// The call fails if any type or its dependencies (both direct and transitive)
// were not available in the container.
//
//   err := c.Invoke(func(l *log.Logger) {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
//   err := c.Invoke(func(server *http.Server) error {
//     // ...
//   })
//   if err != nil {
//     // ...
//   }
//
// Any error returned by the invoked function is propagated back to the
// caller.
//
// Parameter Objects
//
// Constructors declare their dependencies as function parameters. This can
// very quickly become unreadable if the constructor has a lot of
// dependencies.
//
//   func NewHandler(users *UserGateway, comments *CommentGateway, posts *PostGateway, votes *VoteGateway, authz *AuthZGateway) *Handler {
//     // ...
//   }
//
// A pattern employed to improve readability in a situation like this is to
// create a struct that lists all the parameters of the function as fields and
// changing the function to accept that struct instead. This is referred to as
// a parameter object.
//
// Dig has first class support for parameter objects: any struct embedding
// dig.In gets treated as a parameter object. The following is equivalent to
// the constructor above.
//
//   type HandlerParams struct {
//     dig.In
//
//     Users    *UserGateway
//     Comments *CommentGateway
//     Posts    *PostGateway
//     Votes    *VoteGateway
//     AuthZ    *AuthZGateway
//   }
//
//   func NewHandler(p HandlerParams) *Handler {
//     // ...
//   }
//
// Handlers can receive any combination of parameter objects and parameters.
//
//   func NewHandler(p HandlerParams, l *log.Logger) *Handler {
//     // ...
//   }
//
// Result Objects
//
// Result objects are the flip side of parameter objects. These are structs
// that represent multiple outputs from a single function as fields in the
// struct. Structs embedding dig.Out get treated as result objects.
//
//   func SetupGateways(conn *sql.DB) (*UserGateway, *CommentGateway, *PostGateway, error) {
//     // ...
//   }
//
// The above is equivalent to,
//
//  type Gateways struct {
//    dig.Out
//
//    Users    *UserGateway
//    Comments *CommentGateway
//    Posts    *PostGateway
//  }
//
//  func SetupGateways(conn *sql.DB) (Gateways, error) {
//    // ...
//  }
//
// Optional Dependencies
//
// Constructors often don't have a hard dependency on some types and
// are able to operate in a degraded state when that dependency is missing.
// Dig supports declaring dependencies as optional by adding an
// `optional:"true"` tag to fields of a dig.In struct.
//
// Fields in a dig.In structs that have the `optional:"true"` tag are treated
// as optional by Dig.
//
//   type UserGatewayParams struct {
//     dig.In
//
//     Conn  *sql.DB
//     Cache *redis.Client `optional:"true"`
//   }
//
// If an optional field is not available in the container, the constructor
// will receive a zero value for the field.
//
//   func NewUserGateway(p UserGatewayParams, log *log.Logger) (*UserGateway, error) {
//     if p.Cache != nil {
//       log.Print("Logging disabled")
//     }
//     // ...
//   }
//
// Constructors that declare dependencies as optional MUST handle the case of
// those dependencies being absent.
//
// The optional tag also allows adding new dependencies without breaking
// existing consumers of the constructor.
//
// Named Values
//
// Some use cases call for multiple values of the same type. Dig allows adding
// multiple values of the same type to the container with the use of
// `name:".."` tags on fields of dig.In and dig.Out structs.
//
// A constructor that produces a dig.Out struct can tag any field with
// `name:".."` to have the corresponding value added to the graph under the
// specified name.
//
//   type ConnectionResult struct {
//     dig.Out
//
//     ReadWrite *sql.DB `name:"rw"`
//     ReadOnly  *sql.DB `name:"ro"`
//   }
//
//   func ConnectToDatabase(...) (ConnectionResult, error) {
//     // ...
//     return ConnectionResult{ReadWrite: rw, ReadOnly:  ro}, nil
//   }
//
// Another constructor can consume these values by adding fields to a dig.In
// struct with the same name AND type.
//
//   type GatewayParams struct {
//     dig.In
//
//     WriteToConn  *sql.DB `name:"rw"`
//     ReadFromConn *sql.DB `name:"ro"`
//   }
//
// The name tag may be combined with the optional tag to declare the
// dependency optional.
//
//   type GatewayParams struct {
//     dig.In
//
//     WriteToConn  *sql.DB `name:"rw"`
//     ReadFromConn *sql.DB `name:"ro" optional:"true"`
//   }
//
//   func NewCommentGateway(p GatewayParams, log *log.Logger) (*CommentGateway, error) {
//     if p.ReadFromConn == nil {
//       log.Print("Warning: Using RW connection for reads")
//       p.ReadFromConn = p.WriteToConn
//     }
//     // ...
//   }
//
// Value Groups
//
//   Added in Dig 1.2
//
// Dig provides value groups to allow producing and consuming many values of
// the same type. Value groups allow constructors to send values to a named,
// unordered collection in the container. Other constructors can request all
// values in this collection as a slice.
//
// Constructors can send values into value groups by returning a dig.Out
// struct tagged with `group:".."`.
//
//   type HandlerResult struct {
//     dig.Out
//
//     Handler Handler `group:"server"`
//   }
//
//   func NewHelloHandler() HandlerResult {
//     ..
//   }
//
//   func NewEchoHandler() HandlerResult {
//     ..
//   }
//
// Any number of constructors may provide values to this named collection.
// Other constructors can request all values for this collection by requesting
// a slice tagged with `group:".."`. This will execute all constructors that
// provide a value to that group in an unspecified order.
//
//   type ServerParams struct {
//     dig.In
//
//     Handlers []Handler `group:"server"`
//   }
//
//   func NewServer(p ServerParams) *Server {
//     server := newServer()
//     for _, h := range p.Handlers {
//       server.Register(h)
//     }
//     return server
//   }
//
// Note that values in a value group are unordered. Dig makes no guarantees
// about the order in which these values will be produced.
package dig
<|endoftext|>