lookup_peer.go
package nsqd
import (
"encoding/binary"
"fmt"
"io"
"net"
"time"
"github.com/nsqio/go-nsq"
)
// lookupPeer is a low-level type for connecting/reading/writing to nsqlookupd
//
// A lookupPeer instance is designed to connect lazily to nsqlookupd and reconnect
// gracefully (i.e. it is all handled by the library). Clients can simply use the
// Command interface to perform a round-trip.
type lookupPeer struct {
l Logger
addr string
conn net.Conn
state int32
connectCallback func(*lookupPeer)
maxBodySize int64
Info peerInfo
}
// peerInfo contains metadata for a lookupPeer instance (and is JSON marshalable)
type peerInfo struct {
TCPPort int `json:"tcp_port"`
HTTPPort int `json:"http_port"`
Version string `json:"version"`
BroadcastAddress string `json:"broadcast_address"`
}
// newLookupPeer creates a new lookupPeer instance connecting to the supplied address.
//
// The supplied connectCallback will be called *every* time the instance connects.
func newLookupPeer(addr string, maxBodySize int64, l Logger, connectCallback func(*lookupPeer)) *lookupPeer {
return &lookupPeer{
l: l,
addr: addr,
state: stateDisconnected,
maxBodySize: maxBodySize,
connectCallback: connectCallback,
}
}
// Connect will Dial the specified address, with timeouts
func (lp *lookupPeer) Connect() error {
lp.l.Output(2, fmt.Sprintf("LOOKUP connecting to %s", lp.addr))
conn, err := net.DialTimeout("tcp", lp.addr, time.Second)
if err != nil {
return err
}
lp.conn = conn
return nil
}
// String returns the specified address
func (lp *lookupPeer) String() string {
return lp.addr
}
// Read implements the io.Reader interface, adding deadlines
func (lp *lookupPeer) Read(data []byte) (int, error) {
lp.conn.SetReadDeadline(time.Now().Add(time.Second))
return lp.conn.Read(data)
}
// Write implements the io.Writer interface, adding deadlines
func (lp *lookupPeer) Write(data []byte) (int, error) {
lp.conn.SetWriteDeadline(time.Now().Add(time.Second))
return lp.conn.Write(data)
}
// Close implements the io.Closer interface
func (lp *lookupPeer) Close() error {
lp.state = stateDisconnected
if lp.conn != nil {
return lp.conn.Close()
}
return nil
}
// Command performs a round-trip for the specified Command.
//
// It will lazily connect to nsqlookupd and gracefully handle
// reconnecting in the event of a failure.
//
// It returns the response from nsqlookupd as []byte
func (lp *lookupPeer) Command(cmd *nsq.Command) ([]byte, error) {
initialState := lp.state
if lp.state != stateConnected {
err := lp.Connect()
if err != nil {
return nil, err
}
lp.state = stateConnected
lp.Write(nsq.MagicV1)
if initialState == stateDisconnected {
lp.connectCallback(lp)
}
}
if cmd == nil {
return nil, nil
}
_, err := cmd.WriteTo(lp)
if err != nil {
lp.Close()
return nil, err
}
resp, err := readResponseBounded(lp, lp.maxBodySize)
if err != nil {
lp.Close()
return nil, err
}
return resp, nil
}
func readResponseBounded(r io.Reader, limit int64) ([]byte, error) {
var msgSize int32
// message size
err := binary.Read(r, binary.BigEndian, &msgSize)
if err != nil {
return nil, err
}
if int64(msgSize) > limit {
return nil, fmt.Errorf("response body size (%d) is greater than limit (%d)",
msgSize, limit)
}
// message binary data
buf := make([]byte, msgSize)
_, err = io.ReadFull(r, buf)
if err != nil {
return nil, err
}
return buf, nil
}
lookup_peer.go的更多相关文章
随机推荐
- Unity脚本编程之——协程(Coroutine)
本文翻译自Unity官方文档:https://docs.unity3d.com/Manual/Coroutines.html 专有名词: Coroutine 协程 Alpha 不透明度 当你调用一个函 ...
- 剑指offer面试题48: 最长不含重复字符的子字符串
Given a string, find the length of the longest substring without repeating characters.(请从子字符串中找出一个最长 ...
- jquery-取消冒泡
1.通过返回false来取消默认的行为并阻止事件起泡. jQuery 代码: $("form").bind( "submit", function() { re ...
- 通过jQuery源码学习javascript(三)
承接上两篇继续写下去.我尽量把我明白的地方给大家说清楚.有些大家的提问我也有点搞不明白,如果有人能解答,再好不过了 疑问 第一篇中有位博友提出了以下的问题,我也不太明白,如果有明白的,能否告知一.二 ...
- SystemJS to Webpack – Before You Begin
http://angularfirst.com/systemjs-to-webpack-before-you-begin/ This is a primer discussing why to mov ...
- Linux服务器安全审计工具与流程完全指南
http://Linux.chinaitlab.com/server/860516.html 当今许多linux服务器都不是刚刚部署完毕的新机器,有专业的Linux系统管理员进行定期维护,IT技术人员 ...
- Redis实现简单消息队列
http://www.jianshu.com/p/9c04890615ba 任务异步化 打开浏览器,输入地址,按下回车,打开了页面.于是一个HTTP请求(request)就由客户端发送到服务器,服务器 ...
- 安装Redis 编译make gcc: error trying to exec 'cc1': execvp: 没有该文件或目录的错误
Linux(Redhat) make: gcc: error trying to exec 'cc1': execvp: 没有该文件或目录的错误 排查错误: 1.检查gcc.gcc-c++是否安装rp ...
- 学习ASP.NET Core Razor 编程系列九——增加查询功能
学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...
- python 面向对象终极进阶之开发流程
好了,你现在会了面向对象的各种语法了, 但是你会发现很多同学都是学会了面向对象的语法,却依然写不出面向对象的程序,原因是什么呢?原因就是因为你还没掌握一门面向对象设计利器, 此刻有经验的人可能会想到 ...