github.com/sereiner/library@v0.0.0-20200518095232-1fa3e640cc5f/queue/xmq/xmq.producer.go (about)

     1  package xmq
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"sync"
     8  	"time"
     9  
    10  	"github.com/sereiner/library/encoding"
    11  	logger "github.com/sereiner/library/log"
    12  	"github.com/sereiner/library/mq"
    13  	"github.com/sereiner/library/queue"
    14  )
    15  
    16  //XMQProducer Producer
    17  type XMQProducer struct {
    18  	conf        *Conf
    19  	conn        net.Conn
    20  	connecting  bool
    21  	isConnected bool
    22  	closeCh     chan struct{}
    23  	done        bool
    24  	lk          sync.Mutex
    25  	writeLock   sync.Mutex
    26  	//	header      []string
    27  	lastWrite      time.Time
    28  	firstConnected bool
    29  	Logger         *logger.Logger
    30  }
    31  
    32  //New 创建新的producer
    33  func New(address []string, c string) (producer *XMQProducer, err error) {
    34  	producer = &XMQProducer{}
    35  	producer.closeCh = make(chan struct{})
    36  	producer.conf, err = NewConf(c)
    37  	if err != nil {
    38  		return nil, err
    39  	}
    40  	if producer.Logger == nil {
    41  		producer.Logger = logger.GetSession("xmq.queue", logger.CreateSession())
    42  	}
    43  	//	producer.header = make([]string, 0, 4)
    44  	return producer, producer.Connect()
    45  }
    46  
    47  //Connect  循环连接服务器
    48  func (producer *XMQProducer) Connect() error {
    49  	err := producer.connectOnce()
    50  	if err != nil {
    51  		producer.Logger.Error(err)
    52  	}
    53  	go func() {
    54  	START:
    55  		for {
    56  			select {
    57  			case <-producer.closeCh:
    58  				break START
    59  			case <-time.After(time.Second * 3):
    60  				if producer.done {
    61  					return
    62  				}
    63  				if producer.isConnected {
    64  					if time.Since(producer.lastWrite).Seconds() > 3 {
    65  						message, err := NewXMQHeartBit().MakeMessage()
    66  						if err != nil {
    67  							producer.Logger.Error(err)
    68  							continue
    69  						}
    70  						err = producer.writeMessage(message)
    71  						if err == nil {
    72  							continue
    73  						}
    74  						producer.Logger.Error(err)
    75  						err = producer.connectOnce()
    76  						if err != nil {
    77  							producer.Logger.Error(err)
    78  						}
    79  					}
    80  					continue
    81  				}
    82  				err = producer.connectOnce()
    83  				if err != nil {
    84  					producer.Logger.Error(err)
    85  				}
    86  
    87  			}
    88  		}
    89  	}()
    90  	return nil
    91  }
    92  
    93  func (producer *XMQProducer) writeMessage(msg string) error {
    94  	if !producer.isConnected {
    95  		return fmt.Errorf("未连接到服务器")
    96  	}
    97  	producer.writeLock.Lock()
    98  	defer producer.writeLock.Unlock()
    99  	producer.lastWrite = time.Now()
   100  	result, err := encoding.Decode(msg, "gbk")
   101  	if err != nil {
   102  		return err
   103  	}
   104  	_, err = producer.conn.Write(result)
   105  	producer.lastWrite = time.Now()
   106  	if err != nil {
   107  		producer.Logger.Warn("发送数据失败:", err)
   108  		//producer.disconnect()
   109  	}
   110  	return err
   111  }
   112  
   113  func (producer *XMQProducer) disconnect() {
   114  	producer.isConnected = false
   115  	if producer.conn == nil {
   116  		return
   117  	}
   118  	producer.conn.Close()
   119  	return
   120  }
   121  
   122  //reconnect 自动重连
   123  func (producer *XMQProducer) reconnect() {
   124  	producer.conn.Close()
   125  	producer.disconnect()
   126  	err := producer.Connect()
   127  	if err != nil {
   128  		producer.Logger.Errorf("连接到MQ服务器失败:%v", err)
   129  	}
   130  }
   131  
   132  //ConnectOnce 连接到服务器
   133  func (producer *XMQProducer) connectOnce() (err error) {
   134  	if producer.connecting {
   135  		return nil
   136  	}
   137  	producer.lk.Lock()
   138  	defer producer.lk.Unlock()
   139  	if producer.connecting {
   140  		return nil
   141  	}
   142  	producer.connecting = true
   143  	defer func() {
   144  		producer.connecting = false
   145  	}()
   146  	producer.isConnected = false
   147  	producer.conn, err = net.DialTimeout("tcp", producer.conf.Address, time.Second*2)
   148  	if err != nil {
   149  		return fmt.Errorf("mq 无法连接到远程服务器:%v", err)
   150  	}
   151  	if !producer.firstConnected {
   152  		producer.firstConnected = true
   153  	} else {
   154  		producer.Logger.Info("恢复连接:", producer.conf.Address)
   155  	}
   156  	producer.isConnected = true
   157  	producer.lastWrite = time.Now()
   158  	return nil
   159  }
   160  func (producer *XMQProducer) Push(queue string, msg string) error {
   161  	return producer.Send(queue, msg, time.Hour*1000)
   162  }
   163  
   164  func (producer *XMQProducer) Pop(key string) (string, error) {
   165  	return "", fmt.Errorf("not support")
   166  }
   167  func (producer *XMQProducer) Count(key string) (int64, error) {
   168  	return 0, nil
   169  }
   170  
   171  //Send 发送消息
   172  func (producer *XMQProducer) Send(queue string, msg string, timeout time.Duration) (err error) {
   173  	if producer.done {
   174  		return errors.New("mq producer 已关闭")
   175  	}
   176  	if !producer.isConnected {
   177  		return fmt.Errorf("producer无法连接到MQ服务器:%s", producer.conf.Address)
   178  	}
   179  	message := NewXMQMessage(queue, msg, int(timeout/time.Second))
   180  	if producer.conf.Key != "" {
   181  		message.signKey = producer.conf.Key
   182  	}
   183  	smessage, err := message.MakeMessage()
   184  	if err != nil {
   185  		return
   186  	}
   187  	pmsg := &mq.ProcuderMessage{Queue: queue, Data: smessage, Timeout: timeout}
   188  	return producer.writeMessage(pmsg.Data)
   189  }
   190  
   191  //Close 关闭当前连接
   192  func (producer *XMQProducer) Close() error {
   193  	producer.done = true
   194  	close(producer.closeCh)
   195  	return nil
   196  }
   197  
   198  type xmqResolver struct {
   199  }
   200  
   201  func (s *xmqResolver) Resolve(address []string, conf string) (queue.IQueue, error) {
   202  	return New(address, conf)
   203  }
   204  
   205  func init() {
   206  	queue.Register("xmq", &xmqResolver{})
   207  }