~samwhited/xmpp

fcf132e165a5cfbd52afea3dac5ac9fac8a9a708 — Sam Whited 1 year, 9 months ago 69e49f4
all: allow encoding structs from within handlers
M echobot_example_test.go => echobot_example_test.go +1 -1
@@ 55,7 55,7 @@ func Example_echobot() {
		return
	}

	s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
	s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
		d := xml.NewTokenDecoder(t)

		// Ignore anything that's not a message. In a real system we'd want to at

M examples/echobot/echo.go => examples/echobot/echo.go +1 -1
@@ 69,7 69,7 @@ func echo(ctx context.Context, addr, pass string, xmlIn, xmlOut io.Writer, logge
		return fmt.Errorf("Error sending initial presence: %w", err)
	}

	return s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
	return s.Serve(xmpp.HandlerFunc(func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
		d := xml.NewTokenDecoder(t)

		// Ignore anything that's not a message. In a real system we'd want to at

M examples/echobot/go.mod => examples/echobot/go.mod +1 -1
@@ 4,7 4,7 @@ go 1.13

require (
	mellium.im/sasl v0.2.1
	mellium.im/xmlstream v0.13.4
	mellium.im/xmlstream v0.13.5
	mellium.im/xmpp v0.0.0
)


M examples/echobot/go.sum => examples/echobot/go.sum +2 -2
@@ 17,5 17,5 @@ mellium.im/reader v0.1.0 h1:UUEMev16gdvaxxZC7fC08j7IzuDKh310nB6BlwnxTww=
mellium.im/reader v0.1.0/go.mod h1:F+X5HXpkIfJ9EE1zHQG9lM/hO946iYAmU7xjg5dsQHI=
mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w=
mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
mellium.im/xmlstream v0.13.4 h1:AN9dkVD9K/CHzp21IVKnKXYUCsBjCEsrPqW8k1/tgGw=
mellium.im/xmlstream v0.13.4/go.mod h1:O7wqreSmFi1LOh4RiK7r2j4H4pYDgzo1qv5ZkYJZ7Ns=
mellium.im/xmlstream v0.13.5 h1:Y3OBsAT3a5G2B9gEv7ia3SSaLykwFB9SWvRuwd+Fplw=
mellium.im/xmlstream v0.13.5/go.mod h1:O7wqreSmFi1LOh4RiK7r2j4H4pYDgzo1qv5ZkYJZ7Ns=

M go.mod => go.mod +1 -1
@@ 8,5 8,5 @@ require (
	golang.org/x/net v0.0.0-20190611141213-3f473d35a33a
	golang.org/x/text v0.3.2
	mellium.im/sasl v0.2.1
	mellium.im/xmlstream v0.13.4
	mellium.im/xmlstream v0.13.5
)

M go.sum => go.sum +2 -2
@@ 17,5 17,5 @@ mellium.im/reader v0.1.0 h1:UUEMev16gdvaxxZC7fC08j7IzuDKh310nB6BlwnxTww=
mellium.im/reader v0.1.0/go.mod h1:F+X5HXpkIfJ9EE1zHQG9lM/hO946iYAmU7xjg5dsQHI=
mellium.im/sasl v0.2.1 h1:nspKSRg7/SyO0cRGY71OkfHab8tf9kCts6a6oTDut0w=
mellium.im/sasl v0.2.1/go.mod h1:ROaEDLQNuf9vjKqE1SrAfnsobm2YKXT1gnN1uDp1PjQ=
mellium.im/xmlstream v0.13.4 h1:AN9dkVD9K/CHzp21IVKnKXYUCsBjCEsrPqW8k1/tgGw=
mellium.im/xmlstream v0.13.4/go.mod h1:O7wqreSmFi1LOh4RiK7r2j4H4pYDgzo1qv5ZkYJZ7Ns=
mellium.im/xmlstream v0.13.5 h1:Y3OBsAT3a5G2B9gEv7ia3SSaLykwFB9SWvRuwd+Fplw=
mellium.im/xmlstream v0.13.5/go.mod h1:O7wqreSmFi1LOh4RiK7r2j4H4pYDgzo1qv5ZkYJZ7Ns=

M handler.go => handler.go +3 -3
@@ 12,16 12,16 @@ import (

// A Handler triggers events or responds to incoming elements in an XML stream.
type Handler interface {
	HandleXMPP(t xmlstream.TokenReadWriter, start *xml.StartElement) error
	HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error
}

// The HandlerFunc type is an adapter to allow the use of ordinary functions as
// XMPP handlers.
// If f is a function with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(t xmlstream.TokenReadWriter, start *xml.StartElement) error
type HandlerFunc func(t xmlstream.TokenReadEncoder, start *xml.StartElement) error

// HandleXMPP calls f(t, start).
func (f HandlerFunc) HandleXMPP(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
func (f HandlerFunc) HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
	return f(t, start)
}

M handler_test.go => handler_test.go +5 -3
@@ 13,12 13,14 @@ var errHandlerFuncSentinal = errors.New("handler test")

type sentinalReadWriter struct{}

func (sentinalReadWriter) Token() (xml.Token, error)   { return nil, nil }
func (sentinalReadWriter) EncodeToken(xml.Token) error { return nil }
func (sentinalReadWriter) Token() (xml.Token, error)                         { return nil, nil }
func (sentinalReadWriter) EncodeToken(xml.Token) error                       { return nil }
func (sentinalReadWriter) Encode(interface{}) error                          { return nil }
func (sentinalReadWriter) EncodeElement(interface{}, xml.StartElement) error { return nil }

func TestHandlerFunc(t *testing.T) {
	s := &xml.StartElement{}
	var f xmpp.HandlerFunc = func(r xmlstream.TokenReadWriter, start *xml.StartElement) error {
	var f xmpp.HandlerFunc = func(r xmlstream.TokenReadEncoder, start *xml.StartElement) error {
		if _, ok := r.(sentinalReadWriter); !ok {
			t.Errorf("HandleXMPP did not pass reader to HandlerFunc")
		}

M mux/mux.go => mux/mux.go +2 -2
@@ 32,7 32,7 @@ type ServeMux struct {
	patterns map[xml.Name]xmpp.Handler
}

func fallback(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
func fallback(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
	if start.Name.Local != "iq" {
		return nil
	}


@@ 113,7 113,7 @@ func (m *ServeMux) Handler(name xml.Name) (h xmpp.Handler, ok bool) {

// HandleXMPP dispatches the request to the handler whose pattern most closely
// matches start.Name.
func (m *ServeMux) HandleXMPP(t xmlstream.TokenReadWriter, start *xml.StartElement) error {
func (m *ServeMux) HandleXMPP(t xmlstream.TokenReadEncoder, start *xml.StartElement) error {
	h, ok := m.Handler(start.Name)
	if ok {
		return h.HandleXMPP(t, start)

M mux/mux_test.go => mux/mux_test.go +16 -6
@@ 15,6 15,7 @@ import (

	"mellium.im/xmlstream"
	"mellium.im/xmpp"
	"mellium.im/xmpp/internal"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/internal/xmpptest"
	"mellium.im/xmpp/mux"


@@ 22,11 23,11 @@ import (

var passTest = errors.New("mux_test: PASSED")

var passHandler xmpp.HandlerFunc = func(xmlstream.TokenReadWriter, *xml.StartElement) error {
var passHandler xmpp.HandlerFunc = func(xmlstream.TokenReadEncoder, *xml.StartElement) error {
	return passTest
}

var failHandler xmpp.HandlerFunc = func(xmlstream.TokenReadWriter, *xml.StartElement) error {
var failHandler xmpp.HandlerFunc = func(xmlstream.TokenReadEncoder, *xml.StartElement) error {
	return errors.New("mux_test: FAILED")
}



@@ 87,6 88,18 @@ func TestMux(t *testing.T) {
	}
}

type testEncoder struct {
	xml.TokenReader
	xmlstream.TokenWriter
}

func (e testEncoder) Encode(v interface{}) error {
	return internal.EncodeXML(e.TokenWriter, v)
}
func (e testEncoder) EncodeElement(v interface{}, start xml.StartElement) error {
	return internal.EncodeXMLElement(e.TokenWriter, v, start)
}

func TestFallback(t *testing.T) {
	buf := &bytes.Buffer{}
	rw := struct {


@@ 107,10 120,7 @@ func TestFallback(t *testing.T) {
	start := tok.(xml.StartElement)
	w := s.TokenWriter()
	defer w.Close()
	err = mux.New().HandleXMPP(struct {
		xml.TokenReader
		xmlstream.TokenWriter
	}{
	err = mux.New().HandleXMPP(testEncoder{
		TokenReader: r,
		TokenWriter: w,
	}, &start)

M session.go => session.go +9 -1
@@ 310,7 310,7 @@ func (s *Session) sendError(err error) (e error) {

type nopHandler struct{}

func (nopHandler) HandleXMPP(_ xmlstream.TokenReadWriter, _ *xml.StartElement) error {
func (nopHandler) HandleXMPP(xmlstream.TokenReadEncoder, *xml.StartElement) error {
	return nil
}



@@ 480,6 480,14 @@ func (rw *responseChecker) EncodeToken(t xml.Token) error {
	return rw.TokenWriter.EncodeToken(t)
}

func (rw *responseChecker) Encode(v interface{}) error {
	return internal.EncodeXML(rw, v)
}

func (rw *responseChecker) EncodeElement(v interface{}, start xml.StartElement) error {
	return internal.EncodeXMLElement(rw, v, start)
}

// Feature checks if a feature with the given namespace was advertised
// by the server for the current stream. If it was data will be the canonical
// representation of the feature as returned by the feature's Parse function.

M session_test.go => session_test.go +8 -8
@@ 156,7 156,7 @@ var serveTests = [...]struct {
		out: invalidIQ + `</stream:stream>`,
	},
	3: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			_, err := xmlstream.Copy(rw, stanza.WrapIQ(stanza.IQ{
				ID:   "1234",
				Type: stanza.ResultIQ,


@@ 167,7 167,7 @@ var serveTests = [...]struct {
		out: `<iq type="result" id="1234"></iq></stream:stream>`,
	},
	4: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			_, err := xmlstream.Copy(rw, stanza.WrapIQ(stanza.IQ{
				ID:   "wrongid",
				Type: stanza.ResultIQ,


@@ 178,7 178,7 @@ var serveTests = [...]struct {
		out: `<iq type="result" id="wrongid"></iq>` + invalidIQ + `</stream:stream>`,
	},
	5: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			_, err := xmlstream.Copy(rw, stanza.WrapIQ(stanza.IQ{
				ID:   "1234",
				Type: stanza.ErrorIQ,


@@ 189,7 189,7 @@ var serveTests = [...]struct {
		out: `<iq type="error" id="1234"></iq></stream:stream>`,
	},
	6: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			_, err := xmlstream.Copy(rw, stanza.WrapIQ(stanza.IQ{
				ID:   "1234",
				Type: stanza.GetIQ,


@@ 200,7 200,7 @@ var serveTests = [...]struct {
		out: `<iq type="get" id="1234"></iq>` + invalidIQ + `</stream:stream>`,
	},
	7: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			for _, attr := range start.Attr {
				if attr.Name.Local == "from" && attr.Value != "" {
					panic("expected attr to be normalized")


@@ 212,7 212,7 @@ var serveTests = [...]struct {
		out: `</stream:stream>`,
	},
	8: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			for _, attr := range start.Attr {
				if attr.Name.Local == "from" && attr.Value == "" {
					panic("expected attr not to be normalized")


@@ 224,7 224,7 @@ var serveTests = [...]struct {
		out: `</stream:stream>`,
	},
	9: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			for _, attr := range start.Attr {
				if attr.Name.Local == "from" && attr.Value == "" {
					panic("expected attr not to be normalized")


@@ 236,7 236,7 @@ var serveTests = [...]struct {
		out: `</stream:stream>`,
	},
	10: {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadWriter, start *xml.StartElement) error {
		handler: xmpp.HandlerFunc(func(rw xmlstream.TokenReadEncoder, start *xml.StartElement) error {
			for _, attr := range start.Attr {
				if attr.Name.Local == "from" && attr.Value == "" {
					panic("expected attr not to be normalized")