func New(options ...Options) *JWTMiddleware {

	var opts Options
	if len(options) == 0 {
		opts = Options{}
	} else {
		opts = options[0]
	}

	if opts.UserProperty == "" {
		opts.UserProperty = "user"
	}

	if opts.ErrorHandler == nil {
		opts.ErrorHandler = OnError
	}

	if opts.Extractor == nil {
		opts.Extractor = FromAuthHeader
	}

	return &JWTMiddleware{
		Options: opts,
	}
}

func New ( options ... Options ) * JWTMiddleware { var opts Options if len ( options ) == 0 { opts = Options { } } else { opts = options [ 0 ] } if opts . UserProperty == " " { opts . UserProperty = " " } if opts . ErrorHandler == nil { opts . ErrorHandler = OnError } if opts . Extractor == nil { opts . Extractor = FromAuthHeader } return & JWTMiddleware { Options : opts , } }

// New constructs a new Secure instance with supplied options.

New constructs a new Secure instance with supplied options .


func (m *JWTMiddleware) HandlerWithNext(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
	err := m.CheckJWT(w, r)

	// If there was an error, do not call next.
	if err == nil && next != nil {
		next(w, r)
	}
}

// Special implementation for Negroni, but could be used elsewhere.

Special implementation for Negroni but could be used elsewhere .


func FromAuthHeader(r *http.Request) (string, error) {
	authHeader := r.Header.Get("Authorization")
	if authHeader == "" {
		return "", nil // No error, just no token
	}

	// TODO: Make this a bit more robust, parsing-wise
	authHeaderParts := strings.Split(authHeader, " ")
	if len(authHeaderParts) != 2 || strings.ToLower(authHeaderParts[0]) != "bearer" {
		return "", errors.New("Authorization header format must be Bearer {token}")
	}

	return authHeaderParts[1], nil
}

// FromAuthHeader is a "TokenExtractor" that takes a give request and extracts
// the JWT token from the Authorization header.

FromAuthHeader is a TokenExtractor that takes a give request and extracts the JWT token from the Authorization header .


func FromParameter(param string) TokenExtractor {
	return func(r *http.Request) (string, error) {
		return r.URL.Query().Get(param), nil
	}
}

func FromParameter ( param string ) TokenExtractor { return func ( r * http . Request ) ( string , error ) { return r . URL . Query ( ) . Get ( param ) , nil } }

// FromParameter returns a function that extracts the token from the specified
// query string parameter

FromParameter returns a function that extracts the token from the specified query string parameter


func FromFirst(extractors ...TokenExtractor) TokenExtractor {
	return func(r *http.Request) (string, error) {
		for _, ex := range extractors {
			token, err := ex(r)
			if err != nil {
				return "", err
			}
			if token != "" {
				return token, nil
			}
		}
		return "", nil
	}
}

func FromFirst ( extractors ... TokenExtractor ) TokenExtractor { return func ( r * http . Request ) ( string , error ) { for _ , ex := range extractors { token , err := ex ( r ) if err != nil { return " " , err } if token != " " { return token , nil } } return " " , nil } }

// FromFirst returns a function that runs multiple token extractors and takes the
// first token it finds

FromFirst returns a function that runs multiple token extractors and takes the first token it finds


func (p *PubSub) getHelloPacket() *RPC {
	var rpc RPC
	for t := range p.myTopics {
		as := &pb.RPC_SubOpts{
			Topicid:   proto.String(t),
			Subscribe: proto.Bool(true),
		}
		rpc.Subscriptions = append(rpc.Subscriptions, as)
	}
	return &rpc
}

func ( p * PubSub ) getHelloPacket ( ) * RPC { var rpc RPC for t := range p . myTopics { as := & pb . RPC_SubOpts { Topicid : proto . String ( t ) , Subscribe : proto . Bool ( true ) , } rpc . Subscriptions = append ( rpc . Subscriptions , as ) } return & rpc }

// get the initial RPC containing all of our subscriptions to send to new peers


func NewFloodsubWithProtocols(ctx context.Context, h host.Host, ps []protocol.ID, opts ...Option) (*PubSub, error) {
	rt := &FloodSubRouter{
		protocols: ps,
	}
	return NewPubSub(ctx, h, rt, opts...)
}

func NewFloodsubWithProtocols ( ctx context . Context , h host . Host , ps [ ] protocol . ID , opts ... Option ) ( * PubSub , error ) { rt := & FloodSubRouter { protocols : ps , } return NewPubSub ( ctx , h , rt , opts ... ) }

// NewFloodsubWithProtocols returns a new floodsub-enabled PubSub objecting using the protocols specified in ps.

NewFloodsubWithProtocols returns a new floodsub - enabled PubSub objecting using the protocols specified in ps .


func NewFloodSub(ctx context.Context, h host.Host, opts ...Option) (*PubSub, error) {
	return NewFloodsubWithProtocols(ctx, h, []protocol.ID{FloodSubID}, opts...)
}

func NewFloodSub ( ctx context . Context , h host . Host , opts ... Option ) ( * PubSub , error ) { return NewFloodsubWithProtocols ( ctx , h , [ ] protocol . ID { FloodSubID } , opts ... ) }

// NewFloodSub returns a new PubSub object using the FloodSubRouter.

NewFloodSub returns a new PubSub object using the FloodSubRouter .


func NewLRUBlacklist(cap int) (Blacklist, error) {
	c, err := lru.New(cap)
	if err != nil {
		return nil, err
	}

	b := &LRUBlacklist{lru: c}
	return b, nil
}

func NewLRUBlacklist ( cap int ) ( Blacklist , error ) { c , err := lru . New ( cap ) if err != nil { return nil , err } b := & LRUBlacklist { lru : c } return b , nil }

// NewLRUBlacklist creates a new LRUBlacklist with capacity cap


func NewRandomSub(ctx context.Context, h host.Host, opts ...Option) (*PubSub, error) {
	rt := &RandomSubRouter{
		peers: make(map[peer.ID]protocol.ID),
	}
	return NewPubSub(ctx, h, rt, opts...)
}

func NewRandomSub ( ctx context . Context , h host . Host , opts ... Option ) ( * PubSub , error ) { rt := & RandomSubRouter { peers : make ( map [ peer . ID ] protocol . ID ) , } return NewPubSub ( ctx , h , rt , opts ... ) }

// NewRandomSub returns a new PubSub object using RandomSubRouter as the router.

NewRandomSub returns a new PubSub object using RandomSubRouter as the router .


func NewGossipSub(ctx context.Context, h host.Host, opts ...Option) (*PubSub, error) {
	rt := &GossipSubRouter{
		peers:   make(map[peer.ID]protocol.ID),
		mesh:    make(map[string]map[peer.ID]struct{}),
		fanout:  make(map[string]map[peer.ID]struct{}),
		lastpub: make(map[string]int64),
		gossip:  make(map[peer.ID][]*pb.ControlIHave),
		control: make(map[peer.ID]*pb.ControlMessage),
		mcache:  NewMessageCache(GossipSubHistoryGossip, GossipSubHistoryLength),
	}
	return NewPubSub(ctx, h, rt, opts...)
}

func NewGossipSub ( ctx context . Context , h host . Host , opts ... Option ) ( * PubSub , error ) { rt := & GossipSubRouter { peers : make ( map [ peer . ID ] protocol . ID ) , mesh : make ( map [ string ] map [ peer . ID ] struct { } ) , fanout : make ( map [ string ] map [ peer . ID ] struct { } ) , lastpub : make ( map [ string ] int64 ) , gossip : make ( map [ peer . ID ] [ ] * pb . ControlIHave ) , control : make ( map [ peer . ID ] * pb . ControlMessage ) , mcache : NewMessageCache ( GossipSubHistoryGossip , GossipSubHistoryLength ) , } return NewPubSub ( ctx , h , rt , opts ... ) }

// NewGossipSub returns a new PubSub object using GossipSubRouter as the router.

NewGossipSub returns a new PubSub object using GossipSubRouter as the router .


func NewPubSub(ctx context.Context, h host.Host, rt PubSubRouter, opts ...Option) (*PubSub, error) {
	ps := &PubSub{
		host:             h,
		ctx:              ctx,
		rt:               rt,
		signID:           h.ID(),
		signKey:          h.Peerstore().PrivKey(h.ID()),
		signStrict:       true,
		incoming:         make(chan *RPC, 32),
		publish:          make(chan *Message),
		newPeers:         make(chan peer.ID),
		newPeerStream:    make(chan inet.Stream),
		newPeerError:     make(chan peer.ID),
		peerDead:         make(chan peer.ID),
		cancelCh:         make(chan *Subscription),
		getPeers:         make(chan *listPeerReq),
		addSub:           make(chan *addSubReq),
		getTopics:        make(chan *topicReq),
		sendMsg:          make(chan *sendReq, 32),
		addVal:           make(chan *addValReq),
		rmVal:            make(chan *rmValReq),
		validateThrottle: make(chan struct{}, defaultValidateThrottle),
		eval:             make(chan func()),
		myTopics:         make(map[string]map[*Subscription]struct{}),
		topics:           make(map[string]map[peer.ID]struct{}),
		peers:            make(map[peer.ID]chan *RPC),
		topicVals:        make(map[string]*topicVal),
		blacklist:        NewMapBlacklist(),
		blacklistPeer:    make(chan peer.ID),
		seenMessages:     timecache.NewTimeCache(TimeCacheDuration),
		counter:          uint64(time.Now().UnixNano()),
	}

	for _, opt := range opts {
		err := opt(ps)
		if err != nil {
			return nil, err
		}
	}

	if ps.signStrict && ps.signKey == nil {
		return nil, fmt.Errorf("strict signature verification enabled but message signing is disabled")
	}

	rt.Attach(ps)

	for _, id := range rt.Protocols() {
		h.SetStreamHandler(id, ps.handleNewStream)
	}
	h.Network().Notify((*PubSubNotif)(ps))

	go ps.processLoop(ctx)

	return ps, nil
}

func NewPubSub ( ctx context . Context , h host . Host , rt PubSubRouter , opts ... Option ) ( * PubSub , error ) { ps := & PubSub { host : h , ctx : ctx , rt : rt , signID : h . ID ( ) , signKey : h . Peerstore ( ) . PrivKey ( h . ID ( ) ) , signStrict : true , incoming : make ( chan * RPC , 32 ) , publish : make ( chan * Message ) , newPeers : make ( chan peer . ID ) , newPeerStream : make ( chan inet . Stream ) , newPeerError : make ( chan peer . ID ) , peerDead : make ( chan peer . ID ) , cancelCh : make ( chan * Subscription ) , getPeers : make ( chan * listPeerReq ) , addSub : make ( chan * addSubReq ) , getTopics : make ( chan * topicReq ) , sendMsg : make ( chan * sendReq , 32 ) , addVal : make ( chan * addValReq ) , rmVal : make ( chan * rmValReq ) , validateThrottle : make ( chan struct { } , defaultValidateThrottle ) , eval : make ( chan func ( ) ) , myTopics : make ( map [ string ] map [ * Subscription ] struct { } ) , topics : make ( map [ string ] map [ peer . ID ] struct { } ) , peers : make ( map [ peer . ID ] chan * RPC ) , topicVals : make ( map [ string ] * topicVal ) , blacklist : NewMapBlacklist ( ) , blacklistPeer : make ( chan peer . ID ) , seenMessages : timecache . NewTimeCache ( TimeCacheDuration ) , counter : uint64 ( time . Now ( ) . UnixNano ( ) ) , } for _ , opt := range opts { err := opt ( ps ) if err != nil { return nil , err } } if ps . signStrict && ps . signKey == nil { return nil , fmt . Errorf ( " " ) } rt . Attach ( ps ) for _ , id := range rt . Protocols ( ) { h . SetStreamHandler ( id , ps . handleNewStream ) } h . Network ( ) . Notify ( ( * PubSubNotif ) ( ps ) ) go ps . processLoop ( ctx ) return ps , nil }

// NewPubSub returns a new PubSub management object.

NewPubSub returns a new PubSub management object .


func WithValidateThrottle(n int) Option {
	return func(ps *PubSub) error {
		ps.validateThrottle = make(chan struct{}, n)
		return nil
	}
}

func WithValidateThrottle ( n int ) Option { return func ( ps * PubSub ) error { ps . validateThrottle = make ( chan struct { } , n ) return nil } }

// WithValidateThrottle sets the upper bound on the number of active validation
// goroutines.

WithValidateThrottle sets the upper bound on the number of active validation goroutines .


func WithBlacklist(b Blacklist) Option {
	return func(p *PubSub) error {
		p.blacklist = b
		return nil
	}
}

func WithBlacklist ( b Blacklist ) Option { return func ( p * PubSub ) error { p . blacklist = b return nil } }

// WithBlacklist provides an implementation of the blacklist; the default is a
// MapBlacklist

WithBlacklist provides an implementation of the blacklist ; the default is a MapBlacklist


func (p *PubSub) handleRemoveSubscription(sub *Subscription) {
	subs := p.myTopics[sub.topic]

	if subs == nil {
		return
	}

	sub.err = fmt.Errorf("subscription cancelled by calling sub.Cancel()")
	close(sub.ch)
	delete(subs, sub)

	if len(subs) == 0 {
		delete(p.myTopics, sub.topic)
		p.announce(sub.topic, false)
		p.rt.Leave(sub.topic)
	}
}

func ( p * PubSub ) handleRemoveSubscription ( sub * Subscription ) { subs := p . myTopics [ sub . topic ] if subs == nil { return } sub . err = fmt . Errorf ( " " ) close ( sub . ch ) delete ( subs , sub ) if len ( subs ) == 0 { delete ( p . myTopics , sub . topic ) p . announce ( sub . topic , false ) p . rt . Leave ( sub . topic ) } }

// handleRemoveSubscription removes Subscription sub from bookeeping.
// If this was the last Subscription for a given topic, it will also announce
// that this node is not subscribing to this topic anymore.
// Only called from processLoop.

handleRemoveSubscription removes Subscription sub from bookeeping . If this was the last Subscription for a given topic it will also announce that this node is not subscribing to this topic anymore . Only called from processLoop .


func (p *PubSub) handleAddSubscription(req *addSubReq) {
	sub := req.sub
	subs := p.myTopics[sub.topic]

	// announce we want this topic
	if len(subs) == 0 {
		p.announce(sub.topic, true)
		p.rt.Join(sub.topic)
	}

	// make new if not there
	if subs == nil {
		p.myTopics[sub.topic] = make(map[*Subscription]struct{})
		subs = p.myTopics[sub.topic]
	}

	sub.ch = make(chan *Message, 32)
	sub.cancelCh = p.cancelCh

	p.myTopics[sub.topic][sub] = struct{}{}

	req.resp <- sub
}

func
(
p
*
PubSub
)
handleAddSubscription
(
req
*
addSubReq
)
{
sub
:=
req
.
sub
subs
:=
p
.
myTopics
[
sub
.
topic
]
// announce we want this topic
if
len
(
subs
)
==
0
{
p
.
announce
(
sub
.
topic
,
true
)
p
.
rt
.
Join
(
sub
.
topic
)
}
// make new if not there
if
subs
==
{
p
.
myTopics
[
sub
.
topic
]
=
make
(
map
[
*
Subscription
]
struct
{
}
)
subs
=
p
.
myTopics
[
sub
.
topic
]
}
sub
.
ch
=
make
(
chan
*
Message
,
32
)
sub
.
cancelCh
=
p
.
cancelCh
p
.
myTopics
[
sub
.
topic
]
[
sub
]
=
struct
{
}
{
}
req
.
resp
<-
sub
}

// handleAddSubscription adds a Subscription for a particular topic. If it is
// the first Subscription for the topic, it will announce that this node
// subscribes to the topic.
// Only called from processLoop.

handleAddSubscription adds a Subscription for a particular topic . If it is the first Subscription for the topic it will announce that this node subscribes to the topic . Only called from processLoop .


func (p *PubSub) announce(topic string, sub bool) {
	subopt := &pb.RPC_SubOpts{
		Topicid:   &topic,
		Subscribe: &sub,
	}

	out := rpcWithSubs(subopt)
	for pid, peer := range p.peers {
		select {
		case peer <- out:
		default:
			log.Infof("Can't send announce message to peer %s: queue full; scheduling retry", pid)
			go p.announceRetry(pid, topic, sub)
		}
	}
}

func ( p * PubSub ) announce ( topic string , sub bool ) { subopt := & pb . RPC_SubOpts { Topicid : & topic , Subscribe : & sub , } out := rpcWithSubs ( subopt ) for pid , peer := range p . peers { select { case peer <- out : default : log . Infof ( " " , pid ) go p . announceRetry ( pid , topic , sub ) } } }

// announce announces whether or not this node is interested in a given topic
// Only called from processLoop.

announce announces whether or not this node is interested in a given topic Only called from processLoop .


func (p *PubSub) notifySubs(msg *pb.Message) {
	for _, topic := range msg.GetTopicIDs() {
		subs := p.myTopics[topic]
		for f := range subs {
			select {
			case f.ch <- &Message{msg}:
			default:
				log.Infof("Can't deliver message to subscription for topic %s; subscriber too slow", topic)
			}
		}
	}
}

func ( p * PubSub ) notifySubs ( msg * pb . Message ) { for _ , topic := range msg . GetTopicIDs ( ) { subs := p . myTopics [ topic ] for f := range subs { select { case f . ch <- & Message { msg } : default : log . Infof ( " " , topic ) } } } }

// notifySubs sends a given message to all corresponding subscribers.
// Only called from processLoop.

notifySubs sends a given message to all corresponding subscribers . Only called from processLoop .


func (p *PubSub) seenMessage(id string) bool {
	return p.seenMessages.Has(id)
}

func ( p * PubSub ) seenMessage ( id string ) bool { return p . seenMessages . Has ( id ) }

// seenMessage returns whether we already saw this message before


func (p *PubSub) subscribedToMsg(msg *pb.Message) bool {
	if len(p.myTopics) == 0 {
		return false
	}

	for _, t := range msg.GetTopicIDs() {
		if _, ok := p.myTopics[t]; ok {
			return true
		}
	}
	return false
}

func ( p * PubSub ) subscribedToMsg ( msg * pb . Message ) bool { if len ( p . myTopics ) == 0 { return false } for _ , t := range msg . GetTopicIDs ( ) { if _ , ok := p . myTopics [ t ] ; ok { return true } } return false }

// subscribedToMessage returns whether we are subscribed to one of the topics
// of a given message

subscribedToMessage returns whether we are subscribed to one of the topics of a given message


func msgID(pmsg *pb.Message) string {
	return string(pmsg.GetFrom()) + string(pmsg.GetSeqno())
}

func msgID ( pmsg * pb . Message ) string { return string ( pmsg . GetFrom ( ) ) + string ( pmsg . GetSeqno ( ) ) }

// msgID returns a unique ID of the passed Message


func (p *PubSub) pushMsg(vals []*topicVal, src peer.ID, msg *Message) {
	// reject messages from blacklisted peers
	if p.blacklist.Contains(src) {
		log.Warningf("dropping message from blacklisted peer %s", src)
		return
	}

	// even if they are forwarded by good peers
	if p.blacklist.Contains(msg.GetFrom()) {
		log.Warningf("dropping message from blacklisted source %s", src)
		return
	}

	// reject unsigned messages when strict before we even process the id
	if p.signStrict && msg.Signature == nil {
		log.Debugf("dropping unsigned message from %s", src)
		return
	}

	// have we already seen and validated this message?
	id := msgID(msg.Message)
	if p.seenMessage(id) {
		return
	}

	if len(vals) > 0 || msg.Signature != nil {
		// validation is asynchronous and globally throttled with the throttleValidate semaphore.
		// the purpose of the global throttle is to bound the goncurrency possible from incoming
		// network traffic; each validator also has an individual throttle to preclude
		// slow (or faulty) validators from starving other topics; see validate below.
		select {
		case p.validateThrottle <- struct{}{}:
			go func() {
				p.validate(vals, src, msg)
				<-p.validateThrottle
			}()
		default:
			log.Warningf("message validation throttled; dropping message from %s", src)
		}
		return
	}

	p.publishMessage(src, msg.Message)
}

// pushMsg pushes a message performing validation as necessary


func (p *PubSub) validate(vals []*topicVal, src peer.ID, msg *Message) {
	if msg.Signature != nil {
		if !p.validateSignature(msg) {
			log.Warningf("message signature validation failed; dropping message from %s", src)
			return
		}
	}

	if len(vals) > 0 {
		if !p.validateTopic(vals, src, msg) {
			log.Warningf("message validation failed; dropping message from %s", src)
			return
		}
	}

	// all validators were successful, send the message
	p.sendMsg <- &sendReq{
		from: src,
		msg:  msg,
	}
}

// validate performs validation and only sends the message if all validators succeed


func (p *PubSub) validateSingleTopic(val *topicVal, src peer.ID, msg *Message) bool {
	select {
	case val.validateThrottle <- struct{}{}:
		ctx, cancel := context.WithCancel(p.ctx)
		defer cancel()

		res := val.validateMsg(ctx, src, msg)
		<-val.validateThrottle

		return res

	default:
		log.Debugf("validation throttled for topic %s", val.topic)
		return false
	}
}

func ( p * PubSub ) validateSingleTopic ( val * topicVal , src peer . ID , msg * Message ) bool { select { case val . validateThrottle <- struct { } { } : ctx , cancel := context . WithCancel ( p . ctx ) defer cancel ( ) res := val . validateMsg ( ctx , src , msg ) <- val . validateThrottle return res default : log . Debugf ( " " , val . topic ) return false } }

// fast path for single topic validation that avoids the extra goroutine


func (p *PubSub) getValidators(msg *Message) []*topicVal {
	var vals []*topicVal

	for _, topic := range msg.GetTopicIDs() {
		val, ok := p.topicVals[topic]
		if !ok {
			continue
		}

		vals = append(vals, val)
	}

	return vals
}

func ( p * PubSub ) getValidators ( msg * Message ) [ ] * topicVal { var vals [ ] * topicVal for _ , topic := range msg . GetTopicIDs ( ) { val , ok := p . topicVals [ topic ] if ! ok { continue } vals = append ( vals , val ) } return vals }

// getValidators returns all validators that apply to a given message


func (p *PubSub) Subscribe(topic string, opts ...SubOpt) (*Subscription, error) {
	td := pb.TopicDescriptor{Name: &topic}

	return p.SubscribeByTopicDescriptor(&td, opts...)
}

func ( p * PubSub ) Subscribe ( topic string , opts ... SubOpt ) ( * Subscription , error ) { td := pb . TopicDescriptor { Name : & topic } return p . SubscribeByTopicDescriptor ( & td , opts ... ) }

// Subscribe returns a new Subscription for the given topic.
// Note that subscription is not an instanteneous operation. It may take some time
// before the subscription is processed by the pubsub main loop and propagated to our peers.

Subscribe returns a new Subscription for the given topic . Note that subscription is not an instanteneous operation . It may take some time before the subscription is processed by the pubsub main loop and propagated to our peers .


func (p *PubSub) SubscribeByTopicDescriptor(td *pb.TopicDescriptor, opts ...SubOpt) (*Subscription, error) {
	if td.GetAuth().GetMode() != pb.TopicDescriptor_AuthOpts_NONE {
		return nil, fmt.Errorf("auth mode not yet supported")
	}

	if td.GetEnc().GetMode() != pb.TopicDescriptor_EncOpts_NONE {
		return nil, fmt.Errorf("encryption mode not yet supported")
	}

	sub := &Subscription{
		topic: td.GetName(),
	}

	for _, opt := range opts {
		err := opt(sub)
		if err != nil {
			return nil, err
		}
	}

	out := make(chan *Subscription, 1)
	p.addSub <- &addSubReq{
		sub:  sub,
		resp: out,
	}

	return <-out, nil
}

func ( p * PubSub ) SubscribeByTopicDescriptor ( td * pb . TopicDescriptor , opts ... SubOpt ) ( * Subscription , error ) { if td . GetAuth ( ) . GetMode ( ) != pb . TopicDescriptor_AuthOpts_NONE { return nil , fmt . Errorf ( " " ) } if td . GetEnc ( ) . GetMode ( ) != pb . TopicDescriptor_EncOpts_NONE { return nil , fmt . Errorf ( " " ) } sub := & Subscription { topic : td . GetName ( ) , } for _ , opt := range opts { err := opt ( sub ) if err != nil { return nil , err } } out := make ( chan * Subscription , 1 ) p . addSub <- & addSubReq { sub : sub , resp : out , } return <- out , nil }

// SubscribeByTopicDescriptor lets you subscribe a topic using a pb.TopicDescriptor.

SubscribeByTopicDescriptor lets you subscribe a topic using a pb . TopicDescriptor .


func (p *PubSub) GetTopics() []string {
	out := make(chan []string, 1)
	p.getTopics <- &topicReq{resp: out}
	return <-out
}

func ( p * PubSub ) GetTopics ( ) [ ] string { out := make ( chan [ ] string , 1 ) p . getTopics <- & topicReq { resp : out } return <- out }

// GetTopics returns the topics this node is subscribed to.

GetTopics returns the topics this node is subscribed to .


func (p *PubSub) Publish(topic string, data []byte) error {
	seqno := p.nextSeqno()
	m := &pb.Message{
		Data:     data,
		TopicIDs: []string{topic},
		From:     []byte(p.host.ID()),
		Seqno:    seqno,
	}
	if p.signKey != nil {
		m.From = []byte(p.signID)
		err := signMessage(p.signID, p.signKey, m)
		if err != nil {
			return err
		}
	}
	p.publish <- &Message{m}
	return nil
}

func ( p * PubSub ) Publish ( topic string , data [ ] byte ) error { seqno := p . nextSeqno ( ) m := & pb . Message { Data : data , TopicIDs : [ ] string { topic } , From : [ ] byte ( p . host . ID ( ) ) , Seqno : seqno , } if p . signKey != nil { m . From = [ ] byte ( p . signID ) err := signMessage ( p . signID , p . signKey , m ) if err != nil { return err } } p . publish <- & Message { m } return nil }

// Publish publishes data to the given topic.

Publish publishes data to the given topic .


func (p *PubSub) ListPeers(topic string) []peer.ID {
	out := make(chan []peer.ID)
	p.getPeers <- &listPeerReq{
		resp:  out,
		topic: topic,
	}
	return <-out
}

func ( p * PubSub ) ListPeers ( topic string ) [ ] peer . ID { out := make ( chan [ ] peer . ID ) p . getPeers <- & listPeerReq { resp : out , topic : topic , } return <- out }

// ListPeers returns a list of peers we are connected to in the given topic.

ListPeers returns a list of peers we are connected to in the given topic .


func WithValidatorTimeout(timeout time.Duration) ValidatorOpt {
	return func(addVal *addValReq) error {
		addVal.timeout = timeout
		return nil
	}
}

func WithValidatorTimeout ( timeout time . Duration ) ValidatorOpt { return func ( addVal * addValReq ) error { addVal . timeout = timeout return nil } }

// WithValidatorTimeout is an option that sets the topic validator timeout.

WithValidatorTimeout is an option that sets the topic validator timeout .


func WithValidatorConcurrency(n int) ValidatorOpt {
	return func(addVal *addValReq) error {
		addVal.throttle = n
		return nil
	}
}

func WithValidatorConcurrency ( n int ) ValidatorOpt { return func ( addVal * addValReq ) error { addVal . throttle = n return nil } }

// WithValidatorConcurrency is an option that sets topic validator throttle.

WithValidatorConcurrency is an option that sets topic validator throttle .


func (p *PubSub) RegisterTopicValidator(topic string, val Validator, opts ...ValidatorOpt) error {
	addVal := &addValReq{
		topic:    topic,
		validate: val,
		resp:     make(chan error, 1),
	}

	for _, opt := range opts {
		err := opt(addVal)
		if err != nil {
			return err
		}
	}

	p.addVal <- addVal
	return <-addVal.resp
}

func ( p * PubSub ) RegisterTopicValidator ( topic string , val Validator , opts ... ValidatorOpt ) error { addVal := & addValReq { topic : topic , validate : val , resp : make ( chan error , 1 ) , } for _ , opt := range opts { err := opt ( addVal ) if err != nil { return err } } p . addVal <- addVal return <- addVal . resp }

// RegisterTopicValidator registers a validator for topic.

RegisterTopicValidator registers a validator for topic .


func (p *PubSub) UnregisterTopicValidator(topic string) error {
	rmVal := &rmValReq{
		topic: topic,
		resp:  make(chan error, 1),
	}

	p.rmVal <- rmVal
	return <-rmVal.resp
}

func ( p * PubSub ) UnregisterTopicValidator ( topic string ) error { rmVal := & rmValReq { topic : topic , resp : make ( chan error , 1 ) , } p . rmVal <- rmVal return <- rmVal . resp }

// UnregisterTopicValidator removes a validator from a topic.
// Returns an error if there was no validator registered with the topic.

UnregisterTopicValidator removes a validator from a topic . Returns an error if there was no validator registered with the topic .


func DefaultMetricPrefix(name string, tags map[string]string) string {
	return MetricWithPrefix("tchannel.", name, tags)
}

func DefaultMetricPrefix ( name string , tags map [ string ] string ) string { return MetricWithPrefix ( " " , name , tags ) }

// DefaultMetricPrefix is the default mapping for metrics to statsd keys.
// It uses a "tchannel" prefix for all stats.

DefaultMetricPrefix is the default mapping for metrics to statsd keys . It uses a tchannel prefix for all stats .


func MetricWithPrefix(prefix, name string, tags map[string]string) string {
	buf := bufPool.Get().(*bytes.Buffer)
	buf.Reset()

	if prefix != "" {
		buf.WriteString(prefix)
	}
	buf.WriteString(name)

	addKeys := make([]string, 0, 5)
	switch {
	case strings.HasPrefix(name, "outbound"):
		addKeys = append(addKeys, "service", "target-service", "target-endpoint")
		if strings.HasPrefix(name, "outbound.calls.retries") {
			addKeys = append(addKeys, "retry-count")
		}
	case strings.HasPrefix(name, "inbound"):
		addKeys = append(addKeys, "calling-service", "service", "endpoint")
	}

	for _, k := range addKeys {
		buf.WriteByte('.')
		v, ok := tags[k]
		if ok {
			writeClean(buf, v)
		} else {
			buf.WriteString("no-")
			buf.WriteString(k)
		}
	}

	m := buf.String()
	bufPool.Put(buf)
	return m
}

func MetricWithPrefix ( prefix , name string , tags map [ string ] string ) string { buf := bufPool . Get ( ) . ( * bytes . Buffer ) buf . Reset ( ) if prefix != " " { buf . WriteString ( prefix ) } buf . WriteString ( name ) addKeys := make ( [ ] string , 0 , 5 ) switch { case strings . HasPrefix ( name , " " ) : addKeys = append ( addKeys , " " , " " , " " ) if strings . HasPrefix ( name , " " ) { addKeys = append ( addKeys , " " ) } case strings . HasPrefix ( name , " " ) : addKeys = append ( addKeys , " " , " " , " " ) } for _ , k := range addKeys { buf . WriteByte ( '.' ) v , ok := tags [ k ] if ok { writeClean ( buf , v ) } else { buf . WriteString ( " " ) buf . WriteString ( k ) } } m := buf . String ( ) bufPool . Put ( buf ) return m }

// MetricWithPrefix is the default mapping for metrics to statsd keys.

MetricWithPrefix is the default mapping for metrics to statsd keys .


func NewClient(ch *tchannel.Channel, targetService string, opts *ClientOptions) *Client {
	client := &Client{
		ch:            ch,
		targetService: targetService,
	}
	if opts != nil && opts.HostPort != "" {
		client.hostPort = opts.HostPort
	}
	return client
}

func NewClient ( ch * tchannel . Channel , targetService string , opts * ClientOptions ) * Client { client := & Client { ch : ch , targetService : targetService , } if opts != nil && opts . HostPort != " " { client . hostPort = opts . HostPort } return client }

// NewClient returns a json.Client used to make outbound JSON calls.

NewClient returns a json . Client used to make outbound JSON calls .


func (c *Client) Call(ctx Context, method string, arg, resp interface{}) error {
	var (
		headers = ctx.Headers()

		respHeaders map[string]string
		respErr     ErrApplication
		errAt       string
		isOK        bool
	)

	err := c.ch.RunWithRetry(ctx, func(ctx context.Context, rs *tchannel.RequestState) error {
		respHeaders, respErr, isOK = nil, nil, false
		errAt = "connect"

		call, err := c.startCall(ctx, method, &tchannel.CallOptions{
			Format:       tchannel.JSON,
			RequestState: rs,
		})
		if err != nil {
			return err
		}

		isOK, errAt, err = makeCall(call, headers, arg, &respHeaders, resp, &respErr)
		return err
	})
	if err != nil {
		// TODO: Don't lose the error type here.
		return fmt.Errorf("%s: %v", errAt, err)
	}
	if !isOK {
		return respErr
	}

	return nil
}

// Call makes a JSON call, with retries.


func CallPeer(ctx Context, peer *tchannel.Peer, serviceName, method string, arg, resp interface{}) error {
	call, err := peer.BeginCall(ctx, serviceName, method, &tchannel.CallOptions{Format: tchannel.JSON})
	if err != nil {
		return err
	}

	return wrapCall(ctx, call, method, arg, resp)
}

func CallPeer ( ctx Context , peer * tchannel . Peer , serviceName , method string , arg , resp interface { } ) error { call , err := peer . BeginCall ( ctx , serviceName , method , & tchannel . CallOptions { Format : tchannel . JSON } ) if err != nil { return err } return wrapCall ( ctx , call , method , arg , resp ) }

// CallPeer makes a JSON call using the given peer.

CallPeer makes a JSON call using the given peer .


func CallSC(ctx Context, sc *tchannel.SubChannel, method string, arg, resp interface{}) error {
	call, err := sc.BeginCall(ctx, method, &tchannel.CallOptions{Format: tchannel.JSON})
	if err != nil {
		return err
	}

	return wrapCall(ctx, call, method, arg, resp)
}

func CallSC ( ctx Context , sc * tchannel . SubChannel , method string , arg , resp interface { } ) error { call , err := sc . BeginCall ( ctx , method , & tchannel . CallOptions { Format : tchannel . JSON } ) if err != nil { return err } return wrapCall ( ctx , call , method , arg , resp ) }

// CallSC makes a JSON call using the given subchannel.

CallSC makes a JSON call using the given subchannel .


func ReadResponse(call tchannel.ArgReadable) (*http.Response, error) {
	var arg2 []byte
	if err := tchannel.NewArgReader(call.Arg2Reader()).Read(&arg2); err != nil {
		return nil, err
	}

	rb := typed.NewReadBuffer(arg2)
	statusCode := rb.ReadUint16()
	message := readVarintString(rb)

	response := &http.Response{
		StatusCode: int(statusCode),
		Status:     fmt.Sprintf("%v %v", statusCode, message),
		Proto:      "HTTP/1.1",
		ProtoMajor: 1,
		ProtoMinor: 1,
		Header:     make(http.Header),
	}
	readHeaders(rb, response.Header)
	if err := rb.Err(); err != nil {
		return nil, err
	}

	arg3Reader, err := call.Arg3Reader()
	if err != nil {
		return nil, err
	}

	response.Body = arg3Reader
	return response, nil
}

func ReadResponse ( call tchannel . ArgReadable ) ( * http . Response , error ) { var arg2 [ ] byte if err := tchannel . NewArgReader ( call . Arg2Reader ( ) ) . Read ( & arg2 ) ; err != nil { return nil , err } rb := typed . NewReadBuffer ( arg2 ) statusCode := rb . ReadUint16 ( ) message := readVarintString ( rb ) response := & http . Response { StatusCode : int ( statusCode ) , Status : fmt . Sprintf ( " " , statusCode , message ) , Proto : " " , ProtoMajor : 1 , ProtoMinor : 1 , Header : make ( http . Header ) , } readHeaders ( rb , response . Header ) if err := rb . Err ( ) ; err != nil { return nil , err } arg3Reader , err := call . Arg3Reader ( ) if err != nil { return nil , err } response . Body = arg3Reader return response , nil }

// ReadResponse reads a http.Response from the given readers.

ReadResponse reads a http . Response from the given readers .


func (w *tchanResponseWriter) writeHeaders() {
	// TODO(prashant): Allow creating write buffers that let you grow the buffer underneath.
	wb := typed.NewWriteBufferWithSize(10000)
	wb.WriteUint16(uint16(w.statusCode))
	writeVarintString(wb, http.StatusText(w.statusCode))
	writeHeaders(wb, w.headers)

	arg2Writer, err := w.response.Arg2Writer()
	if err != nil {
		w.err = err
		return
	}
	if _, w.err = wb.FlushTo(arg2Writer); w.err != nil {
		return
	}
	if w.err = arg2Writer.Close(); w.err != nil {
		return
	}

	w.arg3Writer, w.err = w.response.Arg3Writer()
}

// writeHeaders writes out the HTTP headers as arg2, and creates the arg3 writer.

writeHeaders writes out the HTTP headers as arg2 and creates the arg3 writer .


func ResponseWriter(response tchannel.ArgWritable) (http.ResponseWriter, func() error) {
	responseWriter := newTChanResponseWriter(response)
	return responseWriter, responseWriter.finish
}

func ResponseWriter ( response tchannel . ArgWritable ) ( http . ResponseWriter , func ( ) error ) { responseWriter := newTChanResponseWriter ( response ) return responseWriter , responseWriter . finish }

// ResponseWriter returns a http.ResponseWriter that will write to an underlying writer.
// It also returns a function that should be called once the handler has completed.

ResponseWriter returns a http . ResponseWriter that will write to an underlying writer . It also returns a function that should be called once the handler has completed .


func ReadHeaders(r io.Reader) (map[string]string, error) {
	reader := typed.NewReader(r)
	m, err := readHeaders(reader)
	reader.Release()

	return m, err
}

func ReadHeaders ( r io . Reader ) ( map [ string ] string , error ) { reader := typed . NewReader ( r ) m , err := readHeaders ( reader ) reader . Release ( ) return m , err }

// ReadHeaders reads key-value pairs encoded using WriteHeaders.

ReadHeaders reads key - value pairs encoded using WriteHeaders .


func NewTCPRawRelay(dests []string) (Relay, error) {
	return newTCPRelay(dests, func(_ bool, src, dst net.Conn) {
		io.Copy(src, dst)
	})
}

func NewTCPRawRelay ( dests [ ] string ) ( Relay , error ) { return newTCPRelay ( dests , func ( _ bool , src , dst net . Conn ) { io . Copy ( src , dst ) } ) }

// NewTCPRawRelay creates a relay that just pipes data from one connection
// to another directly.

NewTCPRawRelay creates a relay that just pipes data from one connection to another directly .


func NewClient(ch *tchannel.Channel, config Configuration, opts *ClientOptions) (*Client, error) {
	client := &Client{tchan: ch, quit: make(chan struct{})}
	if opts != nil {
		client.opts = *opts
	}
	if client.opts.Timeout == 0 {
		client.opts.Timeout = 3 * time.Second
	}
	if client.opts.TimeoutPerAttempt == 0 {
		client.opts.TimeoutPerAttempt = time.Second
	}
	if client.opts.Handler == nil {
		client.opts.Handler = nullHandler{}
	}
	if client.opts.TimeSleep == nil {
		client.opts.TimeSleep = time.Sleep
	}

	if err := parseConfig(&config); err != nil {
		return nil, err
	}

	// Add the given initial nodes as peers.
	for _, node := range config.InitialNodes {
		addPeer(ch, node)
	}

	client.jsonClient = tjson.NewClient(ch, hyperbahnServiceName, nil)
	thriftClient := tthrift.NewClient(ch, hyperbahnServiceName, nil)
	client.hyperbahnClient = htypes.NewTChanHyperbahnClient(thriftClient)

	return client, nil
}

// NewClient creates a new Hyperbahn client using the given channel.
// config is the environment-specific configuration for Hyperbahn such as the list of initial nodes.
// opts are optional, and are used to customize the client.

NewClient creates a new Hyperbahn client using the given channel . config is the environment - specific configuration for Hyperbahn such as the list of initial nodes . opts are optional and are used to customize the client .


func (c *Client) Advertise(otherServices ...tchannel.Registrar) error {
	c.getServiceNames(otherServices)

	if err := c.initialAdvertise(); err != nil {
		return err
	}

	c.opts.Handler.On(Advertised)
	go c.advertiseLoop()
	return nil
}

func ( c * Client ) Advertise ( otherServices ... tchannel . Registrar ) error { c . getServiceNames ( otherServices ) if err := c . initialAdvertise ( ) ; err != nil { return err } c . opts . Handler . On ( Advertised ) go c . advertiseLoop ( ) return nil }

// Advertise advertises the service with Hyperbahn, and returns any errors on initial advertisement.
// Advertise can register multiple services hosted on the same endpoint.
// If the advertisement succeeds, a goroutine is started to re-advertise periodically.

Advertise advertises the service with Hyperbahn and returns any errors on initial advertisement . Advertise can register multiple services hosted on the same endpoint . If the advertisement succeeds a goroutine is started to re - advertise periodically .


func (h *handler) Handle(tctx context.Context, call *tchannel.InboundCall) error {
	var headers map[string]string
	if err := tchannel.NewArgReader(call.Arg2Reader()).ReadJSON(&headers); err != nil {
		return fmt.Errorf("arg2 read failed: %v", err)
	}
	tctx = tchannel.ExtractInboundSpan(tctx, call, headers, h.tracer())
	ctx := WithHeaders(tctx, headers)

	var arg3 reflect.Value
	var callArg reflect.Value
	if h.isArgMap {
		arg3 = reflect.New(h.argType)
		// New returns a pointer, but the method accepts the map directly.
		callArg = arg3.Elem()
	} else {
		arg3 = reflect.New(h.argType.Elem())
		callArg = arg3
	}
	if err := tchannel.NewArgReader(call.Arg3Reader()).ReadJSON(arg3.Interface()); err != nil {
		return fmt.Errorf("arg3 read failed: %v", err)
	}

	args := []reflect.Value{reflect.ValueOf(ctx), callArg}
	results := h.handler.Call(args)

	res := results[0].Interface()
	err := results[1].Interface()
	// If an error was returned, we create an error arg3 to respond with.
	if err != nil {
		// TODO(prashantv): More consistent error handling between json/raw/thrift..
		if serr, ok := err.(tchannel.SystemError); ok {
			return call.Response().SendSystemError(serr)
		}

		call.Response().SetApplicationError()
		// TODO(prashant): Allow client to customize the error in more ways.
		res = struct {
			Type    string `json:"type"`
			Message string `json:"message"`
		}{
			Type:    "error",
			Message: err.(error).Error(),
		}
	}

	if err := tchannel.NewArgWriter(call.Response().Arg2Writer()).WriteJSON(ctx.ResponseHeaders()); err != nil {
		return err
	}

	return tchannel.NewArgWriter(call.Response().Arg3Writer()).WriteJSON(res)
}

// Handle deserializes the JSON arguments and calls the underlying handler.

Handle deserializes the JSON arguments and calls the underlying handler .


func (s *Server) Start() error {
	if s.HostPort == "" {
		s.HostPort = ":" + common.DefaultServerPort
	}
	channelOpts := &tchannel.ChannelOptions{
		Tracer: s.Tracer,
	}
	ch, err := tchannel.NewChannel(common.DefaultServiceName, channelOpts)
	if err != nil {
		return err
	}

	if err := ch.ListenAndServe(s.HostPort); err != nil {
		return err
	}
	s.HostPort = ch.PeerInfo().HostPort // override in case it was ":0"
	log.Printf("Started tchannel server at %s\n", s.HostPort)
	s.Ch = ch
	return nil
}

func
(
s
*
Server
)
Start
(
)
error
{
if
s
.
HostPort
==
"
"
{
s
.
HostPort
=
"
"
+
common
.
DefaultServerPort
}
channelOpts
:=
&
tchannel
.
ChannelOptions
{
Tracer
:
s
.
Tracer
,
}
ch
,
err
:=
tchannel
.
NewChannel
(
common
.
DefaultServiceName
,
channelOpts
)
if
err
!=
{
return
err
}
if
err
:=
ch
.
ListenAndServe
(
s
.
HostPort
)
;
err
!=
{
return
err
}
s
.
HostPort
=
ch
.
PeerInfo
(
)
.
HostPort
// override in case it was ":0"
log
.
Printf
(
"
\n
"
,
s
.
HostPort
)
s
.
Ch
=
ch
return
}

// Start starts the test server called by the Client and other upstream servers.

Start starts the test server called by the Client and other upstream servers .


func (s *Server) Port() string {
	hostPortSplit := strings.Split(s.HostPort, ":")
	port := hostPortSplit[len(hostPortSplit)-1]
	return port
}

func ( s * Server ) Port ( ) string { hostPortSplit := strings . Split ( s . HostPort , " " ) port := hostPortSplit [ len ( hostPortSplit ) - 1 ] return port }

// Port returns the actual port the server listens to


func (l *PeerList) SetStrategy(sc ScoreCalculator) {
	l.Lock()
	defer l.Unlock()

	l.scoreCalculator = sc
	for _, ps := range l.peersByHostPort {
		newScore := l.scoreCalculator.GetScore(ps.Peer)
		l.updatePeer(ps, newScore)
	}
}

func ( l * PeerList ) SetStrategy ( sc ScoreCalculator ) { l . Lock ( ) defer l . Unlock ( ) l . scoreCalculator = sc for _ , ps := range l . peersByHostPort { newScore := l . scoreCalculator . GetScore ( ps . Peer ) l . updatePeer ( ps , newScore ) } }

// SetStrategy sets customized peer selection strategy.

SetStrategy sets customized peer selection strategy .


func (l *PeerList) Add(hostPort string) *Peer {
	if ps, ok := l.exists(hostPort); ok {
		return ps.Peer
	}
	l.Lock()
	defer l.Unlock()

	if p, ok := l.peersByHostPort[hostPort]; ok {
		return p.Peer
	}

	p := l.parent.Add(hostPort)
	p.addSC()
	ps := newPeerScore(p, l.scoreCalculator.GetScore(p))

	l.peersByHostPort[hostPort] = ps
	l.peerHeap.addPeer(ps)
	return p
}

func ( l * PeerList ) Add ( hostPort string ) * Peer { if ps , ok := l . exists ( hostPort ) ; ok { return ps . Peer } l . Lock ( ) defer l . Unlock ( ) if p , ok := l . peersByHostPort [ hostPort ] ; ok { return p . Peer } p := l . parent . Add ( hostPort ) p . addSC ( ) ps := newPeerScore ( p , l . scoreCalculator . GetScore ( p ) ) l . peersByHostPort [ hostPort ] = ps l . peerHeap . addPeer ( ps ) return p }

// Add adds a peer to the list if it does not exist, or returns any existing peer.

Add adds a peer to the list if it does not exist or returns any existing peer .


func (l *PeerList) GetNew(prevSelected map[string]struct{}) (*Peer, error) {
	l.Lock()
	defer l.Unlock()
	if l.peerHeap.Len() == 0 {
		return nil, ErrNoPeers
	}

	// Select a peer, avoiding previously selected peers. If all peers have been previously
	// selected, then it's OK to repick them.
	peer := l.choosePeer(prevSelected, true /* avoidHost */)
	if peer == nil {
		peer = l.choosePeer(prevSelected, false /* avoidHost */)
	}
	if peer == nil {
		return nil, ErrNoNewPeers
	}
	return peer, nil
}

// GetNew returns a new, previously unselected peer from the peer list, or nil,
// if no new unselected peer can be found.

GetNew returns a new previously unselected peer from the peer list or nil if no new unselected peer can be found .


func (l *PeerList) Get(prevSelected map[string]struct{}) (*Peer, error) {
	peer, err := l.GetNew(prevSelected)
	if err == ErrNoNewPeers {
		l.Lock()
		peer = l.choosePeer(nil, false /* avoidHost */)
		l.Unlock()
	} else if err != nil {
		return nil, err
	}
	if peer == nil {
		return nil, ErrNoPeers
	}
	return peer, nil
}

func
(
l
*
PeerList
)
Get
(
prevSelected
map
[
string
]
struct
{
}
)
(
*
Peer
,
error
)
{
peer
,
err
:=
l
.
GetNew
(
prevSelected
)
if
err
==
ErrNoNewPeers
{
l
.
Lock
(
)
peer
=
l
.
choosePeer
(
,
false
/* avoidHost */
)
l
.
Unlock
(
)
}
else
if
err
!=
{
return
,
err
}
if
peer
==
{
return
,
ErrNoPeers
}
return
peer
,
}

// Get returns a peer from the peer list, or nil if none can be found,
// will avoid previously selected peers if possible.

Get returns a peer from the peer list or nil if none can be found will avoid previously selected peers if possible .


func (l *PeerList) Remove(hostPort string) error {
	l.Lock()
	defer l.Unlock()

	p, ok := l.peersByHostPort[hostPort]
	if !ok {
		return ErrPeerNotFound
	}

	p.delSC()
	delete(l.peersByHostPort, hostPort)
	l.peerHeap.removePeer(p)

	return nil
}

func ( l * PeerList ) Remove ( hostPort string ) error { l . Lock ( ) defer l . Unlock ( ) p , ok := l . peersByHostPort [ hostPort ] if ! ok { return ErrPeerNotFound } p . delSC ( ) delete ( l . peersByHostPort , hostPort ) l . peerHeap . removePeer ( p ) return nil }

// Remove removes a peer from the peer list. It returns an error if the peer cannot be found.
// Remove does not affect connections to the peer in any way.

Remove removes a peer from the peer list . It returns an error if the peer cannot be found . Remove does not affect connections to the peer in any way .


func (l *PeerList) Copy() map[string]*Peer {
	l.RLock()
	defer l.RUnlock()

	listCopy := make(map[string]*Peer)
	for k, v := range l.peersByHostPort {
		listCopy[k] = v.Peer
	}
	return listCopy
}

func ( l * PeerList ) Copy ( ) map [ string ] * Peer { l . RLock ( ) defer l . RUnlock ( ) listCopy := make ( map [ string ] * Peer ) for k , v := range l . peersByHostPort { listCopy [ k ] = v . Peer } return listCopy }

// Copy returns a copy of the PeerList as a map from hostPort to peer.

Copy returns a copy of the PeerList as a map from hostPort to peer .


func (l *PeerList) Len() int {
	l.RLock()
	defer l.RUnlock()
	return l.peerHeap.Len()
}

func ( l * PeerList ) Len ( ) int { l . RLock ( ) defer l . RUnlock ( ) return l . peerHeap . Len ( ) }

// Len returns the length of the PeerList.

Len returns the length of the PeerList .


func (l *PeerList) exists(hostPort string) (*peerScore, bool) {
	l.RLock()
	ps, ok := l.peersByHostPort[hostPort]
	l.RUnlock()

	return ps, ok
}

func ( l * PeerList ) exists ( hostPort string ) ( * peerScore , bool ) { l . RLock ( ) ps , ok := l . peersByHostPort [ hostPort ] l . RUnlock ( ) return ps , ok }

// exists checks if a hostport exists in the peer list.

exists checks if a hostport exists in the peer list .


func (l *PeerList) getPeerScore(hostPort string) (*peerScore, uint64, bool) {
	ps, ok := l.peersByHostPort[hostPort]
	if !ok {
		return nil, 0, false
	}
	return ps, ps.score, ok
}

func ( l * PeerList ) getPeerScore ( hostPort string ) ( * peerScore , uint64 , bool ) { ps , ok := l . peersByHostPort [ hostPort ] if ! ok { return nil , 0 , false } return ps , ps . score , ok }

// getPeerScore is called to find the peer and its score from a host port key.
// Note that at least a Read lock must be held to call this function.

getPeerScore is called to find the peer and its score from a host port key . Note that at least a Read lock must be held to call this function .


func (l *PeerList) onPeerChange(p *Peer) {
	l.RLock()
	ps, psScore, ok := l.getPeerScore(p.hostPort)
	sc := l.scoreCalculator
	l.RUnlock()
	if !ok {
		return
	}

	newScore := sc.GetScore(ps.Peer)
	if newScore == psScore {
		return
	}

	l.Lock()
	l.updatePeer(ps, newScore)
	l.Unlock()
}

func ( l * PeerList ) onPeerChange ( p * Peer ) { l . RLock ( ) ps , psScore , ok := l . getPeerScore ( p . hostPort ) sc := l . scoreCalculator l . RUnlock ( ) if ! ok { return } newScore := sc . GetScore ( ps . Peer ) if newScore == psScore { return } l . Lock ( ) l . updatePeer ( ps , newScore ) l . Unlock ( ) }

// onPeerChange is called when there is a change that may cause the peer's score to change.
// The new score is calculated, and the peer heap is updated with the new score if the score changes.

onPeerChange is called when there is a change that may cause the peer s score to change . The new score is calculated and the peer heap is updated with the new score if the score changes .


func (l *PeerList) updatePeer(ps *peerScore, newScore uint64) {
	if ps.score == newScore {
		return
	}

	ps.score = newScore
	l.peerHeap.updatePeer(ps)
}

func ( l * PeerList ) updatePeer ( ps * peerScore , newScore uint64 ) { if ps . score == newScore { return } ps . score = newScore l . peerHeap . updatePeer ( ps ) }

// updatePeer is called to update the score of the peer given the existing score.
// Note that a Write lock must be held to call this function.

updatePeer is called to update the score of the peer given the existing score . Note that a Write lock must be held to call this function .


func (p *Peer) getConn(i int) *Connection {
	inboundLen := len(p.inboundConnections)
	if i < inboundLen {
		return p.inboundConnections[i]
	}

	return p.outboundConnections[i-inboundLen]
}

func ( p * Peer ) getConn ( i int ) * Connection { inboundLen := len ( p . inboundConnections ) if i < inboundLen { return p . inboundConnections [ i ] } return p . outboundConnections [ i - inboundLen ] }

// getConn treats inbound and outbound connections as a single virtual list
// that can be indexed. The peer must be read-locked.

getConn treats inbound and outbound connections as a single virtual list that can be indexed . The peer must be read - locked .


func (p *Peer) GetConnection(ctx context.Context) (*Connection, error) {
	if activeConn, ok := p.getActiveConn(); ok {
		return activeConn, nil
	}

	// Lock here to restrict new connection creation attempts to one goroutine
	p.newConnLock.Lock()
	defer p.newConnLock.Unlock()

	// Check active connections again in case someone else got ahead of us.
	if activeConn, ok := p.getActiveConn(); ok {
		return activeConn, nil
	}

	// No active connections, make a new outgoing connection.
	return p.Connect(ctx)
}

// GetConnection returns an active connection to this peer. If no active connections
// are found, it will create a new outbound connection and return it.

GetConnection returns an active connection to this peer . If no active connections are found it will create a new outbound connection and return it .


func (p *Peer) getConnectionRelay(timeout time.Duration) (*Connection, error) {
	if conn, ok := p.getActiveConn(); ok {
		return conn, nil
	}

	// Lock here to restrict new connection creation attempts to one goroutine
	p.newConnLock.Lock()
	defer p.newConnLock.Unlock()

	// Check active connections again in case someone else got ahead of us.
	if activeConn, ok := p.getActiveConn(); ok {
		return activeConn, nil
	}

	// When the relay creates outbound connections, we don't want those services
	// to ever connect back to us and send us traffic. We hide the host:port
	// so that service instances on remote machines don't try to connect back
	// and don't try to send Hyperbahn traffic on this connection.
	ctx, cancel := NewContextBuilder(timeout).HideListeningOnOutbound().Build()
	defer cancel()

	return p.Connect(ctx)
}

// getConnectionRelay gets a connection, and uses the given timeout to lazily
// create a context if a new connection is required.

getConnectionRelay gets a connection and uses the given timeout to lazily create a context if a new connection is required .


func (p *Peer) canRemove() bool {
	p.RLock()
	count := len(p.inboundConnections) + len(p.outboundConnections) + int(p.scCount)
	p.RUnlock()
	return count == 0
}

func ( p * Peer ) canRemove ( ) bool { p . RLock ( ) count := len ( p . inboundConnections ) + len ( p . outboundConnections ) + int ( p . scCount ) p . RUnlock ( ) return count == 0 }

// canRemove returns whether this peer can be safely removed from the root peer list.

canRemove returns whether this peer can be safely removed from the root peer list .


func (p *Peer) addConnection(c *Connection, direction connectionDirection) error {
	conns := p.connectionsFor(direction)

	if c.readState() != connectionActive {
		return ErrInvalidConnectionState
	}

	p.Lock()
	*conns = append(*conns, c)
	p.Unlock()

	// Inform third parties that a peer gained a connection.
	p.onStatusChanged(p)

	return nil
}

// addConnection adds an active connection to the peer's connection list.
// If a connection is not active, returns ErrInvalidConnectionState.

addConnection adds an active connection to the peer s connection list . If a connection is not active returns ErrInvalidConnectionState .


func (p *Peer) removeConnection(connsPtr *[]*Connection, changed *Connection) bool {
	conns := *connsPtr
	for i, c := range conns {
		if c == changed {
			// Remove the connection by moving the last item forward, and slicing the list.
			last := len(conns) - 1
			conns[i], conns[last] = conns[last], nil
			*connsPtr = conns[:last]
			return true
		}
	}

	return false
}

// removeConnection will check remove the connection if it exists on connsPtr
// and returns whether it removed the connection.

removeConnection will check remove the connection if it exists on connsPtr and returns whether it removed the connection .


func (p *Peer) connectionCloseStateChange(changed *Connection) {
	if changed.IsActive() {
		return
	}

	p.Lock()
	found := p.removeConnection(&p.inboundConnections, changed)
	if !found {
		found = p.removeConnection(&p.outboundConnections, changed)
	}
	p.Unlock()

	if found {
		p.onClosedConnRemoved(p)
		// Inform third parties that a peer lost a connection.
		p.onStatusChanged(p)
	}
}

// connectionStateChanged is called when one of the peers' connections states changes.
// All non-active connections are removed from the peer. The connection will
// still be tracked by the channel until it's completely closed.

connectionStateChanged is called when one of the peers connections states changes . All non - active connections are removed from the peer . The connection will still be tracked by the channel until it s completely closed .


func (p *Peer) Connect(ctx context.Context) (*Connection, error) {
	return p.channel.Connect(ctx, p.hostPort)
}

func ( p * Peer ) Connect ( ctx context . Context ) ( * Connection , error ) { return p . channel . Connect ( ctx , p . hostPort ) }

// Connect adds a new outbound connection to the peer.

Connect adds a new outbound connection to the peer .


func (p *Peer) BeginCall(ctx context.Context, serviceName, methodName string, callOptions *CallOptions) (*OutboundCall, error) {
	if callOptions == nil {
		callOptions = defaultCallOptions
	}
	callOptions.RequestState.AddSelectedPeer(p.HostPort())

	if err := validateCall(ctx, serviceName, methodName, callOptions); err != nil {
		return nil, err
	}

	conn, err := p.GetConnection(ctx)
	if err != nil {
		return nil, err
	}

	call, err := conn.beginCall(ctx, serviceName, methodName, callOptions)
	if err != nil {
		return nil, err
	}

	return call, err
}

func ( p * Peer ) BeginCall ( ctx context . Context , serviceName , methodName string , callOptions * CallOptions ) ( * OutboundCall , error ) { if callOptions == nil { callOptions = defaultCallOptions } callOptions . RequestState . AddSelectedPeer ( p . HostPort ( ) ) if err := validateCall ( ctx , serviceName , methodName , callOptions ) ; err != nil { return nil , err } conn , err := p . GetConnection ( ctx ) if err != nil { return nil , err } call , err := conn . beginCall ( ctx , serviceName , methodName , callOptions ) if err != nil { return nil , err } return call , err }

// BeginCall starts a new call to this specific peer, returning an OutboundCall that can
// be used to write the arguments of the call.

BeginCall starts a new call to this specific peer returning an OutboundCall that can be used to write the arguments of the call .


func (p *Peer) NumConnections() (inbound int, outbound int) {
	p.RLock()
	inbound = len(p.inboundConnections)
	outbound = len(p.outboundConnections)
	p.RUnlock()
	return inbound, outbound
}

func ( p * Peer ) NumConnections ( ) ( inbound int , outbound int ) { p . RLock ( ) inbound = len ( p . inboundConnections ) outbound = len ( p . outboundConnections ) p . RUnlock ( ) return inbound , outbound }

// NumConnections returns the number of inbound and outbound connections for this peer.

NumConnections returns the number of inbound and outbound connections for this peer .


func (p *Peer) NumPendingOutbound() int {
	count := 0
	p.RLock()
	for _, c := range p.outboundConnections {
		count += c.outbound.count()
	}

	for _, c := range p.inboundConnections {
		count += c.outbound.count()
	}
	p.RUnlock()
	return count
}

func ( p * Peer ) NumPendingOutbound ( ) int { count := 0 p . RLock ( ) for _ , c := range p . outboundConnections { count += c . outbound . count ( ) } for _ , c := range p . inboundConnections { count += c . outbound . count ( ) } p . RUnlock ( ) return count }

// NumPendingOutbound returns the number of pending outbound calls.

NumPendingOutbound returns the number of pending outbound calls .


func isEphemeralHostPort(hostPort string) bool {
	return hostPort == "" || hostPort == ephemeralHostPort || strings.HasSuffix(hostPort, ":0")
}

func isEphemeralHostPort ( hostPort string ) bool { return hostPort == " " || hostPort == ephemeralHostPort || strings . HasSuffix ( hostPort , " " ) }

// isEphemeralHostPort returns if hostPort is the default ephemeral hostPort.

isEphemeralHostPort returns if hostPort is the default ephemeral hostPort .


func (h *kvHandler) Get(ctx thrift.Context, key string) (string, error) {
	if err := isValidKey(key); err != nil {
		return "", err
	}

	h.RLock()
	defer h.RUnlock()

	if val, ok := h.vals[key]; ok {
		return val, nil
	}

	return "", &keyvalue.KeyNotFound{Key: key}
}

func ( h * kvHandler ) Get ( ctx thrift . Context , key string ) ( string , error ) { if err := isValidKey ( key ) ; err != nil { return " " , err } h . RLock ( ) defer h . RUnlock ( ) if val , ok := h . vals [ key ] ; ok { return val , nil } return " " , & keyvalue . KeyNotFound { Key : key } }

// Get returns the value stored for the given key.

Get returns the value stored for the given key .


func (h *kvHandler) Set(ctx thrift.Context, key, value string) error {
	if err := isValidKey(key); err != nil {
		return err
	}

	h.Lock()
	defer h.Unlock()

	h.vals[key] = value
	// Example of how to use response headers. Normally, these values should be passed via result structs.
	ctx.SetResponseHeaders(map[string]string{"count": fmt.Sprint(len(h.vals))})
	return nil
}


func (h *kvHandler) ClearAll(ctx thrift.Context) error {
	if !isAdmin(ctx) {
		return &keyvalue.NotAuthorized{}
	}

	h.Lock()
	defer h.Unlock()

	h.vals = make(map[string]string)
	return nil
}

func ( h * kvHandler ) ClearAll ( ctx thrift . Context ) error { if ! isAdmin ( ctx ) { return & keyvalue . NotAuthorized { } } h . Lock ( ) defer h . Unlock ( ) h . vals = make ( map [ string ] string ) return nil }


func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
	if serviceName == "" {
		return nil, ErrNoServiceName
	}

	if opts == nil {
		opts = &ChannelOptions{}
	}

	processName := opts.ProcessName
	if processName == "" {
		processName = fmt.Sprintf("%s[%d]", filepath.Base(os.Args[0]), os.Getpid())
	}

	logger := opts.Logger
	if logger == nil {
		logger = NullLogger
	}

	statsReporter := opts.StatsReporter
	if statsReporter == nil {
		statsReporter = NullStatsReporter
	}

	timeNow := opts.TimeNow
	if timeNow == nil {
		timeNow = time.Now
	}

	timeTicker := opts.TimeTicker
	if timeTicker == nil {
		timeTicker = time.NewTicker
	}

	chID := _nextChID.Inc()
	logger = logger.WithFields(
		LogField{"serviceName", serviceName},
		LogField{"process", processName},
		LogField{"chID", chID},
	)

	if err := opts.validateIdleCheck(); err != nil {
		return nil, err
	}

	ch := &Channel{
		channelConnectionCommon: channelConnectionCommon{
			log:           logger,
			relayLocal:    toStringSet(opts.RelayLocalHandlers),
			statsReporter: statsReporter,
			subChannels:   &subChannelMap{},
			timeNow:       timeNow,
			timeTicker:    timeTicker,
			tracer:        opts.Tracer,
		},
		chID:              chID,
		connectionOptions: opts.DefaultConnectionOptions.withDefaults(),
		relayHost:         opts.RelayHost,
		relayMaxTimeout:   validateRelayMaxTimeout(opts.RelayMaxTimeout, logger),
		relayTimerVerify:  opts.RelayTimerVerification,
		closed:            make(chan struct{}),
	}
	ch.peers = newRootPeerList(ch, opts.OnPeerStatusChanged).newChild()

	if opts.Handler != nil {
		ch.handler = opts.Handler
	} else {
		ch.handler = channelHandler{ch}
	}

	ch.mutable.peerInfo = LocalPeerInfo{
		PeerInfo: PeerInfo{
			ProcessName: processName,
			HostPort:    ephemeralHostPort,
			IsEphemeral: true,
			Version: PeerVersion{
				Language:        "go",
				LanguageVersion: strings.TrimPrefix(runtime.Version(), "go"),
				TChannelVersion: VersionInfo,
			},
		},
		ServiceName: serviceName,
	}
	ch.mutable.state = ChannelClient
	ch.mutable.conns = make(map[uint32]*Connection)
	ch.createCommonStats()

	// Register internal unless the root handler has been overridden, since
	// Register will panic.
	if opts.Handler == nil {
		ch.registerInternal()
	}

	registerNewChannel(ch)

	if opts.RelayHost != nil {
		opts.RelayHost.SetChannel(ch)
	}

	// Start the idle connection timer.
	ch.mutable.idleSweep = startIdleSweep(ch, opts)

	return ch, nil
}

// NewChannel creates a new Channel.  The new channel can be used to send outbound requests
// to peers, but will not listen or handling incoming requests until one of ListenAndServe
// or Serve is called. The local service name should be passed to serviceName.

NewChannel creates a new Channel . The new channel can be used to send outbound requests to peers but will not listen or handling incoming requests until one of ListenAndServe or Serve is called . The local service name should be passed to serviceName .


func (ch *Channel) Serve(l net.Listener) error {
	mutable := &ch.mutable
	mutable.Lock()
	defer mutable.Unlock()

	if mutable.l != nil {
		return errAlreadyListening
	}
	mutable.l = tnet.Wrap(l)

	if mutable.state != ChannelClient {
		return errInvalidStateForOp
	}
	mutable.state = ChannelListening

	mutable.peerInfo.HostPort = l.Addr().String()
	mutable.peerInfo.IsEphemeral = false
	ch.log = ch.log.WithFields(LogField{"hostPort", mutable.peerInfo.HostPort})
	ch.log.Info("Channel is listening.")
	go ch.serve()
	return nil
}

func ( ch * Channel ) Serve ( l net . Listener ) error { mutable := & ch . mutable mutable . Lock ( ) defer mutable . Unlock ( ) if mutable . l != nil { return errAlreadyListening } mutable . l = tnet . Wrap ( l ) if mutable . state != ChannelClient { return errInvalidStateForOp } mutable . state = ChannelListening mutable . peerInfo . HostPort = l . Addr ( ) . String ( ) mutable . peerInfo . IsEphemeral = false ch . log = ch . log . WithFields ( LogField { " " , mutable . peerInfo . HostPort } ) ch . log . Info ( " " ) go ch . serve ( ) return nil }

// Serve serves incoming requests using the provided listener.
// The local peer info is set synchronously, but the actual socket listening is done in
// a separate goroutine.

Serve serves incoming requests using the provided listener . The local peer info is set synchronously but the actual socket listening is done in a separate goroutine .


func (ch *Channel) ListenAndServe(hostPort string) error {
	mutable := &ch.mutable
	mutable.RLock()

	if mutable.l != nil {
		mutable.RUnlock()
		return errAlreadyListening
	}

	l, err := net.Listen("tcp", hostPort)
	if err != nil {
		mutable.RUnlock()
		return err
	}

	mutable.RUnlock()
	return ch.Serve(l)
}

func ( ch * Channel ) ListenAndServe ( hostPort string ) error { mutable := & ch . mutable mutable . RLock ( ) if mutable . l != nil { mutable . RUnlock ( ) return errAlreadyListening } l , err := net . Listen ( " " , hostPort ) if err != nil { mutable . RUnlock ( ) return err } mutable . RUnlock ( ) return ch . Serve ( l ) }

// ListenAndServe listens on the given address and serves incoming requests.
// The port may be 0, in which case the channel will use an OS assigned port
// This method does not block as the handling of connections is done in a goroutine.

ListenAndServe listens on the given address and serves incoming requests . The port may be 0 in which case the channel will use an OS assigned port This method does not block as the handling of connections is done in a goroutine .


func (ch *Channel) Register(h Handler, methodName string) {
	if _, ok := ch.handler.(channelHandler); !ok {
		panic("can't register handler when channel configured with alternate root handler")
	}
	ch.GetSubChannel(ch.PeerInfo().ServiceName).Register(h, methodName)
}

func ( ch * Channel ) Register ( h Handler , methodName string ) { if _ , ok := ch . handler . ( channelHandler ) ; ! ok { panic ( " " ) } ch . GetSubChannel ( ch . PeerInfo ( ) . ServiceName ) . Register ( h , methodName ) }

// Register registers a handler for a method.
//
// The handler is registered with the service name used when the Channel was
// created. To register a handler with a different service name, obtain a
// SubChannel for that service with GetSubChannel, and Register a handler
// under that. You may also use SetHandler on a SubChannel to set up a
// catch-all Handler for that service. See the docs for SetHandler for more
// information.
//
// Register panics if the channel was constructed with an alternate root
// handler.

Register registers a handler for a method . The handler is registered with the service name used when the Channel was created . To register a handler with a different service name obtain a SubChannel for that service with GetSubChannel and Register a handler under that . You may also use SetHandler on a SubChannel to set up a catch - all Handler for that service . See the docs for SetHandler for more information . Register panics if the channel was constructed with an alternate root handler .


func (ch *Channel) PeerInfo() LocalPeerInfo {
	ch.mutable.RLock()
	peerInfo := ch.mutable.peerInfo
	ch.mutable.RUnlock()

	return peerInfo
}

func ( ch * Channel ) PeerInfo ( ) LocalPeerInfo { ch . mutable . RLock ( ) peerInfo := ch . mutable . peerInfo ch . mutable . RUnlock ( ) return peerInfo }

// PeerInfo returns the current peer info for the channel


func (ch *Channel) GetSubChannel(serviceName string, opts ...SubChannelOption) *SubChannel {
	sub, added := ch.subChannels.getOrAdd(serviceName, ch)
	if added {
		for _, opt := range opts {
			opt(sub)
		}
	}
	return sub
}

func ( ch * Channel ) GetSubChannel ( serviceName string , opts ... SubChannelOption ) * SubChannel { sub , added := ch . subChannels . getOrAdd ( serviceName , ch ) if added { for _ , opt := range opts { opt ( sub ) } } return sub }

// GetSubChannel returns a SubChannel for the given service name. If the subchannel does not
// exist, it is created.

GetSubChannel returns a SubChannel for the given service name . If the subchannel does not exist it is created .


func (ch *Channel) serve() {
	acceptBackoff := 0 * time.Millisecond

	for {
		netConn, err := ch.mutable.l.Accept()
		if err != nil {
			// Backoff from new accepts if this is a temporary error
			if ne, ok := err.(net.Error); ok && ne.Temporary() {
				if acceptBackoff == 0 {
					acceptBackoff = 5 * time.Millisecond
				} else {
					acceptBackoff *= 2
				}
				if max := 1 * time.Second; acceptBackoff > max {
					acceptBackoff = max
				}
				ch.log.WithFields(
					ErrField(err),
					LogField{"backoff", acceptBackoff},
				).Warn("Accept error, will wait and retry.")
				time.Sleep(acceptBackoff)
				continue
			} else {
				// Only log an error if this didn't happen due to a Close.
				if ch.State() >= ChannelStartClose {
					return
				}
				ch.log.WithFields(ErrField(err)).Fatal("Unrecoverable accept error, closing server.")
				return
			}
		}

		acceptBackoff = 0

		// Perform the connection handshake in a background goroutine.
		go func() {
			// Register the connection in the peer once the channel is set up.
			events := connectionEvents{
				OnActive:           ch.inboundConnectionActive,
				OnCloseStateChange: ch.connectionCloseStateChange,
				OnExchangeUpdated:  ch.exchangeUpdated,
			}
			if _, err := ch.inboundHandshake(context.Background(), netConn, events); err != nil {
				netConn.Close()
			}
		}()
	}
}

// serve runs the listener to accept and manage new incoming connections, blocking
// until the channel is closed.

serve runs the listener to accept and manage new incoming connections blocking until the channel is closed .


func (ch *Channel) Ping(ctx context.Context, hostPort string) error {
	peer := ch.RootPeers().GetOrAdd(hostPort)
	conn, err := peer.GetConnection(ctx)
	if err != nil {
		return err
	}

	return conn.ping(ctx)
}

func ( ch * Channel ) Ping ( ctx context . Context , hostPort string ) error { peer := ch . RootPeers ( ) . GetOrAdd ( hostPort ) conn , err := peer . GetConnection ( ctx ) if err != nil { return err } return conn . ping ( ctx ) }

// Ping sends a ping message to the given hostPort and waits for a response.

Ping sends a ping message to the given hostPort and waits for a response .


func (ch *Channel) StatsTags() map[string]string {
	m := make(map[string]string)
	for k, v := range ch.commonStatsTags {
		m[k] = v
	}
	return m
}

func ( ch * Channel ) StatsTags ( ) map [ string ] string { m := make ( map [ string ] string ) for k , v := range ch . commonStatsTags { m [ k ] = v } return m }

// StatsTags returns the common tags that should be used when reporting stats.
// It returns a new map for each call.

StatsTags returns the common tags that should be used when reporting stats . It returns a new map for each call .


func (ch *Channel) Connect(ctx context.Context, hostPort string) (*Connection, error) {
	switch state := ch.State(); state {
	case ChannelClient, ChannelListening:
		break
	default:
		ch.log.Debugf("Connect rejecting new connection as state is %v", state)
		return nil, errInvalidStateForOp
	}

	// The context timeout applies to the whole call, but users may want a lower
	// connect timeout (e.g. for streams).
	if params := getTChannelParams(ctx); params != nil && params.connectTimeout > 0 {
		var cancel context.CancelFunc
		ctx, cancel = context.WithTimeout(ctx, params.connectTimeout)
		defer cancel()
	}

	events := connectionEvents{
		OnActive:           ch.outboundConnectionActive,
		OnCloseStateChange: ch.connectionCloseStateChange,
		OnExchangeUpdated:  ch.exchangeUpdated,
	}

	if err := ctx.Err(); err != nil {
		return nil, GetContextError(err)
	}

	timeout := getTimeout(ctx)
	tcpConn, err := dialContext(ctx, hostPort)
	if err != nil {
		if ne, ok := err.(net.Error); ok && ne.Timeout() {
			ch.log.WithFields(
				LogField{"remoteHostPort", hostPort},
				LogField{"timeout", timeout},
			).Info("Outbound net.Dial timed out.")
			err = ErrTimeout
		} else if ctx.Err() == context.Canceled {
			ch.log.WithFields(
				LogField{"remoteHostPort", hostPort},
			).Info("Outbound net.Dial was cancelled.")
			err = GetContextError(ErrRequestCancelled)
		} else {
			ch.log.WithFields(
				ErrField(err),
				LogField{"remoteHostPort", hostPort},
			).Info("Outbound net.Dial failed.")
		}
		return nil, err
	}

	conn, err := ch.outboundHandshake(ctx, tcpConn, hostPort, events)
	if conn != nil {
		// It's possible that the connection we just created responds with a host:port
		// that is not what we tried to connect to. E.g., we may have connected to
		// 127.0.0.1:1234, but the returned host:port may be 10.0.0.1:1234.
		// In this case, the connection won't be added to 127.0.0.1:1234 peer
		// and so future calls to that peer may end up creating new connections. To
		// avoid this issue, and to avoid clients being aware of any TCP relays, we
		// add the connection to the intended peer.
		if hostPort != conn.remotePeerInfo.HostPort {
			conn.log.Debugf("Outbound connection host:port mismatch, adding to peer %v", conn.remotePeerInfo.HostPort)
			ch.addConnectionToPeer(hostPort, conn, outbound)
		}
	}

	return conn, err
}

// Connect creates a new outbound connection to hostPort.

Connect creates a new outbound connection to hostPort .


func (ch *Channel) exchangeUpdated(c *Connection) {
	if c.remotePeerInfo.HostPort == "" {
		// Hostport is unknown until we get init resp.
		return
	}

	p, ok := ch.RootPeers().Get(c.remotePeerInfo.HostPort)
	if !ok {
		return
	}

	ch.updatePeer(p)
}

// exchangeUpdated updates the peer heap.


func (ch *Channel) updatePeer(p *Peer) {
	ch.peers.onPeerChange(p)
	ch.subChannels.updatePeer(p)
	p.callOnUpdateComplete()
}

func ( ch * Channel ) updatePeer ( p * Peer ) { ch . peers . onPeerChange ( p ) ch . subChannels . updatePeer ( p ) p . callOnUpdateComplete ( ) }

// updatePeer updates the score of the peer and update it's position in heap as well.

updatePeer updates the score of the peer and update it s position in heap as well .


func (ch *Channel) addConnection(c *Connection, direction connectionDirection) bool {
	ch.mutable.Lock()
	defer ch.mutable.Unlock()

	if c.readState() != connectionActive {
		return false
	}

	switch state := ch.mutable.state; state {
	case ChannelClient, ChannelListening:
		break
	default:
		return false
	}

	ch.mutable.conns[c.connID] = c
	return true
}

func ( ch * Channel ) addConnection ( c * Connection , direction connectionDirection ) bool { ch . mutable . Lock ( ) defer ch . mutable . Unlock ( ) if c . readState ( ) != connectionActive { return false } switch state := ch . mutable . state ; state { case ChannelClient , ChannelListening : break default : return false } ch . mutable . conns [ c . connID ] = c return true }

// addConnection adds the connection to the channel's list of connection
// if the channel is in a valid state to accept this connection. It returns
// whether the connection was added.

addConnection adds the connection to the channel s list of connection if the channel is in a valid state to accept this connection . It returns whether the connection was added .


func (ch *Channel) removeClosedConn(c *Connection) {
	if c.readState() != connectionClosed {
		return
	}

	ch.mutable.Lock()
	delete(ch.mutable.conns, c.connID)
	ch.mutable.Unlock()
}

func ( ch * Channel ) removeClosedConn ( c * Connection ) { if c . readState ( ) != connectionClosed { return } ch . mutable . Lock ( ) delete ( ch . mutable . conns , c . connID ) ch . mutable . Unlock ( ) }

// removeClosedConn removes a connection if it's closed.
// Until a connection is fully closed, the channel must keep track of it.

removeClosedConn removes a connection if it s closed . Until a connection is fully closed the channel must keep track of it .


func (ch *Channel) connectionCloseStateChange(c *Connection) {
	ch.removeClosedConn(c)
	if peer, ok := ch.RootPeers().Get(c.remotePeerInfo.HostPort); ok {
		peer.connectionCloseStateChange(c)
		ch.updatePeer(peer)
	}
	if c.outboundHP != "" && c.outboundHP != c.remotePeerInfo.HostPort {
		// Outbound connections may be in multiple peers.
		if peer, ok := ch.RootPeers().Get(c.outboundHP); ok {
			peer.connectionCloseStateChange(c)
			ch.updatePeer(peer)
		}
	}

	chState := ch.State()
	if chState != ChannelStartClose && chState != ChannelInboundClosed {
		return
	}

	ch.mutable.RLock()
	minState := ch.getMinConnectionState()
	ch.mutable.RUnlock()

	var updateTo ChannelState
	if minState >= connectionClosed {
		updateTo = ChannelClosed
	} else if minState >= connectionInboundClosed && chState == ChannelStartClose {
		updateTo = ChannelInboundClosed
	}

	var updatedToState ChannelState
	if updateTo > 0 {
		ch.mutable.Lock()
		// Recheck the state as it's possible another goroutine changed the state
		// from what we expected, and so we might make a stale change.
		if ch.mutable.state == chState {
			ch.mutable.state = updateTo
			updatedToState = updateTo
		}
		ch.mutable.Unlock()
		chState = updateTo
	}

	c.log.Debugf("ConnectionCloseStateChange channel state = %v connection minState = %v",
		chState, minState)

	if updatedToState == ChannelClosed {
		ch.onClosed()
	}
}

// connectionCloseStateChange is called when a connection's close state changes.

connectionCloseStateChange is called when a connection s close state changes .


func (ch *Channel) State() ChannelState {
	ch.mutable.RLock()
	state := ch.mutable.state
	ch.mutable.RUnlock()

	return state
}

func ( ch * Channel ) State ( ) ChannelState { ch . mutable . RLock ( ) state := ch . mutable . state ch . mutable . RUnlock ( ) return state }

// State returns the current channel state.

State returns the current channel state .


func NewReader(reader io.Reader) *Reader {
	r := readerPool.Get().(*Reader)
	r.reader = reader
	r.err = nil
	return r
}

func NewReader ( reader io . Reader ) * Reader { r := readerPool . Get ( ) . ( * Reader ) r . reader = reader r . err = nil return r }

// NewReader returns a reader that reads typed values from the reader.

NewReader returns a reader that reads typed values from the reader .


func (r *Reader) ReadUint16() uint16 {
	if r.err != nil {
		return 0
	}

	buf := r.buf[:2]

	var readN int
	readN, r.err = io.ReadFull(r.reader, buf)
	if readN < 2 {
		return 0
	}
	return binary.BigEndian.Uint16(buf)
}

func ( r * Reader ) ReadUint16 ( ) uint16 { if r . err != nil { return 0 } buf := r . buf [ : 2 ] var readN int readN , r . err = io . ReadFull ( r . reader , buf ) if readN < 2 { return 0 } return binary . BigEndian . Uint16 ( buf ) }


func (r *Reader) ReadString(n int) string {
	if r.err != nil {
		return ""
	}

	var buf []byte
	if n <= maxPoolStringLen {
		buf = r.buf[:n]
	} else {
		buf = make([]byte, n)
	}

	var readN int
	readN, r.err = io.ReadFull(r.reader, buf)
	if readN < n {
		return ""
	}
	s := string(buf)

	return s
}

func ( r * Reader ) ReadString ( n int ) string { if r . err != nil { return " " } var buf [ ] byte if n <= maxPoolStringLen { buf = r . buf [ : n ] } else { buf = make ( [ ] byte , n ) } var readN int readN , r . err = io . ReadFull ( r . reader , buf ) if readN < n { return " " } s := string ( buf ) return s }

// ReadString reads a string of length n.


func (r *Reader) ReadLen16String() string {
	len := r.ReadUint16()
	return r.ReadString(int(len))
}

func ( r * Reader ) ReadLen16String ( ) string { len := r . ReadUint16 ( ) return r . ReadString ( int ( len ) ) }

// ReadLen16String reads a uint16-length prefixed string.

ReadLen16String reads a uint16 - length prefixed string .


func (b *Behavior) Register(ch *tchannel.Channel) {
	b.registerThrift(ch)
	b.registerJSON(ch)
}

func ( b * Behavior ) Register ( ch * tchannel . Channel ) { b . registerThrift ( ch ) b . registerJSON ( ch ) }

// Register function adds JSON and Thrift handlers to the server channel ch


func (b *Behavior) Run(t crossdock.T) {
	logParams(t)
	sampled, err := strconv.ParseBool(t.Param(sampledParam))
	if err != nil {
		t.Fatalf("Malformed param %s: %s", sampledParam, err)
	}
	baggage := randomBaggage()

	level1 := &Request{
		ServerRole: RoleS1,
	}
	server1 := t.Param(server1NameParam)

	level2 := &Downstream{
		ServiceName: t.Param(server2NameParam),
		ServerRole:  RoleS2,
		HostPort: fmt.Sprintf("%s:%s",
			b.serviceToHost(t.Param(server2NameParam)),
			b.ServerPort,
		),
		Encoding: t.Param(server2EncodingParam),
	}
	level1.Downstream = level2

	level3 := &Downstream{
		ServiceName: t.Param(server3NameParam),
		ServerRole:  RoleS3,
		HostPort: fmt.Sprintf("%s:%s",
			b.serviceToHost(t.Param(server3NameParam)),
			b.ServerPort,
		),
		Encoding: t.Param(server3EncodingParam),
	}
	level2.Downstream = level3

	resp, err := b.startTrace(t, level1, sampled, baggage)
	if err != nil {
		t.Errorf("Failed to startTrace in S1(%s): %s", server1, err.Error())
		return
	}

	log.Printf("Response: span=%+v, downstream=%+v", resp.Span, resp.Downstream)
	traceID := resp.Span.TraceID

	require := crossdock.Require(t)
	require.NotEmpty(traceID, "Trace ID should not be empty in S1(%s)", server1)

	if validateTrace(t, level1.Downstream, resp, server1, 1, traceID, sampled, baggage) {
		t.Successf("trace checks out")
		log.Println("PASS")
	} else {
		log.Println("FAIL")
	}
}

func ( b * Behavior ) Run ( t crossdock . T ) { logParams ( t ) sampled , err := strconv . ParseBool ( t . Param ( sampledParam ) ) if err != nil { t . Fatalf ( " " , sampledParam , err ) } baggage := randomBaggage ( ) level1 := & Request { ServerRole : RoleS1 , } server1 := t . Param ( server1NameParam ) level2 := & Downstream { ServiceName : t . Param ( server2NameParam ) , ServerRole : RoleS2 , HostPort : fmt . Sprintf ( " " , b . serviceToHost ( t . Param ( server2NameParam ) ) , b . ServerPort , ) , Encoding : t . Param ( server2EncodingParam ) , } level1 . Downstream = level2 level3 := & Downstream { ServiceName : t . Param ( server3NameParam ) , ServerRole : RoleS3 , HostPort : fmt . Sprintf ( " " , b . serviceToHost ( t . Param ( server3NameParam ) ) , b . ServerPort , ) , Encoding : t . Param ( server3EncodingParam ) , } level2 . Downstream = level3 resp , err := b . startTrace ( t , level1 , sampled , baggage ) if err != nil { t . Errorf ( " " , server1 , err . Error ( ) ) return } log . Printf ( " " , resp . Span , resp . Downstream ) traceID := resp . Span . TraceID require := crossdock . Require ( t ) require . NotEmpty ( traceID , " " , server1 ) if validateTrace ( t , level1 . Downstream , resp , server1 , 1 , traceID , sampled , baggage ) { t . Successf ( " " ) log . Println ( " " ) } else { log . Println ( " " ) } }


func (tp *relayTimerPool) Get() *relayTimer {
	timer, ok := tp.pool.Get().(*relayTimer)
	if ok {
		timer.released = false
		return timer
	}

	rt := &relayTimer{
		pool: tp,
	}
	// Go timers are started by default. However, we need to separate creating
	// the timer and starting the timer for use in the relay code paths.
	// To make this work without more locks in the relayTimer, we create a Go timer
	// with a huge timeout so it doesn't run, then stop it so we can start it later.
	rt.timer = time.AfterFunc(time.Duration(math.MaxInt64), rt.OnTimer)
	if !rt.timer.Stop() {
		panic("relayTimer requires timers in stopped state, but failed to stop underlying timer")
	}
	return rt
}

// Get returns a relay timer that has not started. Timers must be started explicitly
// using the Start function.

Get returns a relay timer that has not started . Timers must be started explicitly using the Start function .


func (tp *relayTimerPool) Put(rt *relayTimer) {
	if tp.verify {
		// If we are trying to verify correct pool behavior, then we don't release
		// the timer, and instead ensure no methods are called after being released.
		return
	}
	tp.pool.Put(rt)
}

// Put returns a relayTimer back to the pool.

Put returns a relayTimer back to the pool .


func (rt *relayTimer) Start(d time.Duration, items *relayItems, id uint32, isOriginator bool) {
	rt.verifyNotReleased()
	if rt.active {
		panic("Tried to start an already-active timer")
	}

	rt.active = true
	rt.items = items
	rt.id = id
	rt.isOriginator = isOriginator

	if wasActive := rt.timer.Reset(d); wasActive {
		panic("relayTimer's underlying timer was Started multiple times without Stop")
	}
}

func ( rt * relayTimer ) Start ( d time . Duration , items * relayItems , id uint32 , isOriginator bool ) { rt . verifyNotReleased ( ) if rt . active { panic ( " " ) } rt . active = true rt . items = items rt . id = id rt . isOriginator = isOriginator if wasActive := rt . timer . Reset ( d ) ; wasActive { panic ( " " ) } }

// Start starts a timer with the given duration for the specified ID.

Start starts a timer with the given duration for the specified ID .


func (rt *relayTimer) Release() {
	rt.verifyNotReleased()
	if rt.active {
		panic("only stopped or completed timers can be released")
	}
	rt.released = true
	rt.pool.Put(rt)
}

func ( rt * relayTimer ) Release ( ) { rt . verifyNotReleased ( ) if rt . active { panic ( " " ) } rt . released = true rt . pool . Put ( rt ) }

// Release releases a timer back to the timer pool. The timer MUST have run or be
// stopped before Release is called.

Release releases a timer back to the timer pool . The timer MUST have run or be stopped before Release is called .


func NewLogger(writer io.Writer, fields ...LogField) Logger {
	return &writerLogger{writer, fields}
}

func NewLogger ( writer io . Writer , fields ... LogField ) Logger { return & writerLogger { writer , fields } }

// NewLogger returns a Logger that writes to the given writer.

NewLogger returns a Logger that writes to the given writer .


func NewTCPFrameRelay(dests []string, modifier func(bool, *tchannel.Frame) *tchannel.Frame) (Relay, error) {
	var err error
	r := &tcpFrameRelay{modifier: modifier}

	r.tcpRelay, err = newTCPRelay(dests, r.handleConnFrameRelay)
	if err != nil {
		return nil, err
	}

	return r, nil
}

func NewTCPFrameRelay ( dests [ ] string , modifier func ( bool , * tchannel . Frame ) * tchannel . Frame ) ( Relay , error ) { var err error r := & tcpFrameRelay { modifier : modifier } r . tcpRelay , err = newTCPRelay ( dests , r . handleConnFrameRelay ) if err != nil { return nil , err } return r , nil }

// NewTCPFrameRelay relays frames from one connection to another. It reads
// and writes frames using the TChannel frame functions.

NewTCPFrameRelay relays frames from one connection to another . It reads and writes frames using the TChannel frame functions .


func (kt knownTags) tallyTags() map[string]string {
	tallyTags := make(map[string]string, 5)

	if kt.dest != "" {
		tallyTags["dest"] = kt.dest
	}
	if kt.source != "" {
		tallyTags["source"] = kt.source
	}
	if kt.procedure != "" {
		tallyTags["procedure"] = kt.procedure
	}
	if kt.retryCount != "" {
		tallyTags["retry-count"] = kt.retryCount
	}

	return tallyTags
}

func ( kt knownTags ) tallyTags ( ) map [ string ] string { tallyTags := make ( map [ string ] string , 5 ) if kt . dest != " " { tallyTags [ " " ] = kt . dest } if kt . source != " " { tallyTags [ " " ] = kt . source } if kt . procedure != " " { tallyTags [ " " ] = kt . procedure } if kt . retryCount != " " { tallyTags [ " " ] = kt . retryCount } return tallyTags }

// Create a sub-scope for this set of known tags.

Create a sub - scope for this set of known tags .


func Isolated(s *SubChannel) {
	s.Lock()
	s.peers = s.topChannel.peers.newSibling()
	s.peers.SetStrategy(newLeastPendingCalculator())
	s.Unlock()
}

func Isolated ( s * SubChannel ) { s . Lock ( ) s . peers = s . topChannel . peers . newSibling ( ) s . peers . SetStrategy ( newLeastPendingCalculator ( ) ) s . Unlock ( ) }

// Isolated is a SubChannelOption that creates an isolated subchannel.

Isolated is a SubChannelOption that creates an isolated subchannel .


func (c *SubChannel) Isolated() bool {
	c.RLock()
	defer c.RUnlock()
	return c.topChannel.Peers() != c.peers
}

func ( c * SubChannel ) Isolated ( ) bool { c . RLock ( ) defer c . RUnlock ( ) return c . topChannel . Peers ( ) != c . peers }

// Isolated returns whether this subchannel is an isolated subchannel.

Isolated returns whether this subchannel is an isolated subchannel .


func (c *SubChannel) Register(h Handler, methodName string) {
	handlers, ok := c.handler.(*handlerMap)
	if !ok {
		panic(fmt.Sprintf(
			"handler for SubChannel(%v) was changed to disallow method registration",
			c.ServiceName(),
		))
	}
	handlers.register(h, methodName)
}

func ( c * SubChannel ) Register ( h Handler , methodName string ) { handlers , ok := c . handler . ( * handlerMap ) if ! ok { panic ( fmt . Sprintf ( " " , c . ServiceName ( ) , ) ) } handlers . register ( h , methodName ) }

// Register registers a handler on the subchannel for the given method.
//
// This function panics if the Handler for the SubChannel was overwritten with
// SetHandler.

Register registers a handler on the subchannel for the given method . This function panics if the Handler for the SubChannel was overwritten with SetHandler .


func (c *SubChannel) GetHandlers() map[string]Handler {
	handlers, ok := c.handler.(*handlerMap)
	if !ok {
		panic(fmt.Sprintf(
			"handler for SubChannel(%v) was changed to disallow method registration",
			c.ServiceName(),
		))
	}

	handlers.RLock()
	handlersMap := make(map[string]Handler, len(handlers.handlers))
	for k, v := range handlers.handlers {
		handlersMap[k] = v
	}
	handlers.RUnlock()
	return handlersMap
}

func ( c * SubChannel ) GetHandlers ( ) map [ string ] Handler { handlers , ok := c . handler . ( * handlerMap ) if ! ok { panic ( fmt . Sprintf ( " " , c . ServiceName ( ) , ) ) } handlers . RLock ( ) handlersMap := make ( map [ string ] Handler , len ( handlers . handlers ) ) for k , v := range handlers . handlers { handlersMap [ k ] = v } handlers . RUnlock ( ) return handlersMap }

// GetHandlers returns all handlers registered on this subchannel by method name.
//
// This function panics if the Handler for the SubChannel was overwritten with
// SetHandler.

GetHandlers returns all handlers registered on this subchannel by method name . This function panics if the Handler for the SubChannel was overwritten with SetHandler .


func (c *SubChannel) StatsTags() map[string]string {
	tags := c.topChannel.StatsTags()
	tags["subchannel"] = c.serviceName
	return tags
}

func ( c * SubChannel ) StatsTags ( ) map [ string ] string { tags := c . topChannel . StatsTags ( ) tags [ " " ] = c . serviceName return tags }

// StatsTags returns the stats tags for this subchannel.

StatsTags returns the stats tags for this subchannel .


func (subChMap *subChannelMap) registerNewSubChannel(serviceName string, ch *Channel) (_ *SubChannel, added bool) {
	subChMap.Lock()
	defer subChMap.Unlock()

	if subChMap.subchannels == nil {
		subChMap.subchannels = make(map[string]*SubChannel)
	}

	if sc, ok := subChMap.subchannels[serviceName]; ok {
		return sc, false
	}

	sc := newSubChannel(serviceName, ch)
	subChMap.subchannels[serviceName] = sc
	return sc, true
}

func ( subChMap * subChannelMap ) registerNewSubChannel ( serviceName string , ch * Channel ) ( _ * SubChannel , added bool ) { subChMap . Lock ( ) defer subChMap . Unlock ( ) if subChMap . subchannels == nil { subChMap . subchannels = make ( map [ string ] * SubChannel ) } if sc , ok := subChMap . subchannels [ serviceName ] ; ok { return sc , false } sc := newSubChannel ( serviceName , ch ) subChMap . subchannels [ serviceName ] = sc return sc , true }

// Register a new subchannel for the given serviceName


func (subChMap *subChannelMap) get(serviceName string) (*SubChannel, bool) {
	subChMap.RLock()
	sc, ok := subChMap.subchannels[serviceName]
	subChMap.RUnlock()
	return sc, ok
}

func ( subChMap * subChannelMap ) get ( serviceName string ) ( * SubChannel , bool ) { subChMap . RLock ( ) sc , ok := subChMap . subchannels [ serviceName ] subChMap . RUnlock ( ) return sc , ok }


func (subChMap *subChannelMap) getOrAdd(serviceName string, ch *Channel) (_ *SubChannel, added bool) {
	if sc, ok := subChMap.get(serviceName); ok {
		return sc, false
	}

	return subChMap.registerNewSubChannel(serviceName, ch)
}

func ( subChMap * subChannelMap ) getOrAdd ( serviceName string , ch * Channel ) ( _ * SubChannel , added bool ) { if sc , ok := subChMap . get ( serviceName ) ; ok { return sc , false } return subChMap . registerNewSubChannel ( serviceName , ch ) }

// GetOrAdd a subchannel for the given serviceName on the map


func (c *Client) Discover(serviceName string) ([]string, error) {
	ctx, cancel := thrift.NewContext(time.Second)
	defer cancel()

	result, err := c.hyperbahnClient.Discover(ctx, &hyperbahn.DiscoveryQuery{ServiceName: serviceName})
	if err != nil {
		return nil, err
	}

	var hostPorts []string
	for _, peer := range result.GetPeers() {
		hostPorts = append(hostPorts, servicePeerToHostPort(peer))
	}

	return hostPorts, nil
}

func ( c * Client ) Discover ( serviceName string ) ( [ ] string , error ) { ctx , cancel := thrift . NewContext ( time . Second ) defer cancel ( ) result , err := c . hyperbahnClient . Discover ( ctx , & hyperbahn . DiscoveryQuery { ServiceName : serviceName } ) if err != nil { return nil , err } var hostPorts [ ] string for _ , peer := range result . GetPeers ( ) { hostPorts = append ( hostPorts , servicePeerToHostPort ( peer ) ) } return hostPorts , nil }

// Discover queries Hyperbahn for a list of peers that are currently
// advertised with the specified service name.

Discover queries Hyperbahn for a list of peers that are currently advertised with the specified service name .


func (c *Client) Start() error {
	if err := c.listen(); err != nil {
		return err
	}
	go func() {
		http.Serve(c.listener, c.mux)
	}()
	return nil
}

func ( c * Client ) Start ( ) error { if err := c . listen ( ) ; err != nil { return err } go func ( ) { http . Serve ( c . listener , c . mux ) } ( ) return nil }

// Start begins a Crossdock client in the background.

Start begins a Crossdock client in the background .


func (c *Client) listen() error {
	c.setDefaultPort(&c.ClientHostPort, ":"+common.DefaultClientPortHTTP)
	c.setDefaultPort(&c.ServerPort, common.DefaultServerPort)

	c.mux = http.NewServeMux() // Using default mux creates problem in unit tests
	c.mux.Handle("/", crossdock.Handler(c.Behaviors, true))

	listener, err := net.Listen("tcp", c.ClientHostPort)
	if err != nil {
		return err
	}
	c.listener = listener
	c.ClientHostPort = listener.Addr().String() // override in case it was ":0"
	return nil
}


func WriteRequest(call tchannel.ArgWritable, req *http.Request) error {
	// TODO(prashant): Allow creating write buffers that let you grow the buffer underneath.
	wb := typed.NewWriteBufferWithSize(10000)
	wb.WriteLen8String(req.Method)
	writeVarintString(wb, req.URL.String())
	writeHeaders(wb, req.Header)

	arg2Writer, err := call.Arg2Writer()
	if err != nil {
		return err
	}
	if _, err := wb.FlushTo(arg2Writer); err != nil {
		return err
	}
	if err := arg2Writer.Close(); err != nil {
		return err
	}

	arg3Writer, err := call.Arg3Writer()
	if err != nil {
		return err
	}

	if req.Body != nil {
		if _, err = io.Copy(arg3Writer, req.Body); err != nil {
			return err
		}
	}
	return arg3Writer.Close()
}

// WriteRequest writes a http.Request to the given writers.

WriteRequest writes a http . Request to the given writers .


func ReadRequest(call tchannel.ArgReadable) (*http.Request, error) {
	var arg2 []byte
	if err := tchannel.NewArgReader(call.Arg2Reader()).Read(&arg2); err != nil {
		return nil, err
	}
	rb := typed.NewReadBuffer(arg2)
	method := rb.ReadLen8String()
	url := readVarintString(rb)

	r, err := http.NewRequest(method, url, nil)
	if err != nil {
		return nil, err
	}
	readHeaders(rb, r.Header)

	if err := rb.Err(); err != nil {
		return nil, err
	}

	r.Body, err = call.Arg3Reader()
	return r, err
}

func ReadRequest ( call tchannel . ArgReadable ) ( * http . Request , error ) { var arg2 [ ] byte if err := tchannel . NewArgReader ( call . Arg2Reader ( ) ) . Read ( & arg2 ) ; err != nil { return nil , err } rb := typed . NewReadBuffer ( arg2 ) method := rb . ReadLen8String ( ) url := readVarintString ( rb ) r , err := http . NewRequest ( method , url , nil ) if err != nil { return nil , err } readHeaders ( rb , r . Header ) if err := rb . Err ( ) ; err != nil { return nil , err } r . Body , err = call . Arg3Reader ( ) return r , err }

// ReadRequest reads a http.Request from the given readers.

ReadRequest reads a http . Request from the given readers .


func NewReadBufferWithSize(size int) *ReadBuffer {
	return &ReadBuffer{buffer: make([]byte, size), remaining: nil}
}

func NewReadBufferWithSize ( size int ) * ReadBuffer { return & ReadBuffer { buffer : make ( [ ] byte , size ) , remaining : nil } }

// NewReadBufferWithSize returns a ReadBuffer with a given capacity


func (r *ReadBuffer) ReadByte() (byte, error) {
	if r.err != nil {
		return 0, r.err
	}

	if len(r.remaining) < 1 {
		r.err = ErrEOF
		return 0, r.err
	}

	b := r.remaining[0]
	r.remaining = r.remaining[1:]
	return b, nil
}

func ( r * ReadBuffer ) ReadByte ( ) ( byte , error ) { if r . err != nil { return 0 , r . err } if len ( r . remaining ) < 1 { r . err = ErrEOF return 0 , r . err } b := r . remaining [ 0 ] r . remaining = r . remaining [ 1 : ] return b , nil }

// ReadByte returns the next byte from the buffer.

ReadByte returns the next byte from the buffer .


func (r *ReadBuffer) ReadBytes(n int) []byte {
	if r.err != nil {
		return nil
	}

	if len(r.remaining) < n {
		r.err = ErrEOF
		return nil
	}

	b := r.remaining[0:n]
	r.remaining = r.remaining[n:]
	return b
}

func ( r * ReadBuffer ) ReadBytes ( n int ) [ ] byte { if r . err != nil { return nil } if len ( r . remaining ) < n { r . err = ErrEOF return nil } b := r . remaining [ 0 : n ] r . remaining = r . remaining [ n : ] return b }

// ReadBytes returns the next n bytes from the buffer


func (r *ReadBuffer) ReadString(n int) string {
	if b := r.ReadBytes(n); b != nil {
		// TODO(mmihic): This creates a copy, which sucks
		return string(b)
	}

	return ""
}

// ReadString returns a string of size n from the buffer


func (r *ReadBuffer) ReadUint16() uint16 {
	if b := r.ReadBytes(2); b != nil {
		return binary.BigEndian.Uint16(b)
	}

	return 0
}

func ( r * ReadBuffer ) ReadUint16 ( ) uint16 { if b := r . ReadBytes ( 2 ) ; b != nil { return binary . BigEndian . Uint16 ( b ) } return 0 }

// ReadUint16 returns the next value in the buffer as a uint16


func (r *ReadBuffer) ReadUint32() uint32 {
	if b := r.ReadBytes(4); b != nil {
		return binary.BigEndian.Uint32(b)
	}

	return 0
}

func ( r * ReadBuffer ) ReadUint32 ( ) uint32 { if b := r . ReadBytes ( 4 ) ; b != nil { return binary . BigEndian . Uint32 ( b ) } return 0 }

// ReadUint32 returns the next value in the buffer as a uint32


func (r *ReadBuffer) ReadUint64() uint64 {
	if b := r.ReadBytes(8); b != nil {
		return binary.BigEndian.Uint64(b)
	}

	return 0
}

func ( r * ReadBuffer ) ReadUint64 ( ) uint64 { if b := r . ReadBytes ( 8 ) ; b != nil { return binary . BigEndian . Uint64 ( b ) } return 0 }

// ReadUint64 returns the next value in the buffer as a uint64


func (r *ReadBuffer) ReadUvarint() uint64 {
	v, _ := binary.ReadUvarint(r)
	return v
}

func ( r * ReadBuffer ) ReadUvarint ( ) uint64 { v , _ := binary . ReadUvarint ( r ) return v }

// ReadUvarint reads an unsigned varint from the buffer.

ReadUvarint reads an unsigned varint from the buffer .


func (r *ReadBuffer) ReadLen8String() string {
	n := r.ReadSingleByte()
	return r.ReadString(int(n))
}

func ( r * ReadBuffer ) ReadLen8String ( ) string { n := r . ReadSingleByte ( ) return r . ReadString ( int ( n ) ) }

// ReadLen8String reads an 8-bit length preceded string value

ReadLen8String reads an 8 - bit length preceded string value


func (r *ReadBuffer) ReadLen16String() string {
	n := r.ReadUint16()
	return r.ReadString(int(n))
}

func ( r * ReadBuffer ) ReadLen16String ( ) string { n := r . ReadUint16 ( ) return r . ReadString ( int ( n ) ) }

// ReadLen16String reads a 16-bit length preceded string value

ReadLen16String reads a 16 - bit length preceded string value


func (r *ReadBuffer) FillFrom(ior io.Reader, n int) (int, error) {
	if len(r.buffer) < n {
		return 0, ErrEOF
	}

	r.err = nil
	r.remaining = r.buffer[:n]
	return io.ReadFull(ior, r.remaining)
}

func ( r * ReadBuffer ) FillFrom ( ior io . Reader , n int ) ( int , error ) { if len ( r . buffer ) < n { return 0 , ErrEOF } r . err = nil r . remaining = r . buffer [ : n ] return io . ReadFull ( ior , r . remaining ) }

// FillFrom fills the buffer from a reader