2019-06-27 01:21:33 -07:00
|
|
|
# XMPP Stanza
|
|
|
|
|
2019-06-29 05:57:24 -07:00
|
|
|
XMPP `stanza` package is used to parse, marshal and unmarshal XMPP stanzas and nonzas.
|
2019-06-27 01:21:33 -07:00
|
|
|
|
|
|
|
## Stanza creation
|
|
|
|
|
|
|
|
When creating stanzas, you can use two approaches:
|
|
|
|
|
|
|
|
1. You can create IQ, Presence or Message structs, set the fields and manually prepare extensions struct to add to the
|
|
|
|
stanza.
|
2019-06-27 05:30:23 -07:00
|
|
|
2. You can use `stanza` build helper to be guided when creating the stanza, and have more controls performed on the
|
|
|
|
final stanza.
|
2019-06-27 01:21:33 -07:00
|
|
|
|
2019-06-27 05:30:23 -07:00
|
|
|
The methods are equivalent and you can use whatever suits you best. The helpers will finally generate the same type of
|
|
|
|
struct that you can build by hand.
|
2019-06-27 01:21:33 -07:00
|
|
|
|
|
|
|
### Composing stanzas manually with structs
|
|
|
|
|
|
|
|
Here is for example how you would generate an IQ discovery result:
|
|
|
|
|
2019-06-28 07:41:53 -07:00
|
|
|
iqResp := stanza.NewIQ(stanza.Attrs{Type: "result", From: iq.To, To: iq.From, Id: iq.Id})
|
2019-06-27 01:21:33 -07:00
|
|
|
identity := stanza.Identity{
|
|
|
|
Name: opts.Name,
|
|
|
|
Category: opts.Category,
|
|
|
|
Type: opts.Type,
|
|
|
|
}
|
|
|
|
payload := stanza.DiscoInfo{
|
|
|
|
XMLName: xml.Name{
|
|
|
|
Space: stanza.NSDiscoInfo,
|
|
|
|
Local: "query",
|
|
|
|
},
|
2019-06-27 05:30:23 -07:00
|
|
|
Identity: []stanza.Identity{identity},
|
2019-06-27 01:21:33 -07:00
|
|
|
Features: []stanza.Feature{
|
|
|
|
{Var: stanza.NSDiscoInfo},
|
|
|
|
{Var: stanza.NSDiscoItems},
|
|
|
|
{Var: "jabber:iq:version"},
|
|
|
|
{Var: "urn:xmpp:delegation:1"},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
iqResp.Payload = &payload
|
|
|
|
|
2019-06-27 05:30:23 -07:00
|
|
|
### Using helpers
|
2019-06-27 01:21:33 -07:00
|
|
|
|
|
|
|
Here is for example how you would generate an IQ discovery result using Builder:
|
|
|
|
|
2019-06-27 05:30:23 -07:00
|
|
|
iq := stanza.NewIQ(stanza.Attrs{Type: "get", To: "service.localhost", Id: "disco-get-1"})
|
|
|
|
disco := iq.DiscoInfo()
|
|
|
|
disco.AddIdentity("Test Component", "gateway", "service")
|
|
|
|
disco.AddFeatures(stanza.NSDiscoInfo, stanza.NSDiscoItems, "jabber:iq:version", "urn:xmpp:delegation:1")
|
2019-06-27 01:21:33 -07:00
|
|
|
|
|
|
|
## Payload and extensions
|
|
|
|
|
|
|
|
### Message
|
|
|
|
|
2019-06-28 07:41:53 -07:00
|
|
|
Here is the list of implemented message extensions:
|
|
|
|
|
|
|
|
- `Delegation`
|
|
|
|
|
|
|
|
- `Markable`
|
|
|
|
- `MarkAcknowledged`
|
|
|
|
- `MarkDisplayed`
|
|
|
|
- `MarkReceived`
|
|
|
|
|
|
|
|
- `StateActive`
|
|
|
|
- `StateComposing`
|
|
|
|
- `StateGone`
|
|
|
|
- `StateInactive`
|
|
|
|
- `StatePaused`
|
|
|
|
|
|
|
|
- `HTML`
|
|
|
|
|
|
|
|
- `OOB`
|
|
|
|
|
|
|
|
- `ReceiptReceived`
|
|
|
|
- `ReceiptRequest`
|
|
|
|
|
|
|
|
- `Mood`
|
|
|
|
|
2019-06-27 01:21:33 -07:00
|
|
|
### Presence
|
|
|
|
|
2019-06-28 07:41:53 -07:00
|
|
|
Here is the list of implemented presence extensions:
|
|
|
|
|
|
|
|
- `MucPresence`
|
|
|
|
|
2019-06-27 01:21:33 -07:00
|
|
|
### IQ
|
|
|
|
|
|
|
|
IQ (Information Queries) contain a payload associated with the request and possibly an error. The main difference with
|
|
|
|
Message and Presence extension is that you can only have one payload per IQ. The XMPP specification does not support
|
|
|
|
having multiple payloads.
|
|
|
|
|
|
|
|
Here is the list of structs implementing IQPayloads:
|
|
|
|
|
2019-06-28 07:41:53 -07:00
|
|
|
- `ControlSet`
|
|
|
|
- `ControlSetResponse`
|
|
|
|
- `Delegation`
|
|
|
|
- `DiscoInfo`
|
|
|
|
- `DiscoItems`
|
|
|
|
- `Pubsub`
|
|
|
|
- `Version`
|
|
|
|
- `Node`
|
2019-06-27 01:21:33 -07:00
|
|
|
|
|
|
|
Finally, when the payload of the parsed stanza is unknown, the parser will provide the unknown payload as a generic
|
|
|
|
`Node` element. You can also use the Node struct to add custom information on stanza generation. However, in both cases,
|
|
|
|
you may also consider [adding your own custom extensions on stanzas]().
|
|
|
|
|
|
|
|
|
|
|
|
## Adding your own custom extensions on stanzas
|
|
|
|
|
|
|
|
Extensions are registered on launch using the `Registry`. It can be used to register you own custom payload. You may
|
|
|
|
want to do so to support extensions we did not yet implement, or to add your own custom extensions to your XMPP stanzas.
|
2019-06-28 07:19:09 -07:00
|
|
|
|
|
|
|
To create an extension you need:
|
|
|
|
1. to create a struct for that extension. It need to have XMLName for consistency and to tagged at the struct level with
|
|
|
|
`xml` info.
|
|
|
|
2. It need to implement one or several extensions interface: stanza.IQPayload, stanza.MsgExtension and / or
|
|
|
|
stanza.PresExtension
|
|
|
|
3. Add that custom extension to the stanza.TypeRegistry during the file init.
|
|
|
|
|
|
|
|
Here an example code showing how to create a custom IQPayload.
|
|
|
|
|
|
|
|
```go
|
|
|
|
package myclient
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/xml"
|
|
|
|
|
|
|
|
"gosrc.io/xmpp/stanza"
|
|
|
|
)
|
|
|
|
|
|
|
|
type CustomPayload struct {
|
|
|
|
XMLName xml.Name `xml:"my:custom:payload query"`
|
|
|
|
Node string `xml:"node,attr,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
func (c CustomPayload) Namespace() string {
|
|
|
|
return c.XMLName.Space
|
|
|
|
}
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
stanza.TypeRegistry.MapExtension(stanza.PKTIQ, xml.Name{"my:custom:payload", "query"}, CustomPayload{})
|
|
|
|
}
|
|
|
|
```
|