~samwhited/xmpp

904ee96f0eff803df973e43351864919b816ead9 — Sam Whited 5 months ago 6fa1830
disco/info: new package containing disco features

Previously we had a disco.Feature type. However, packages may want to
provide their feature as a convenience to be easily registered in the
future. If they do this, we will create import loops between any
packages that are already imported by disco (ie. jid and paging). Moving
features out to its own info package will allow other packages to import
it without bringing in all of the disco package.

Signed-off-by: Sam Whited <sam@samwhited.com>
4 files changed, 99 insertions(+), 25 deletions(-)

M CHANGELOG.md
M disco/info.go
A disco/info/feature.go
A disco/info/feature_test.go
M CHANGELOG.md => CHANGELOG.md +5 -0
@@ 21,6 21,10 @@ All notable changes to this project will be documented in this file.

- all: update the default TLS config to disable TLS < 1.2

### Breaking

- disco: the `Feature` type moved to `info.Feature`


### Added



@@ 37,6 41,7 @@ All notable changes to this project will be documented in this file.
- stanza: add `Error` method to `Presence` and `Message`
- websocket: add `Negotiator` to replace the `WebSocket` option on the stream
  config
- disco/info: new package containing the former `disco.Feature` type


### Fixed

M disco/info.go => disco/info.go +4 -25
@@ 10,6 10,7 @@ import (

	"mellium.im/xmlstream"
	"mellium.im/xmpp"
	"mellium.im/xmpp/disco/info"
	"mellium.im/xmpp/form"
	"mellium.im/xmpp/internal/ns"
	"mellium.im/xmpp/jid"


@@ 80,34 81,12 @@ func (i Identity) WriteXML(w xmlstream.TokenWriter) (int, error) {
	return xmlstream.Copy(w, i.TokenReader())
}

// Feature represents a feature supported by an entity on the network.
type Feature struct {
	XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info feature"`
	Var     string   `xml:"var,attr"`
}

// TokenReader implements xmlstream.Marshaler.
func (f Feature) TokenReader() xml.TokenReader {
	return xmlstream.Wrap(nil, xml.StartElement{
		Name: xml.Name{Space: NSInfo, Local: "feature"},
		Attr: []xml.Attr{{
			Name:  xml.Name{Local: "var"},
			Value: f.Var,
		}},
	})
}

// WriteXML implements xmlstream.WriterTo.
func (f Feature) WriteXML(w xmlstream.TokenWriter) (int, error) {
	return xmlstream.Copy(w, f.TokenReader())
}

// Info is a response to a disco info query.
type Info struct {
	InfoQuery
	Identity []Identity `xml:"identity"`
	Features []Feature  `xml:"feature"`
	Form     *form.Data `xml:"jabber:x:data x,omitempty"`
	Identity []Identity     `xml:"identity"`
	Features []info.Feature `xml:"feature"`
	Form     *form.Data     `xml:"jabber:x:data x,omitempty"`
}

// TokenReader implements xmlstream.Marshaler.

A disco/info/feature.go => disco/info/feature.go +52 -0
@@ 0,0 1,52 @@
// Copyright 2021 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

// Package info contains service discovery features.
//
// These were separated out into a separate package to prevent import loops.
package info // import "mellium.im/xmpp/disco/info"

import (
	"encoding/xml"

	"mellium.im/xmlstream"
)

const (
	ns = `http://jabber.org/protocol/disco#info`
)

// Feature represents a feature supported by an entity on the network.
type Feature struct {
	XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info feature"`
	Var     string   `xml:"var,attr"`
}

// TokenReader implements xmlstream.Marshaler.
func (f Feature) TokenReader() xml.TokenReader {
	return xmlstream.Wrap(nil, xml.StartElement{
		Name: xml.Name{Space: ns, Local: "feature"},
		Attr: []xml.Attr{{
			Name:  xml.Name{Local: "var"},
			Value: f.Var,
		}},
	})
}

// WriteXML implements xmlstream.WriterTo.
func (f Feature) WriteXML(w xmlstream.TokenWriter) (int, error) {
	return xmlstream.Copy(w, f.TokenReader())
}

// MarshalXML implements xml.Marshaler.
func (f Feature) MarshalXML(e *xml.Encoder, _ xml.StartElement) error {
	_, err := f.WriteXML(e)
	return err
}

// FeatureIter is the interface implemented by types that implement disco
// features.
type FeatureIter interface {
	ForFeatures(node string, f func(Feature) error) error
}

A disco/info/feature_test.go => disco/info/feature_test.go +38 -0
@@ 0,0 1,38 @@
// Copyright 2021 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.

package info_test

import (
	"encoding/xml"
	"testing"

	"mellium.im/xmlstream"
	"mellium.im/xmpp/disco"
	"mellium.im/xmpp/disco/info"
	"mellium.im/xmpp/internal/xmpptest"
)

var (
	_ xml.Marshaler       = info.Feature{}
	_ xmlstream.Marshaler = info.Feature{}
	_ xmlstream.WriterTo  = info.Feature{}
)

func TestEncode(t *testing.T) {
	xmpptest.RunEncodingTests(t, []xmpptest.EncodingTestCase{
		0: {
			Value:       &info.Feature{},
			XML:         `<feature xmlns="http://jabber.org/protocol/disco#info" var=""></feature>`,
			NoUnmarshal: true,
		},
		1: {
			Value: &info.Feature{
				XMLName: xml.Name{Space: disco.NSInfo, Local: "feature"},
				Var:     "urn:example",
			},
			XML: `<feature xmlns="http://jabber.org/protocol/disco#info" var="urn:example"></feature>`,
		},
	})
}