client_v2.go
package nsqdimport ("bufio""compress/flate""crypto/tls""fmt""net""sync""sync/atomic""time""github.com/mreiferson/go-snappystream""github.com/nsqio/nsq/internal/auth")const defaultBufferSize = 16 * 1024const (stateInit = iotastateDisconnectedstateConnectedstateSubscribedstateClosing)type identifyDataV2 struct {ShortID string `json:"short_id"` // TODO: deprecated, remove in 1.0LongID string `json:"long_id"` // TODO: deprecated, remove in 1.0ClientID string `json:"client_id"`Hostname string `json:"hostname"`HeartbeatInterval int `json:"heartbeat_interval"`OutputBufferSize int `json:"output_buffer_size"`OutputBufferTimeout int `json:"output_buffer_timeout"`FeatureNegotiation bool `json:"feature_negotiation"`TLSv1 bool `json:"tls_v1"`Deflate bool `json:"deflate"`DeflateLevel int `json:"deflate_level"`Snappy bool `json:"snappy"`SampleRate int32 `json:"sample_rate"`UserAgent string `json:"user_agent"`MsgTimeout int `json:"msg_timeout"`}type identifyEvent struct {OutputBufferTimeout time.DurationHeartbeatInterval time.DurationSampleRate int32MsgTimeout time.Duration}type clientV2 struct {// 64bit atomic vars need to be first for proper alignment on 32bit platformsReadyCount int64InFlightCount int64MessageCount uint64FinishCount uint64RequeueCount uint64writeLock sync.RWMutexmetaLock sync.RWMutexID int64ctx *contextUserAgent string// original connectionnet.Conn// connections based on negotiated featurestlsConn *tls.ConnflateWriter *flate.Writer// reading/writing interfacesReader *bufio.ReaderWriter *bufio.WriterOutputBufferSize intOutputBufferTimeout time.DurationHeartbeatInterval time.DurationMsgTimeout time.DurationState int32ConnectTime time.TimeChannel *ChannelReadyStateChan chan intExitChan chan intClientID stringHostname stringSampleRate int32IdentifyEventChan chan identifyEventSubEventChan chan *ChannelTLS int32Snappy int32Deflate int32// re-usable buffer for reading the 4-byte lengths off the wirelenBuf [4]bytelenSlice []byteAuthSecret stringAuthState *auth.State}func newClientV2(id int64, conn net.Conn, ctx *context) *clientV2 {var identifier stringif conn != nil {identifier, _, _ = net.SplitHostPort(conn.RemoteAddr().String())}c := &clientV2{ID: id,ctx: ctx,Conn: conn,Reader: bufio.NewReaderSize(conn, defaultBufferSize),Writer: bufio.NewWriterSize(conn, defaultBufferSize),OutputBufferSize: defaultBufferSize,OutputBufferTimeout: 250 * time.Millisecond,MsgTimeout: ctx.nsqd.getOpts().MsgTimeout,// ReadyStateChan has a buffer of 1 to guarantee that in the event// there is a race the state update is not lostReadyStateChan: make(chan int, 1),ExitChan: make(chan int),ConnectTime: time.Now(),State: stateInit,ClientID: identifier,Hostname: identifier,SubEventChan: make(chan *Channel, 1),IdentifyEventChan: make(chan identifyEvent, 1),// heartbeats are client configurable but default to 30sHeartbeatInterval: ctx.nsqd.getOpts().ClientTimeout / 2,}c.lenSlice = c.lenBuf[:]return c}func (c *clientV2) String() string {return c.RemoteAddr().String()}func (c *clientV2) Identify(data identifyDataV2) error {c.ctx.nsqd.logf("[%s] IDENTIFY: %+v", c, data)// TODO: for backwards compatibility, remove in 1.0hostname := data.Hostnameif hostname == "" {hostname = data.LongID}// TODO: for backwards compatibility, remove in 1.0clientID := data.ClientIDif clientID == "" {clientID = data.ShortID}c.metaLock.Lock()c.ClientID = clientIDc.Hostname = hostnamec.UserAgent = data.UserAgentc.metaLock.Unlock()err := c.SetHeartbeatInterval(data.HeartbeatInterval)if err != nil {return err}err = c.SetOutputBufferSize(data.OutputBufferSize)if err != nil {return err}err = c.SetOutputBufferTimeout(data.OutputBufferTimeout)if err != nil {return err}err = c.SetSampleRate(data.SampleRate)if err != nil {return err}err = c.SetMsgTimeout(data.MsgTimeout)if err != nil {return err}ie := identifyEvent{OutputBufferTimeout: c.OutputBufferTimeout,HeartbeatInterval: c.HeartbeatInterval,SampleRate: c.SampleRate,MsgTimeout: c.MsgTimeout,}// update the client's message pumpselect {case c.IdentifyEventChan <- ie:default:}return nil}func (c *clientV2) Stats() ClientStats {c.metaLock.RLock()// TODO: deprecated, remove in 1.0name := c.ClientIDclientID := c.ClientIDhostname := c.HostnameuserAgent := c.UserAgentvar identity stringvar identityURL stringif c.AuthState != nil {identity = c.AuthState.IdentityidentityURL = c.AuthState.IdentityURL}c.metaLock.RUnlock()stats := ClientStats{// TODO: deprecated, remove in 1.0Name: name,Version: "V2",RemoteAddress: c.RemoteAddr().String(),ClientID: clientID,Hostname: hostname,UserAgent: userAgent,State: atomic.LoadInt32(&c.State),ReadyCount: atomic.LoadInt64(&c.ReadyCount),InFlightCount: atomic.LoadInt64(&c.InFlightCount),MessageCount: atomic.LoadUint64(&c.MessageCount),FinishCount: atomic.LoadUint64(&c.FinishCount),RequeueCount: atomic.LoadUint64(&c.RequeueCount),ConnectTime: c.ConnectTime.Unix(),SampleRate: atomic.LoadInt32(&c.SampleRate),TLS: atomic.LoadInt32(&c.TLS) == 1,Deflate: atomic.LoadInt32(&c.Deflate) == 1,Snappy: atomic.LoadInt32(&c.Snappy) == 1,Authed: c.HasAuthorizations(),AuthIdentity: identity,AuthIdentityURL: identityURL,}if stats.TLS {p := prettyConnectionState{c.tlsConn.ConnectionState()}stats.CipherSuite = p.GetCipherSuite()stats.TLSVersion = p.GetVersion()stats.TLSNegotiatedProtocol = p.NegotiatedProtocolstats.TLSNegotiatedProtocolIsMutual = p.NegotiatedProtocolIsMutual}return stats}// struct to convert from integers to the human readable stringstype prettyConnectionState struct {tls.ConnectionState}func (p *prettyConnectionState) GetCipherSuite() string {switch p.CipherSuite {case tls.TLS_RSA_WITH_RC4_128_SHA:return "TLS_RSA_WITH_RC4_128_SHA"case tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA:return "TLS_RSA_WITH_3DES_EDE_CBC_SHA"case tls.TLS_RSA_WITH_AES_128_CBC_SHA:return "TLS_RSA_WITH_AES_128_CBC_SHA"case tls.TLS_RSA_WITH_AES_256_CBC_SHA:return "TLS_RSA_WITH_AES_256_CBC_SHA"case tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA"case tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA"case tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA"case tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA:return "TLS_ECDHE_RSA_WITH_RC4_128_SHA"case tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA"case tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA"case tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA"case tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"case tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"}return fmt.Sprintf("Unknown %d", p.CipherSuite)}func (p *prettyConnectionState) GetVersion() string {switch p.Version {case tls.VersionSSL30:return "SSL30"case tls.VersionTLS10:return "TLS1.0"case tls.VersionTLS11:return "TLS1.1"case tls.VersionTLS12:return "TLS1.2"default:return fmt.Sprintf("Unknown %d", p.Version)}}func (c *clientV2) IsReadyForMessages() bool {if c.Channel.IsPaused() {return false}readyCount := atomic.LoadInt64(&c.ReadyCount)inFlightCount := atomic.LoadInt64(&c.InFlightCount)if c.ctx.nsqd.getOpts().Verbose {c.ctx.nsqd.logf("[%s] state rdy: %4d inflt: %4d",c, readyCount, inFlightCount)}if inFlightCount >= readyCount || readyCount <= 0 {return false}return true}func (c *clientV2) SetReadyCount(count int64) {atomic.StoreInt64(&c.ReadyCount, count)c.tryUpdateReadyState()}func (c *clientV2) tryUpdateReadyState() {// you can always *try* to write to ReadyStateChan because in the cases// where you cannot the message pump loop would have iterated anyway.// the atomic integer operations guarantee correctness of the value.select {case c.ReadyStateChan <- 1:default:}}func (c *clientV2) FinishedMessage() {atomic.AddUint64(&c.FinishCount, 1)atomic.AddInt64(&c.InFlightCount, -1)c.tryUpdateReadyState()}func (c *clientV2) Empty() {atomic.StoreInt64(&c.InFlightCount, 0)c.tryUpdateReadyState()}func (c *clientV2) SendingMessage() {atomic.AddInt64(&c.InFlightCount, 1)atomic.AddUint64(&c.MessageCount, 1)}func (c *clientV2) TimedOutMessage() {atomic.AddInt64(&c.InFlightCount, -1)c.tryUpdateReadyState()}func (c *clientV2) RequeuedMessage() {atomic.AddUint64(&c.RequeueCount, 1)atomic.AddInt64(&c.InFlightCount, -1)c.tryUpdateReadyState()}func (c *clientV2) StartClose() {// Force the client into ready 0c.SetReadyCount(0)// mark this client as closingatomic.StoreInt32(&c.State, stateClosing)}func (c *clientV2) Pause() {c.tryUpdateReadyState()}func (c *clientV2) UnPause() {c.tryUpdateReadyState()}func (c *clientV2) SetHeartbeatInterval(desiredInterval int) error {c.writeLock.Lock()defer c.writeLock.Unlock()switch {case desiredInterval == -1:c.HeartbeatInterval = 0case desiredInterval == 0:// do nothing (use default)case desiredInterval >= 1000 &&desiredInterval <= int(c.ctx.nsqd.getOpts().MaxHeartbeatInterval/time.Millisecond):c.HeartbeatInterval = time.Duration(desiredInterval) * time.Milliseconddefault:return fmt.Errorf("heartbeat interval (%d) is invalid", desiredInterval)}return nil}func (c *clientV2) SetOutputBufferSize(desiredSize int) error {var size intswitch {case desiredSize == -1:// effectively no buffer (every write will go directly to the wrapped net.Conn)size = 1case desiredSize == 0:// do nothing (use default)case desiredSize >= 64 && desiredSize <= int(c.ctx.nsqd.getOpts().MaxOutputBufferSize):size = desiredSizedefault:return fmt.Errorf("output buffer size (%d) is invalid", desiredSize)}if size > 0 {c.writeLock.Lock()defer c.writeLock.Unlock()c.OutputBufferSize = sizeerr := c.Writer.Flush()if err != nil {return err}c.Writer = bufio.NewWriterSize(c.Conn, size)}return nil}func (c *clientV2) SetOutputBufferTimeout(desiredTimeout int) error {c.writeLock.Lock()defer c.writeLock.Unlock()switch {case desiredTimeout == -1:c.OutputBufferTimeout = 0case desiredTimeout == 0:// do nothing (use default)case desiredTimeout >= 1 &&desiredTimeout <= int(c.ctx.nsqd.getOpts().MaxOutputBufferTimeout/time.Millisecond):c.OutputBufferTimeout = time.Duration(desiredTimeout) * time.Milliseconddefault:return fmt.Errorf("output buffer timeout (%d) is invalid", desiredTimeout)}return nil}func (c *clientV2) SetSampleRate(sampleRate int32) error {if sampleRate < 0 || sampleRate > 99 {return fmt.Errorf("sample rate (%d) is invalid", sampleRate)}atomic.StoreInt32(&c.SampleRate, sampleRate)return nil}func (c *clientV2) SetMsgTimeout(msgTimeout int) error {c.writeLock.Lock()defer c.writeLock.Unlock()switch {case msgTimeout == 0:// do nothing (use default)case msgTimeout >= 1000 &&msgTimeout <= int(c.ctx.nsqd.getOpts().MaxMsgTimeout/time.Millisecond):c.MsgTimeout = time.Duration(msgTimeout) * time.Milliseconddefault:return fmt.Errorf("msg timeout (%d) is invalid", msgTimeout)}return nil}func (c *clientV2) UpgradeTLS() error {c.writeLock.Lock()defer c.writeLock.Unlock()tlsConn := tls.Server(c.Conn, c.ctx.nsqd.tlsConfig)tlsConn.SetDeadline(time.Now().Add(5 * time.Second))err := tlsConn.Handshake()if err != nil {return err}c.tlsConn = tlsConnc.Reader = bufio.NewReaderSize(c.tlsConn, defaultBufferSize)c.Writer = bufio.NewWriterSize(c.tlsConn, c.OutputBufferSize)atomic.StoreInt32(&c.TLS, 1)return nil}func (c *clientV2) UpgradeDeflate(level int) error {c.writeLock.Lock()defer c.writeLock.Unlock()conn := c.Connif c.tlsConn != nil {conn = c.tlsConn}c.Reader = bufio.NewReaderSize(flate.NewReader(conn), defaultBufferSize)fw, _ := flate.NewWriter(conn, level)c.flateWriter = fwc.Writer = bufio.NewWriterSize(fw, c.OutputBufferSize)atomic.StoreInt32(&c.Deflate, 1)return nil}func (c *clientV2) UpgradeSnappy() error {c.writeLock.Lock()defer c.writeLock.Unlock()conn := c.Connif c.tlsConn != nil {conn = c.tlsConn}c.Reader = bufio.NewReaderSize(snappystream.NewReader(conn, snappystream.SkipVerifyChecksum), defaultBufferSize)c.Writer = bufio.NewWriterSize(snappystream.NewWriter(conn), c.OutputBufferSize)atomic.StoreInt32(&c.Snappy, 1)return nil}func (c *clientV2) Flush() error {var zeroTime time.Timeif c.HeartbeatInterval > 0 {c.SetWriteDeadline(time.Now().Add(c.HeartbeatInterval))} else {c.SetWriteDeadline(zeroTime)}err := c.Writer.Flush()if err != nil {return err}if c.flateWriter != nil {return c.flateWriter.Flush()}return nil}func (c *clientV2) QueryAuthd() error {remoteIP, _, err := net.SplitHostPort(c.String())if err != nil {return err}tls := atomic.LoadInt32(&c.TLS) == 1tlsEnabled := "false"if tls {tlsEnabled = "true"}authState, err := auth.QueryAnyAuthd(c.ctx.nsqd.getOpts().AuthHTTPAddresses,remoteIP, tlsEnabled, c.AuthSecret, c.ctx.nsqd.getOpts().HTTPClientConnectTimeout,c.ctx.nsqd.getOpts().HTTPClientRequestTimeout)if err != nil {return err}c.AuthState = authStatereturn nil}func (c *clientV2) Auth(secret string) error {c.AuthSecret = secretreturn c.QueryAuthd()}func (c *clientV2) IsAuthorized(topic, channel string) (bool, error) {if c.AuthState == nil {return false, nil}if c.AuthState.IsExpired() {err := c.QueryAuthd()if err != nil {return false, err}}if c.AuthState.IsAllowed(topic, channel) {return true, nil}return false, nil}func (c *clientV2) HasAuthorizations() bool {if c.AuthState != nil {return len(c.AuthState.Authorizations) != 0}return false}
client_v2.go的更多相关文章
- influxDB使用小结
在集群中安装influxdb influxdb提供了官方镜像,因此在集群中安装influxdb十分方便,只需要指定镜像名为influxdb即可自动下载运行,只需要配置环境变量就可以进行初始化设置 以下 ...
- NSQ源码剖析——主要结构方法和消息生产消费过程
目录 1 概述 2 主要结构体及方法 2.1 NSQD 2.2 tcpServer 2.3 protocolV2 2.4 clientV2 2.5 Topic 2.6 channel 3 启动过程 4 ...
随机推荐
- 恶补web之三:http学习
http是超文本传输协议的简称,该协议设计目的是保证客户机与服务器之间的通信.http的工作方式为客户机与服务器之间的请求-应答协议. 一般来说web浏览器是客户端,计算机上的网络应用程序可能作为服务 ...
- 重定向和servlet生命周期
重定向(1)什么是重定向服务器通知浏览器向一个新的地址发送请求.注:可以发送一个302状态码和一个Location消息头.(该消息头包含了一个地址,称之为重定向地址),浏览器收到之后,会立即向重定向地 ...
- aside元素
aside元素用来表示当前页面或文章的附属信息部分,它可以包含与当前页面或主要内容相关的引用.侧边栏.广告.导航条,以及其他类似的有别于主要内容的部分. aside元素主要有以下两种使用方法: 1.包 ...
- CDH安装系统环境准备——系统版本和安装包下载地址指南
由于Hadoop深受客户欢迎,许多公司都推出了各自版本的Hadoop,也有一些公司则围绕Hadoop开发产品.在Hadoop生态系统中,规模最大.知名度最高的公司则是Cloudera.接下来的日子里, ...
- SPRING事务的属性有哪些?其中,事务隔离级别有哪几种?什么情况需要使用这几种事务隔离级别?
Spring 声明式事务,propagation属性列表 PROPAGATION_REQUIRED:支持当前事务,如果当前没有事务,就新建一个事务.这是最常见的选择. PROPAGATION_SU ...
- Mac 电脑前端环境配置
恍惚间,好久没有在外面写过随笔了.在阿里的那两年,学到了许多,也成长了许多,认识了很多可爱的人,也明白了很多社会的事.最后种种艰难抉择,我来到了美团成都,一个贫穷落后但更自由开放弹性的地方.已经误以为 ...
- 说说Android的MVP模式
http://toughcoder.NET/blog/2015/11/29/understanding-Android-mvp-pattern/ 安卓应用开发是一个看似容易,实则很难的一门苦活儿.上手 ...
- java数据库(MySQL)之增删改查
1.查询数据 先救从简单的来吧,之前我们实现了将数据库表格信息读取到一个List集合中,数据库的查询,实 际上就是对这个集合的查询: public class Show { public static ...
- asp.net core ABP模板本地化设置
ABP的语言本地化设置非常方便,甚至地区图标ABP框架都已经有了. 先看看结果吧. 英文的界面 中文的界面 配置流程如下: 首先在Localization目录下新建一个对应的json文件,里面存放对应 ...
- SEO优化:浅析关键词出现在网站哪些地方更有利?
关键词出现在网站哪些地方符合SEO?进行网站的SEO时,关键词需要出现在整个网站的适当地方.下面列出几个重要的关键词摆放的地方.以下列出的10个地方希望能够帮助到大家. 1.网站Title部分. 2. ...