// HandleMessagingEvent handles an event, called in the handler goroutine. func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MStart: h.injecter = e.Injecter() case proton.MLinkOpening: if e.Link().IsReceiver() { h.startReceiver(e) } else { h.startSender(e) } case proton.MLinkClosed: h.linkClosed(e.Link(), e.Link().RemoteCondition().Error()) case proton.MSendable: if s, ok := h.senders[e.Link()]; ok { s.sendable() // Signal the send goroutine that we have credit. } else { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s sender not found", e.Link())) } case proton.MMessage: m, err := e.Delivery().Message() // Message() must be called while handling the MMessage event. if err != nil { proton.CloseError(e.Link(), err) break } r, ok := h.receivers[e.Link()] if !ok { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s receiver not found", e.Link())) break } // This will not block as AMQP credit is set to the buffer capacity. r.buffer <- receivedMessage{e.Delivery(), m} util.Debugf("link %s received %s", e.Link(), util.FormatMessage(m)) case proton.MConnectionClosed, proton.MDisconnected: for l, _ := range h.receivers { h.linkClosed(l, nil) } for l, _ := range h.senders { h.linkClosed(l, nil) } } }
func (h *handler) incoming(in Incoming) { var err error if h.connection.incoming != nil { h.connection.incoming <- in err = in.wait() } else { err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s", in.pEndpoint().Type(), in.pEndpoint().String()) } if err == nil { in.pEndpoint().Open() } else { proton.CloseError(in.pEndpoint(), err) } }
func (h *handler) incoming(in Incoming) { var err error if h.connection.incoming != nil { h.connection.incoming <- in // Must block until accept/reject, subsequent events may use the incoming endpoint. err = in.wait() } else { err = amqp.Errorf(amqp.NotAllowed, "rejected incoming %s %s", in.pEndpoint().Type(), in.pEndpoint().String()) } if err == nil { in.pEndpoint().Open() } else { proton.CloseError(in.pEndpoint(), err) } }
// Call in proton goroutine to initiate closing an endpoint locally // handler will complete the close when remote end closes. func localClose(ep proton.Endpoint, err error) { if ep.State().LocalActive() { proton.CloseError(ep, err) } }
func (h *handler) linkError(l proton.Link, msg string) { proton.CloseError(l, amqp.Errorf(amqp.InternalError, "%s for %s %s", msg, l.Type(), l)) }
func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MMessage: if r, ok := h.links[e.Link()].(*receiver); ok { r.message(e.Delivery()) } else { h.internalError(e.Link(), "no receiver for link") } case proton.MSettled: if sm := h.sentMessages[e.Delivery()]; sm != nil { sm.settled(nil) } case proton.MSendable: if s, ok := h.links[e.Link()].(*sender); ok { s.sendable() } else { h.internalError(e.Link(), "no sender for link") } case proton.MSessionOpening: if e.Session().State().LocalUninit() { // Remotely opened incoming := &IncomingSession{h: h, pSession: e.Session()} h.connection.accept(incoming) if err := incoming.error("rejected session %s", e.Session()); err != nil { proton.CloseError(e.Session(), err) } } case proton.MSessionClosed: err := proton.EndpointError(e.Session()) for l, _ := range h.links { if l.Session() == e.Session() { h.linkClosed(l, err) } } delete(h.sessions, e.Session()) case proton.MLinkOpening: l := e.Link() if l.State().LocalActive() { // Already opened locally. break } ss := h.sessions[l.Session()] if ss == nil { h.internalError(e.Link(), "no session for link") break } var incoming Incoming if l.IsReceiver() { incoming = &IncomingReceiver{makeIncomingLink(ss, l)} } else { incoming = &IncomingSender{makeIncomingLink(ss, l)} } h.connection.accept(incoming) if err := incoming.error("rejected link %s", e.Link()); err != nil { proton.CloseError(l, err) break } case proton.MLinkClosing: e.Link().Close() case proton.MLinkClosed: h.linkClosed(e.Link(), proton.EndpointError(e.Link())) case proton.MConnectionClosing: h.connection.err.Set(e.Connection().RemoteCondition().Error()) case proton.MConnectionClosed: h.connection.err.Set(Closed) // If no error already set, this is an orderly close. case proton.MDisconnected: h.connection.err.Set(e.Transport().Condition().Error()) // If err not set at this point (e.g. to Closed) then this is unexpected. h.connection.err.Set(amqp.Errorf(amqp.IllegalState, "unexpected disconnect on %s", h.connection)) err := h.connection.Error() for l, _ := range h.links { h.linkClosed(l, err) } for _, s := range h.sessions { s.closed(err) } for _, sm := range h.sentMessages { sm.settled(err) } } }
func (h *handler) internalError(ep proton.Endpoint, msg string) { proton.CloseError(ep, amqp.Errorf(amqp.InternalError, "%s %s", msg, ep)) }
func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MMessage: if r, ok := h.links[e.Link()].(*receiver); ok { r.handleDelivery(e.Delivery()) } else { h.connection.closed( amqp.Errorf(amqp.InternalError, "cannot find receiver for link %s", e.Link())) } case proton.MSettled: if sm := h.sentMessages[e.Delivery()]; sm != nil { sm.settled(nil) } case proton.MSessionOpening: if e.Session().State().LocalUninit() { // Remotely opened s := newSession(h.connection, e.Session()) h.sessions[e.Session()] = s if h.connection.incoming != nil { h.connection.incoming.In <- s } else { proton.CloseError(e.Session(), amqp.Errorf(amqp.NotAllowed, "remote sessions not allowed")) } } case proton.MSessionClosing: e.Session().Close() case proton.MSessionClosed: err := e.Session().RemoteCondition().Error() for l, _ := range h.links { if l.Session() == e.Session() { h.linkClosed(l, err) } } delete(h.sessions, e.Session()) case proton.MLinkOpening: l := e.Link() if l.State().LocalUninit() { // Remotely opened if h.connection.incoming == nil { proton.CloseError(l, amqp.Errorf(amqp.NotAllowed, ("no remote links"))) break } s := h.sessions[l.Session()] if s == nil { proton.CloseError( l, amqp.Errorf(amqp.InternalError, ("cannot find session for link"))) break } h.connection.handleIncoming(s, l) } case proton.MLinkClosing: e.Link().Close() case proton.MLinkClosed: h.linkClosed(e.Link(), e.Link().RemoteCondition().Error()) case proton.MDisconnected: err := h.connection.Error() for l, _ := range h.links { h.linkClosed(l, err) } for _, s := range h.sessions { s.closed(err) } for _, sm := range h.sentMessages { sm.settled(err) } } }