Ejemplo n.º 1
0
func (self *Handler) Pubrec(messageId uint16) {
	ack := codec.NewPubrelMessage()
	ack.PacketIdentifier = messageId

	self.Connection.WriteMessageQueue(ack)
	self.Connection.GetOutGoingTable().Unref(messageId)
}
Ejemplo n.º 2
0
func (self *DummyPlug) Run() {
	for {
		select {
		case <-self.stop:
			return
		case b := <-self.Switch:
			self.Running = b
		case m := <-self.message:
			if self.Running {
				// メッセージが来たらengineのAPIをたたけばOK
				switch m.GetType() {
				case mqtt.PACKET_TYPE_CONNECT:
				case mqtt.PACKET_TYPE_CONNACK:
				case mqtt.PACKET_TYPE_PUBLISH:
					// TODO:
					if p, ok := m.(*mqtt.PublishMessage); ok {
						fmt.Printf("%s\n", p)
						switch p.QosLevel {
						case 1:
							log.Debug("[DUMMY] Received Publish Message from [%d]. reply puback", p.PacketIdentifier)
							self.engine.OutGoingTable.Unref(p.PacketIdentifier)
						case 2:
							log.Debug("[DUMMY] Received Publish Message from [%d]. reply pubrec", p.PacketIdentifier)
							self.engine.OutGoingTable.Unref(p.PacketIdentifier)
							rel := mqtt.NewPubrelMessage()
							rel.PacketIdentifier = p.PacketIdentifier
							// NOTE: client have to reply pubrec to the server
							self.message <- rel
						}
					}
				case mqtt.PACKET_TYPE_DISCONNECT:
					// TODO: なの?
				case mqtt.PACKET_TYPE_SUBSCRIBE:
				case mqtt.PACKET_TYPE_SUBACK:
				case mqtt.PACKET_TYPE_UNSUBSCRIBE:
				case mqtt.PACKET_TYPE_UNSUBACK:
				case mqtt.PACKET_TYPE_PINGRESP:
				case mqtt.PACKET_TYPE_PINGREQ:
				case mqtt.PACKET_TYPE_PUBACK:
					// TODO: (nothign to do)
				case mqtt.PACKET_TYPE_PUBREC:
					// TODO: (nothign to do)
				case mqtt.PACKET_TYPE_PUBREL:
					// TODO:
					if p, ok := m.(*mqtt.PubrelMessage); ok {
						log.Debug("[DUMMY] Received Pubrel Message from [%d]. send pubcomp", p.PacketIdentifier)
						self.engine.OutGoingTable.Unref(p.PacketIdentifier)

						cmp := mqtt.NewPubcompMessage()
						cmp.PacketIdentifier = p.PacketIdentifier
						// NOTE: client have to reply pubcomp to the server
						self.message <- cmp
					}
				case mqtt.PACKET_TYPE_PUBCOMP:
					// TODO: (nothing)
				default:
					return
				}
			} else {
				// discards message
			}
		}
	}
}
Ejemplo n.º 3
0
// TODO: どっかで綺麗にしたい
func NewMyConnection(conf *MyConfig) *MyConnection {
	if conf == nil {
		conf = &defaultConfig
	}

	c := &MyConnection{
		Events:           make(map[string]interface{}),
		Queue:            make(chan codec.Message, conf.QueueSize),
		OfflineQueue:     make([]codec.Message, 0),
		MaxOfflineQueue:  conf.OfflineQueueSize,
		InflightTable:    util.NewMessageTable(),
		SubscribeHistory: make(map[string]int),
		Mutex:            sync.RWMutex{},
		Qlobber:          util.NewQlobber(),
		SubscribedTopics: make(map[string]int),
		Last:             time.Now(),
		CleanSession:     true,
		Keepalive:        conf.Keepalive,
		State:            STATE_INIT,
		Closed:           make(chan bool),
		MaxMessageSize:   conf.MaxMessageSize,
		fch:              make(chan bool, 1),
	}

	c.t = time.AfterFunc(time.Second*300, func() {
		// NOTE: assume flush
		if c.State == STATE_CONNECTED {
			c.kickFlusher()
		}
	})

	c.logger = log.Global
	if conf.Logger != nil {
		c.logger = conf.Logger
	}

	if conf.WritePerSec > 0 {
		c.balancer = &util.Balancer{
			PerSec: conf.WritePerSec,
		}
	}
	if conf.MaxMessageSize > 0 {
		c.MaxMessageSize = conf.MaxMessageSize
	}

	c.Events["connected"] = func() {
		c.State = STATE_CONNECTED
	}

	c.Events["connack"] = func(result uint8) {
		if result == 0 {
			c.SetState(STATE_CONNECTED)
			if c.Reconnect {
				for key, qos := range c.SubscribeHistory {
					c.Subscribe(key, qos)
				}
			}

			//TODO: このアホっぽい実装はあとでちゃんとなおす。なおしたい
			if len(c.OfflineQueue) > 0 {
				c.Mutex.Lock()
				var targets []codec.Message
				for len(c.OfflineQueue) > 0 {
					targets = append(targets, c.OfflineQueue[0])
					c.OfflineQueue = c.OfflineQueue[1:]
				}
				c.Mutex.Unlock()

				for i := 0; i < len(targets); i++ {
					c.Queue <- targets[i]
				}
			}
			c.setupKicker()
		} else {
			c.State = STATE_CLOSED
		}
	}

	// for Wait API
	c.InflightTable.SetOnFinish(func(id uint16, message codec.Message, opaque interface{}) {
		if m, ok := message.(*codec.PublishMessage); ok {
			if m.QosLevel == 1 {
				if b, ok := opaque.(chan bool); ok {
					close(b)
				}
			} else if m.QosLevel == 2 {
				if b, ok := opaque.(chan bool); ok {
					close(b)
				}
			}
		}
	})

	// こっちに集約できるとClientが薄くなれる
	c.Events["publish"] = func(msg *codec.PublishMessage) {
		if msg.QosLevel == 1 {
			ack := codec.NewPubackMessage()
			ack.PacketIdentifier = msg.PacketIdentifier
			c.WriteMessageQueue(ack)
			c.logger.Debug("Send puback message to sender. [%s: %d]", c.GetId(), ack.PacketIdentifier)
		} else if msg.QosLevel == 2 {
			ack := codec.NewPubrecMessage()
			ack.PacketIdentifier = msg.PacketIdentifier
			c.WriteMessageQueue(ack)
			c.logger.Debug("Send pubrec message to sender. [%s: %d]", c.GetId(), ack.PacketIdentifier)
		}
	}

	c.Events["puback"] = func(messageId uint16) {
		c.InflightTable.Unref(messageId)
	}

	c.Events["pubrec"] = func(messageId uint16) {
		ack := codec.NewPubrelMessage()
		ack.PacketIdentifier = messageId
		c.Queue <- ack
	}

	c.Events["pubrel"] = func(messageId uint16) {
		ack := codec.NewPubcompMessage()
		ack.PacketIdentifier = messageId
		c.Queue <- ack

		c.InflightTable.Unref(ack.PacketIdentifier) // Unackknowleged
	}

	c.Events["pubcomp"] = func(messageId uint16) {
		c.InflightTable.Unref(messageId)
	}

	c.Events["unsuback"] = func(messageId uint16) {
		mm, err := c.InflightTable.Get(messageId)
		if err == nil {
			if v, ok := mm.(*codec.UnsubscribeMessage); ok {
				delete(c.SubscribeHistory, v.TopicName)
			}
		}

		c.InflightTable.Remove(messageId)
	}

	c.Events["subscribe"] = func(p *codec.SubscribeMessage) {
	}

	c.Events["suback"] = func(messageId uint16, grunted int) {
		c.InflightTable.Remove(messageId)
	}

	c.Events["unsubscribe"] = func(messageId uint16, granted int, payload []codec.SubscribePayload) {
		for i := 0; i < len(payload); i++ {
			delete(c.SubscribeHistory, payload[i].TopicPath)
		}
	}

	// これはコネクション渡したほうがいいんではないだろうか。
	c.Events["pingreq"] = func() {
		// TODO: check Ping count periodically, abort MyConnection when the counter exceeded.
		c.PingCounter++
	}

	c.Events["pingresp"] = func() {
		// nothing to do.
		c.PingCounter--
	}

	c.Events["disconnect"] = func() {
		// nothing to do ?
		c.State = STATE_CLOSED
	}

	c.Events["error"] = func(err error) {
		//fmt.Printf("Error: %s\n", err)
	}

	c.Events["connect"] = func(msg *codec.ConnectMessage) {
	}

	c.Events["parsed"] = func() {
	}

	// Write Queue
	go func() {
		for {
			select {
			case msg := <-c.Queue:
				state := c.GetState()
				if state == STATE_CONNECTED || state == STATE_CONNECTING {
					if msg.GetType() == codec.PACKET_TYPE_PUBLISH {
						sb := msg.(*codec.PublishMessage)
						if sb.QosLevel < 0 {
							c.logger.Error("QoS under zero. %s: %#v", c.Id, sb)
							break
						}

						if sb.QosLevel > 0 {
							id := c.InflightTable.NewId()
							sb.PacketIdentifier = id
							c.InflightTable.Register(id, sb, nil)
						}
					}

					e := c.writeMessage(msg)
					if e != nil {
						if v, ok := c.Events["error"].(func(error)); ok {
							v(e)
						}
					}
					c.invalidateTimer()
				} else {
					c.OfflineQueue = append(c.OfflineQueue, msg)
				}
			case <-c.Closed:
				if c.KeepLoop {
					time.Sleep(time.Second)
				} else {
					return
				}
			}
		}
	}()
	go c.flusher()
	return c
}