Improve generic IQ parsing

This commit is contained in:
Mickael Remond 2018-01-15 12:28:34 +01:00
parent ff2da776d3
commit dade3504f0
No known key found for this signature in database
GPG key ID: E6F6045D79965AA3
5 changed files with 113 additions and 13 deletions

View file

@ -170,7 +170,8 @@ func bind(t *testing.T, c net.Conn, decoder *xml.Decoder) {
return return
} }
switch iq.Payload.(type) { // TODO Check all elements
switch iq.Payload[0].(type) {
case *bindBind: case *bindBind:
result := `<iq id='%s' type='result'> result := `<iq id='%s' type='result'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>

View file

@ -1,6 +1,7 @@
package main package main
import ( import (
"encoding/xml"
"fmt" "fmt"
"fluux.io/xmpp" "fluux.io/xmpp"
@ -22,6 +23,13 @@ func main() {
case xmpp.IQ: case xmpp.IQ:
switch inner := p.Payload.(type) { switch inner := p.Payload.(type) {
case *xmpp.Node: case *xmpp.Node:
fmt.Printf("%q\n", inner)
data, err := xml.Marshal(inner)
if err != nil {
fmt.Println("cannot marshall payload")
}
fmt.Println("data=", string(data))
component.processIQ(p.Type, p.Id, p.From, inner) component.processIQ(p.Type, p.Id, p.From, inner)
default: default:
fmt.Println("default") fmt.Println("default")

73
iq.go
View file

@ -7,18 +7,57 @@ import (
"fluux.io/xmpp/iot" "fluux.io/xmpp/iot"
) )
/*
TODO I would like to be able to write
newIQ(Id, From, To, Type, Lang).AddPayload(IQPayload)
xmpp.IQ{
XMLName: xml.Name{
Space: "",
Local: "",
},
PacketAttrs: xmpp.PacketAttrs{
Id: "",
From: "",
To: "",
Type: "",
Lang: "",
},
Payload: nil,
RawXML: "",
}
*/
// ============================================================================ // ============================================================================
// IQ Packet // IQ Packet
type IQ struct { // Info/Query type IQ struct { // Info/Query
XMLName xml.Name `xml:"iq"` XMLName xml.Name `xml:"iq"`
PacketAttrs PacketAttrs
Payload IQPayload `xml:",omitempty"` Payload []IQPayload `xml:",omitempty"`
RawXML string `xml:",innerxml"` RawXML string `xml:",innerxml"`
// TODO We need to support detecting the IQ namespace / Query packet
// Error clientError // Error clientError
} }
func NewIQ(iqtype, from, to, id, lang string) IQ {
return IQ{
XMLName: xml.Name{Local: "iq"},
PacketAttrs: PacketAttrs{
Id: id,
From: from,
To: to,
Type: iqtype,
Lang: lang,
},
}
}
func (iq *IQ) AddPayload(payload IQPayload) {
iq.Payload = append(iq.Payload, payload)
}
func (IQ) Name() string { func (IQ) Name() string {
return "iq" return "iq"
} }
@ -33,10 +72,6 @@ func (iqDecoder) decode(p *xml.Decoder, se xml.StartElement) (IQ, error) {
return packet, err return packet, err
} }
type IQPayload interface {
IsIQPayload()
}
// UnmarshalXML implements custom parsing for IQs // UnmarshalXML implements custom parsing for IQs
func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
iq.XMLName = start.Name iq.XMLName = start.Name
@ -83,7 +118,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if err != nil { if err != nil {
return err return err
} }
iq.Payload = p iq.Payload = []IQPayload{p}
p = nil p = nil
} }
@ -117,12 +152,32 @@ func (iq *IQ) XMPPFormat() string {
} }
// ============================================================================ // ============================================================================
// Genery IQ Node // Generic IQ Payload
type IQPayload interface {
IsIQPayload()
}
type Node struct { type Node struct {
XMLName xml.Name XMLName xml.Name
Content []byte `xml:",innerxml"` Attrs []xml.Attr `xml:"-"`
// Content []byte `xml:",innerxml"`
Nodes []Node `xml:",any"` Nodes []Node `xml:",any"`
} }
func (n *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
n.Attrs = start.Attr
type node Node
return d.DecodeElement((*node)(n), &start)
}
func (n *Node) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
start.Attr = n.Attrs
start.Name = n.XMLName
err = e.EncodeToken(start)
e.EncodeElement(n.Nodes, xml.StartElement{Name: n.XMLName})
return e.EncodeToken(xml.EndElement{Name: start.Name})
}
func (*Node) IsIQPayload() {} func (*Node) IsIQPayload() {}

View file

@ -27,3 +27,38 @@ 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{
Local: "identity",
},
Attrs: []xml.Attr{
{Name: xml.Name{Local: "category"}, Value: "gateway"},
{Name: xml.Name{Local: "type"}, Value: "skype"},
{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")
}
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])
}
}

View file

@ -163,7 +163,8 @@ func (s *Session) bind(o Options) {
return return
} }
switch payload := iq.Payload.(type) { // TODO Check all elements
switch payload := iq.Payload[0].(type) {
case *bindBind: case *bindBind:
s.BindJid = payload.Jid // our local id (with possibly randomly generated resource s.BindJid = payload.Jid // our local id (with possibly randomly generated resource
default: default: