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
}
switch iq.Payload.(type) {
// TODO Check all elements
switch iq.Payload[0].(type) {
case *bindBind:
result := `<iq id='%s' type='result'>
<bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'>

View file

@ -1,6 +1,7 @@
package main
import (
"encoding/xml"
"fmt"
"fluux.io/xmpp"
@ -22,6 +23,13 @@ func main() {
case xmpp.IQ:
switch inner := p.Payload.(type) {
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)
default:
fmt.Println("default")

73
iq.go
View file

@ -7,18 +7,57 @@ import (
"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
type IQ struct { // Info/Query
XMLName xml.Name `xml:"iq"`
PacketAttrs
Payload IQPayload `xml:",omitempty"`
Payload []IQPayload `xml:",omitempty"`
RawXML string `xml:",innerxml"`
// TODO We need to support detecting the IQ namespace / Query packet
// 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 {
return "iq"
}
@ -33,10 +72,6 @@ func (iqDecoder) decode(p *xml.Decoder, se xml.StartElement) (IQ, error) {
return packet, err
}
type IQPayload interface {
IsIQPayload()
}
// UnmarshalXML implements custom parsing for IQs
func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
iq.XMLName = start.Name
@ -83,7 +118,7 @@ func (iq *IQ) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
if err != nil {
return err
}
iq.Payload = p
iq.Payload = []IQPayload{p}
p = nil
}
@ -117,12 +152,32 @@ func (iq *IQ) XMPPFormat() string {
}
// ============================================================================
// Genery IQ Node
// Generic IQ Payload
type IQPayload interface {
IsIQPayload()
}
type Node struct {
XMLName xml.Name
Content []byte `xml:",innerxml"`
Attrs []xml.Attr `xml:"-"`
// Content []byte `xml:",innerxml"`
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() {}

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
}
switch payload := iq.Payload.(type) {
// TODO Check all elements
switch payload := iq.Payload[0].(type) {
case *bindBind:
s.BindJid = payload.Jid // our local id (with possibly randomly generated resource
default: