// Copyright (C) 2020 Storj Labs, Inc. // See LICENSE for copying information. // Package rpcpeer implements context.Context peer tagging. package rpcpeer import ( "context" "crypto/tls" "net" "github.com/zeebo/errs" "storj.io/drpc/drpcctx" ) // Error is the class of errors returned by this package. var Error = errs.Class("rpcpeer") // Peer represents an rpc peer. type Peer struct { Addr net.Addr State tls.ConnectionState } // peerKey is used as a unique value for context keys. type peerKey struct{} // NewContext returns a new context with the peer associated as a value. func NewContext(ctx context.Context, peer *Peer) context.Context { return context.WithValue(ctx, peerKey{}, peer) } // FromContext returns the peer that was previously associated by NewContext. func FromContext(ctx context.Context) (*Peer, error) { if peer, ok := ctx.Value(peerKey{}).(*Peer); ok { return peer, nil } else if peer, drpcErr := drpcInternalFromContext(ctx); drpcErr == nil { return peer, nil } else { return nil, drpcErr } } // drpcInternalFromContext returns a peer from the context using drpc. func drpcInternalFromContext(ctx context.Context) (*Peer, error) { tr, ok := drpcctx.Transport(ctx) if !ok { return nil, Error.New("unable to get drpc peer from context") } conn, ok := tr.(interface { RemoteAddr() net.Addr ConnectionState() tls.ConnectionState }) if !ok { return nil, Error.New("drpc transport does not have required methods") } return &Peer{ Addr: conn.RemoteAddr(), State: conn.ConnectionState(), }, nil }