Implement error parsing
This commit is contained in:
parent
bbfafbb32c
commit
8470c01c09
100
iq.go
100
iq.go
|
@ -6,6 +6,8 @@ import (
|
||||||
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
|
||||||
"fluux.io/xmpp/iot"
|
"fluux.io/xmpp/iot"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -60,6 +62,92 @@ TODO support ability to put Raw payload
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
// XMPP Errors
|
||||||
|
|
||||||
|
type Err struct {
|
||||||
|
XMLName xml.Name `xml:"error"`
|
||||||
|
Reason string
|
||||||
|
Code int `xml:"code,attr,omitempty"`
|
||||||
|
Type string `xml:"type,attr,omitempty"`
|
||||||
|
Text string `xml:"urn:ietf:params:xml:ns:xmpp-stanzas text"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalXML implements custom parsing for IQs
|
||||||
|
func (x *Err) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
|
x.XMLName = start.Name
|
||||||
|
|
||||||
|
// Extract attributes
|
||||||
|
for _, attr := range start.Attr {
|
||||||
|
if attr.Name.Local == "type" {
|
||||||
|
x.Type = attr.Value
|
||||||
|
}
|
||||||
|
if attr.Name.Local == "code" {
|
||||||
|
if code, err := strconv.Atoi(attr.Value); err == nil {
|
||||||
|
x.Code = code
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
t, err := d.Token()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch tt := t.(type) {
|
||||||
|
|
||||||
|
case xml.StartElement:
|
||||||
|
elt := new(Node)
|
||||||
|
|
||||||
|
err = d.DecodeElement(elt, &tt)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
textName := xml.Name{Space: "urn:ietf:params:xml:ns:xmpp-stanzas", Local: "text"}
|
||||||
|
if elt.XMLName == textName {
|
||||||
|
x.Text = string(elt.Content)
|
||||||
|
} else if elt.XMLName.Space == "urn:ietf:params:xml:ns:xmpp-stanzas" {
|
||||||
|
x.Reason = elt.XMLName.Local
|
||||||
|
}
|
||||||
|
|
||||||
|
case xml.EndElement:
|
||||||
|
if tt == start.End() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x Err) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
|
||||||
|
code := xml.Attr{
|
||||||
|
Name: xml.Name{Local: "code"},
|
||||||
|
Value: strconv.Itoa(x.Code),
|
||||||
|
}
|
||||||
|
typ := xml.Attr{
|
||||||
|
Name: xml.Name{Local: "type"},
|
||||||
|
Value: x.Type,
|
||||||
|
}
|
||||||
|
start.Name = xml.Name{Local: "error"}
|
||||||
|
start.Attr = append(start.Attr, code, typ)
|
||||||
|
err = e.EncodeToken(start)
|
||||||
|
|
||||||
|
// Subtags
|
||||||
|
// Reason
|
||||||
|
reason := xml.Name{Space: "urn:ietf:params:xml:ns:xmpp-stanzas", Local: x.Reason}
|
||||||
|
e.EncodeToken(xml.StartElement{Name: reason})
|
||||||
|
e.EncodeToken(xml.EndElement{Name: reason})
|
||||||
|
|
||||||
|
// Text
|
||||||
|
text := xml.Name{Space: "urn:ietf:params:xml:ns:xmpp-stanzas", Local: "text"}
|
||||||
|
e.EncodeToken(xml.StartElement{Name: text})
|
||||||
|
e.EncodeToken(xml.CharData(x.Text))
|
||||||
|
e.EncodeToken(xml.EndElement{Name: text})
|
||||||
|
|
||||||
|
return e.EncodeToken(xml.EndElement{Name: start.Name})
|
||||||
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// IQ Packet
|
// IQ Packet
|
||||||
|
|
||||||
|
@ -68,7 +156,7 @@ type IQ struct { // Info/Query
|
||||||
PacketAttrs
|
PacketAttrs
|
||||||
Payload []IQPayload `xml:",omitempty"`
|
Payload []IQPayload `xml:",omitempty"`
|
||||||
RawXML string `xml:",innerxml"`
|
RawXML string `xml:",innerxml"`
|
||||||
// Error clientError
|
Error Err `xml:"error,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIQ(iqtype, from, to, id, lang string) IQ {
|
func NewIQ(iqtype, from, to, id, lang string) IQ {
|
||||||
|
@ -196,8 +284,8 @@ type IQPayload interface {
|
||||||
type Node struct {
|
type Node struct {
|
||||||
XMLName xml.Name
|
XMLName xml.Name
|
||||||
Attrs []xml.Attr `xml:"-"`
|
Attrs []xml.Attr `xml:"-"`
|
||||||
// Content []byte `xml:",innerxml"`
|
Content string `xml:",innerxml"`
|
||||||
Nodes []Node `xml:",any"`
|
Nodes []Node `xml:",any"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Attr struct {
|
type Attr struct {
|
||||||
|
@ -217,7 +305,7 @@ func (n *Node) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
|
||||||
return d.DecodeElement((*node)(n), &start)
|
return d.DecodeElement((*node)(n), &start)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
|
func (n Node) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
|
||||||
start.Attr = n.Attrs
|
start.Attr = n.Attrs
|
||||||
start.Name = n.XMLName
|
start.Name = n.XMLName
|
||||||
|
|
||||||
|
@ -231,6 +319,10 @@ func (*Node) IsIQPayload() {}
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// Disco
|
// Disco
|
||||||
|
|
||||||
|
const (
|
||||||
|
NSDiscoInfo = "http://jabber.org/protocol/disco#info"
|
||||||
|
)
|
||||||
|
|
||||||
type DiscoInfo struct {
|
type DiscoInfo struct {
|
||||||
XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"`
|
XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"`
|
||||||
Identity Identity `xml:"identity"`
|
Identity Identity `xml:"identity"`
|
||||||
|
|
24
iq_test.go
24
iq_test.go
|
@ -61,6 +61,30 @@ func TestGenerateIq(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestErrorTag(t *testing.T) {
|
||||||
|
xError := Err{
|
||||||
|
XMLName: xml.Name{Local: "error"},
|
||||||
|
Code: 503,
|
||||||
|
Type: "cancel",
|
||||||
|
Reason: "service-unavailable",
|
||||||
|
Text: "User session not found",
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := xml.Marshal(xError)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("cannot marshal xml structure: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
parsedError := Err{}
|
||||||
|
if err = xml.Unmarshal(data, &parsedError); err != nil {
|
||||||
|
t.Errorf("Unmarshal(%s) returned error", data)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !xmlEqual(parsedError, xError) {
|
||||||
|
t.Errorf("non matching items\n%s", cmp.Diff(parsedError, xError))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Compare iq structure but ignore empty namespace as they are set properly on
|
// 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
|
// marshal / unmarshal. There is no need to manage them on the manually
|
||||||
// crafted structure.
|
// crafted structure.
|
||||||
|
|
Loading…
Reference in a new issue