package session import ( "fmt" "log" "badat.dev/maeqtt/v2/mqtt/packets" ) type Session struct { ClientID *string // Nullable Connection *Connection SubscriptionChannel chan packets.PublishPacket ConnecionChannel chan ConnectionRequest freePacketID uint16 Expiry } func NewSession(req ConnectionRequest, rmSessChan RemoveSessionChannel) Session { sess := Session{} sess.SubscriptionChannel = make(chan packets.PublishPacket) sess.ConnecionChannel = make(chan ConnectionRequest) sess.Expiry = NewExpiry(rmSessChan) sess.Connect(req) return sess } func (s *Session) Connect(req ConnectionRequest) { s.stopExpireTimer() if s.Connection != nil { s.Disconnect(packets.DisconnectReasonCodeSessionTakenOver) } connAck := packets.ConnackPacket{} s.SetExpireTimerDuration(req.ConnectPakcet.Properties.SessionExpiryInterval.Value) if req.ConnectPakcet.ClientId == nil { if s.ClientID == nil { s.ClientID = genClientID() } connAck.Properties.AssignedClientIdentifier.Value = s.ClientID } else if s.ClientID != nil && *s.ClientID != *req.ConnectPakcet.ClientId { panic(fmt.Errorf("Session %s connect called with a connect packet with an ID: %s", *s.ClientID, *req.ConnectPakcet.ClientId)) } else { s.ClientID = req.ConnectPakcet.ClientId } true := byte(1) false := byte(0) connAck.Properties.WildcardSubscriptionAvailable.Value = &true connAck.Properties.RetainAvailable.Value = &false connAck.Properties.SharedSubscriptionAvailable.Value = &false s.Connection = req.Connection _ = s.Connection.sendPacket(connAck) go s.Connection.PacketReadLoop() } // Starts a loop the receives and responds to packets func (s *Session) HandlerLoop() { for { var packetChan chan packets.ClientPacket if s.Connection != nil { packetChan = s.Connection.PacketChannel } select { case packet, more := <-packetChan: if more { packet.Visit(s) } else { s.onDisconnect() } case c := <-s.ConnecionChannel: s.Connect(c) case <-s.expiryChannel(): s.expireSession() break case subMessage := <-s.SubscriptionChannel: if s.Connection != nil { // TODO implement other qos levels subMessage.QOSLevel = 0 subMessage.Dup = false err := s.Connection.sendPacket(subMessage) if err != nil { panic("TOOO handle this") } } } } } func (s *Session) onDisconnect() { s.Connection = nil s.startExpireTimer() log.Printf("Client disconnected, id: %s", *s.ClientID) }