diff --git a/client.go b/client.go
index defa642..08ee804 100644
--- a/client.go
+++ b/client.go
@@ -127,6 +127,7 @@ func (c *Client) Recv() <-chan interface{} {
}
// Send sends message text.
+// TODO Move to Go XML Marshaller
func (c *Client) Send(packet string) error {
fmt.Fprintf(c.Session.socketProxy, packet) // TODO handle errors
return nil
diff --git a/cmd/xmpp_component/xmpp_component.go b/cmd/xmpp_component/xmpp_component.go
index e2126d1..01a222a 100644
--- a/cmd/xmpp_component/xmpp_component.go
+++ b/cmd/xmpp_component/xmpp_component.go
@@ -58,20 +58,21 @@ func (c MyComponent) processIQ(iqType, id, from string, inner *xmpp.Node) {
switch inner.XMLName.Space + " " + iqType {
case NSDiscoInfo + " get":
fmt.Println("Send Disco Info")
- result := fmt.Sprintf(`
-
-
-
-
-
-`, c.xmpp.Host, from, id, c.Category, c.Type, c.Name)
- c.xmpp.Send(result)
+
+ iq := xmpp.NewIQ("result", "admin@localhost", "test@localhost", "1", "en")
+ payload := xmpp.DiscoInfo{
+ Identity: xmpp.Identity{
+ Name: "Test Gateway",
+ Category: "gateway",
+ Type: "mqtt",
+ },
+ Features: []xmpp.Feature{
+ {Var: "http://jabber.org/protocol/disco#info"},
+ {Var: "http://jabber.org/protocol/disco#item"},
+ },
+ }
+ iq.AddPayload(&payload)
+ c.xmpp.Send(iq)
default:
iqErr := fmt.Sprintf(`
`, c.xmpp.Host, from, id)
- c.xmpp.Send(iqErr)
+ c.xmpp.SendOld(iqErr) // FIXME Remove that method
}
}
diff --git a/component.go b/component.go
index aa5d8d0..750bfc9 100644
--- a/component.go
+++ b/component.go
@@ -94,7 +94,19 @@ func (c *Component) ReadPacket() (Packet, error) {
return next(c.decoder)
}
-func (c *Component) Send(packet string) error {
+func (c *Component) Send(packet Packet) error {
+ data, err := xml.Marshal(packet)
+ if err != nil {
+ return errors.New("cannot marshal packet " + err.Error())
+ }
+
+ if _, err := fmt.Fprintf(c.conn, string(data)); err != nil {
+ return errors.New("cannot send packet " + err.Error())
+ }
+ return nil
+}
+
+func (c *Component) SendOld(packet string) error {
if _, err := fmt.Fprintf(c.conn, packet); err != nil {
return errors.New("cannot send packet " + err.Error())
}
diff --git a/iq.go b/iq.go
index 695df48..69e04c4 100644
--- a/iq.go
+++ b/iq.go
@@ -152,7 +152,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if err != nil {
return err
}
- iq.Payload = append(iq.Payload, iqPl) // []IQPayload{iqPl}
+ iq.Payload = append(iq.Payload, iqPl)
}
}
@@ -232,17 +232,23 @@ func (*Node) IsIQPayload() {}
// Disco
type DiscoInfo struct {
- XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"`
- Identity Identity
+ XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"`
+ Identity Identity `xml:"identity"`
+ Features []Feature `xml:"feature"`
}
func (*DiscoInfo) IsIQPayload() {}
type Identity struct {
- XMLName xml.Name `xml:"identity"`
- Name string `xml:"name,attr"`
- Category string `xml:"category,attr"`
- Type string `xml:"type,attr"`
+ XMLName xml.Name `xml:"identity,omitempty"`
+ Name string `xml:"name,attr,omitempty"`
+ Category string `xml:"category,attr,omitempty"`
+ Type string `xml:"type,attr,omitempty"`
+}
+
+type Feature struct {
+ XMLName xml.Name `xml:"feature"`
+ Var string `xml:"var,attr"`
}
// ============================================================================
diff --git a/iq_test.go b/iq_test.go
index 1a88d72..2ee86b4 100644
--- a/iq_test.go
+++ b/iq_test.go
@@ -2,9 +2,10 @@ package xmpp // import "fluux.io/xmpp"
import (
"encoding/xml"
- "fmt"
"reflect"
"testing"
+
+ "github.com/google/go-cmp/cmp"
)
func TestUnmarshalIqs(t *testing.T) {
@@ -30,63 +31,20 @@ func TestUnmarshalIqs(t *testing.T) {
}
func TestGenerateIq(t *testing.T) {
- iq := NewIQ("get", "admin@localhost", "test@localhost", "1", "en")
- payload := Node{
- XMLName: xml.Name{
- Space: "http://jabber.org/protocol/disco#info",
- Local: "query",
- },
- Nodes: []Node{
- {XMLName: xml.Name{
- Space: "http://jabber.org/protocol/disco#info",
- Local: "identity",
- },
- Attrs: []xml.Attr{
- {Name: xml.Name{Local: "category"}, Value: "gateway"},
- {Name: xml.Name{Local: "type"}, Value: "mqtt"},
- {Name: xml.Name{Local: "name"}, Value: "Test Gateway"},
- },
- Nodes: nil,
- }},
- }
- iq.AddPayload(&payload)
- data, err := xml.Marshal(iq)
- if err != nil {
- t.Errorf("cannot marshal xml structure")
- }
-
- fmt.Printf("XML Struct: %s\n", data)
-
- var parsedIQ = new(IQ)
- if err = xml.Unmarshal(data, parsedIQ); err != nil {
- t.Errorf("Unmarshal(%s) returned error", data)
- }
-
- if !reflect.DeepEqual(parsedIQ.Payload[0], iq.Payload[0]) {
- t.Errorf("expecting result %+v = %+v", parsedIQ.Payload[0], iq.Payload[0])
- }
-
- fmt.Println("ParsedIQ", parsedIQ)
-}
-
-func TestGenerateIqNew(t *testing.T) {
- iq := NewIQ("get", "admin@localhost", "test@localhost", "1", "en")
+ iq := NewIQ("result", "admin@localhost", "test@localhost", "1", "en")
payload := DiscoInfo{
- XMLName: xml.Name{
- Space: "http://jabber.org/protocol/disco#info",
- Local: "query",
- },
Identity: Identity{
- XMLName: xml.Name{
- Space: "http://jabber.org/protocol/disco#info",
- Local: "identity",
- },
Name: "Test Gateway",
Category: "gateway",
Type: "mqtt",
},
+ Features: []Feature{
+ {Var: "http://jabber.org/protocol/disco#info"},
+ {Var: "http://jabber.org/protocol/disco#item"},
+ },
}
iq.AddPayload(&payload)
+
data, err := xml.Marshal(iq)
if err != nil {
t.Errorf("cannot marshal xml structure")
@@ -97,7 +55,29 @@ func TestGenerateIqNew(t *testing.T) {
t.Errorf("Unmarshal(%s) returned error", data)
}
- if !reflect.DeepEqual(parsedIQ.Payload[0], iq.Payload[0]) {
- t.Errorf("expecting result %+v = %+v", parsedIQ.Payload[0], iq.Payload[0])
+ if !xmlEqual(parsedIQ.Payload, iq.Payload) {
+ t.Errorf("non matching items\n%s", cmp.Diff(parsedIQ.Payload, iq.Payload))
}
}
+
+// Compare iq structure but ignore empty namespace as they are set properly on
+// marshal / unmarshal. There is no need to manage them on the manually
+// crafted structure.
+func xmlEqual(x, y interface{}) bool {
+ alwaysEqual := cmp.Comparer(func(_, _ interface{}) bool { return true })
+ opts := cmp.Options{
+ cmp.FilterValues(func(x, y interface{}) bool {
+ xx, xok := x.(xml.Name)
+ yy, yok := y.(xml.Name)
+ if xok && yok {
+ zero := xml.Name{}
+ if xx == zero || yy == zero {
+ return true
+ }
+ }
+ return false
+ }, alwaysEqual),
+ }
+
+ return cmp.Equal(x, y, opts)
+}