mirror of
https://github.com/zgwit/beeq.git
synced 2025-09-27 03:55:59 +08:00
290 lines
6.1 KiB
Go
290 lines
6.1 KiB
Go
package beeq
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"github.com/zgwit/beeq/packet"
|
|
"log"
|
|
"net"
|
|
"time"
|
|
)
|
|
|
|
type Bee struct {
|
|
clientId string
|
|
session *Session
|
|
|
|
conn net.Conn
|
|
|
|
hive *Hive
|
|
|
|
quit chan struct{}
|
|
events chan *Event
|
|
|
|
timeout time.Duration
|
|
|
|
alive bool
|
|
}
|
|
|
|
func NewBee(conn net.Conn, hive *Hive) *Bee {
|
|
return &Bee{
|
|
conn: conn,
|
|
hive: hive,
|
|
quit: make(chan struct{}),
|
|
events: make(chan *Event, 1024),
|
|
timeout: time.Hour * 24,
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) Event(event *Event) {
|
|
bee.events <- event
|
|
}
|
|
|
|
func (bee *Bee) Active() {
|
|
bee.alive = true
|
|
|
|
go bee.receiver()
|
|
go bee.messenger()
|
|
}
|
|
|
|
func (bee *Bee) Shutdown() {
|
|
bee.alive = false
|
|
|
|
// Tell hive delete me
|
|
bee.hive.Event(NewEvent(E_LOST_CONN, nil, bee))
|
|
|
|
// Stop messenger
|
|
close(bee.events)
|
|
close(bee.quit)
|
|
}
|
|
|
|
func (bee *Bee) recv(b []byte) (int, error) {
|
|
err := bee.conn.SetReadDeadline(time.Now().Add(bee.timeout))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return bee.conn.Read(b)
|
|
}
|
|
|
|
func (bee *Bee) send(b []byte) (int, error) {
|
|
err := bee.conn.SetWriteDeadline(time.Now().Add(bee.timeout))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return bee.conn.Write(b)
|
|
}
|
|
|
|
func (bee *Bee) receiver() {
|
|
|
|
//Abort error
|
|
defer func() {
|
|
if r := recover(); r!=nil {
|
|
log.Print("bee receiver panic ", r)
|
|
bee.Shutdown()
|
|
}
|
|
}()
|
|
|
|
readHead := true
|
|
buf := Alloc(6)
|
|
offset := 0
|
|
total := 0
|
|
for {
|
|
if l, err := bee.recv(buf[offset:]); err != nil {
|
|
log.Print("Receive Failed: ", err)
|
|
break
|
|
} else {
|
|
offset += l
|
|
}
|
|
|
|
//Parse head
|
|
if readHead && offset >= 2 {
|
|
for i := 1; i <= offset; i++ {
|
|
if buf[i] < 0x80 {
|
|
rl, rll := binary.Uvarint(buf[1:])
|
|
remainLength := int(rl)
|
|
total = remainLength + rll + 1
|
|
if total > 6 {
|
|
buf = ReAlloc(buf, total)
|
|
}
|
|
readHead = false
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
//Parse Message
|
|
if !readHead && offset >= total {
|
|
readHead = true
|
|
b := Alloc(6)
|
|
if msg, l, err := packet.Decode(buf); err != nil {
|
|
//TODO log err
|
|
log.Print(err)
|
|
offset = 0 //clear data
|
|
} else {
|
|
bee.Event(NewEvent(E_MESSAGE, msg, bee))
|
|
//Only message less than 6 bytes
|
|
if offset > l {
|
|
copy(b, buf[l:])
|
|
offset -= l
|
|
} else {
|
|
offset = 0 //clear data
|
|
}
|
|
}
|
|
buf = b
|
|
}
|
|
}
|
|
|
|
//Shutdown bee
|
|
if bee.alive {
|
|
bee.Shutdown()
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) messenger() {
|
|
|
|
//Abort error
|
|
defer func() {
|
|
if r := recover(); r!=nil {
|
|
log.Print("bee messenger panic ", r)
|
|
bee.Shutdown()
|
|
}
|
|
}()
|
|
|
|
for {
|
|
//Blocking
|
|
var event *Event
|
|
|
|
select {
|
|
case <-bee.quit:
|
|
bee.conn.Close()
|
|
return
|
|
case event = <-bee.events:
|
|
switch event.event {
|
|
case E_MESSAGE:
|
|
bee.handleMessage(event.data.(packet.Message))
|
|
case E_DISPATCH:
|
|
bee.dispatchMessage(event.data.(packet.Message))
|
|
case E_CLOSE:
|
|
bee.Shutdown()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) handleMessage(msg packet.Message) {
|
|
log.Printf("Received message from %s: %s QOS(%d) DUP(%t) RETAIN(%t)", bee.clientId, msg.Type().Name(), msg.Qos(), msg.Dup(), msg.Retain())
|
|
//log.Print("recv Message:", msg.Type().Name())
|
|
switch msg.Type() {
|
|
case packet.CONNECT:
|
|
bee.handleConnect(msg.(*packet.Connect))
|
|
case packet.PUBLISH:
|
|
bee.handlePublish(msg.(*packet.Publish))
|
|
case packet.PUBACK:
|
|
bee.handlePubAck(msg.(*packet.PubAck))
|
|
case packet.PUBREC:
|
|
bee.handlePubRec(msg.(*packet.PubRec))
|
|
case packet.PUBREL:
|
|
bee.handlePubRel(msg.(*packet.PubRel))
|
|
case packet.PUBCOMP:
|
|
bee.handlePubComp(msg.(*packet.PubComp))
|
|
case packet.SUBSCRIBE:
|
|
bee.handleSubscribe(msg.(*packet.Subscribe))
|
|
case packet.UNSUBSCRIBE:
|
|
bee.handleUnSubscribe(msg.(*packet.UnSubscribe))
|
|
case packet.PINGREQ:
|
|
bee.handlePingReq(msg.(*packet.PingReq))
|
|
case packet.DISCONNECT:
|
|
bee.handleDisconnect(msg.(*packet.DisConnect))
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) handleConnect(msg *packet.Connect) {
|
|
bee.clientId = string(msg.ClientId())
|
|
|
|
//if msg.WillFlag() {
|
|
// bee.session.will = new(packet.Publish)
|
|
//}
|
|
bee.hive.Event(NewEvent(E_CONNECT, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handlePublish(msg *packet.Publish) {
|
|
qos := msg.Qos()
|
|
if qos == packet.Qos0 {
|
|
bee.hive.Event(NewEvent(E_PUBLISH, msg, bee))
|
|
} else if qos == packet.Qos1 {
|
|
bee.hive.Event(NewEvent(E_PUBLISH, msg, bee))
|
|
//Reply PUBACK
|
|
puback := packet.PUBACK.NewMessage().(*packet.PubAck)
|
|
puback.SetPacketId(msg.PacketId())
|
|
bee.Event(NewEvent(E_DISPATCH, puback, bee))
|
|
} else if qos == packet.Qos2 {
|
|
//Save & Send PUBREC
|
|
bee.session.recvPub2[msg.PacketId()] = msg
|
|
pubrec := packet.PUBREC.NewMessage().(*packet.PubRec)
|
|
pubrec.SetPacketId(msg.PacketId())
|
|
bee.Event(NewEvent(E_DISPATCH, pubrec, bee))
|
|
} else {
|
|
//error
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) handlePubAck(msg *packet.PubAck) {
|
|
if _, ok := bee.session.pub1[msg.PacketId()]; ok {
|
|
delete(bee.session.pub1, msg.PacketId())
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) handlePubRec(msg *packet.PubRec) {
|
|
msg.SetType(packet.PUBREL)
|
|
bee.Event(NewEvent(E_DISPATCH, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handlePubRel(msg *packet.PubRel) {
|
|
msg.SetType(packet.PUBCOMP)
|
|
bee.Event(NewEvent(E_DISPATCH, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handlePubComp(msg *packet.PubComp) {
|
|
if _, ok := bee.session.pub2[msg.PacketId()]; ok {
|
|
delete(bee.session.pub2, msg.PacketId())
|
|
}
|
|
}
|
|
|
|
func (bee *Bee) handleSubscribe(msg *packet.Subscribe) {
|
|
bee.hive.Event(NewEvent(E_SUBSCRIBE, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handleUnSubscribe(msg *packet.UnSubscribe) {
|
|
bee.hive.Event(NewEvent(E_UNSUBSCRIBE, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handlePingReq(msg *packet.PingReq) {
|
|
msg.SetType(packet.PINGRESP)
|
|
bee.Event(NewEvent(E_DISPATCH, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) handleDisconnect(msg *packet.DisConnect) {
|
|
bee.hive.Event(NewEvent(E_DISCONNECT, msg, bee))
|
|
}
|
|
|
|
func (bee *Bee) dispatchMessage(msg packet.Message) {
|
|
log.Printf("Send message to %s: %s QOS(%d) DUP(%t) RETAIN(%t)", bee.clientId, msg.Type().Name(), msg.Qos(), msg.Dup(), msg.Retain())
|
|
if head, payload, err := msg.Encode(); err != nil {
|
|
//TODO log
|
|
log.Print("Message encode error: ", err)
|
|
} else {
|
|
bee.send(head)
|
|
if payload != nil && len(payload) > 0 {
|
|
bee.send(payload)
|
|
}
|
|
}
|
|
|
|
if msg.Type() == packet.PUBLISH {
|
|
pub := msg.(*packet.Publish)
|
|
//Publish Qos1 Qos2 Need store
|
|
if msg.Qos() == packet.Qos1 {
|
|
bee.session.pub1[pub.PacketId()] = pub
|
|
} else if msg.Qos() == packet.Qos2 {
|
|
bee.session.pub2[pub.PacketId()] = pub
|
|
}
|
|
}
|
|
}
|