Documentation ¶
Overview ¶
Package for implementing XMPP clients and components.
The package is built around the concept of an XML stream - a pair of XML documents written to and read from a TCP connection. Top-level elements in the document form the messages processed by either end of the connection.
An XML stream is then configured for an XMPP conversation, as either a client (chat, etc) or component (a sort of server plugin).
Create a client:
jid, err := xmpp.ParseJID("alice@wonderland.lit/some-resource") addr, err := xmpp.HomeServerAddrs(jid) stream, err := xmpp.NewStream(addr[0], nil) X, err := xmpp.NewClientXMPP(stream, jid, "password", nil)
Create a component:
jid, err := xmpp.ParseJID("rabbithole.wonderland.lit") stream, err := xmpp.NewStream("localhost:5347", nil) X, err := xmpp.NewComponentXMPP(stream, jid, "secret")
Outgoing XMPP stanzas are sent to the XMPP instance's Out channel, e.g. a client typically announces its presence on the XMPP network as soon as it's connected:
X.Out <- xmpp.Presence{}
Incoming messages are handled by consuming the XMPP instance's In channel. The channel is sent all XMPP stanzas as well as terminating error (io.EOF for clean shutdown or any other error for something unexpected). The channel is also closed after an error.
XMPP defines four types of stanza: <error/>, <iq/>, <message/> and <presence/> represented by Error, Iq, Message (shown below) and Presence structs respectively.
for i := range X.In { switch v := i.(type) { case error: log.Printf("error : %v\n", v) case *xmpp.Message: log.Printf("msg : %s says %s\n", v.From, v.Body) default: log.Printf("%T : %v\n", v, v) } }
Note: A "bound" JID is negotatiated during XMPP setup and may be different to the JID passed to the New(Client|Component)XMPP() call. Always use the XMPP instance's JID attribute in any stanzas.
Index ¶
- Constants
- Variables
- func HomeServerAddrs(jid JID) (addr []string, err error)
- func UUID4() string
- type ClientConfig
- type Disco
- type DiscoFeature
- type DiscoIdentity
- type DiscoInfo
- type DiscoItem
- type DiscoItems
- type Error
- type ErrorCondition
- type FilterId
- type Iq
- type JID
- type Matcher
- type MatcherFunc
- type Message
- type Presence
- type Stream
- func (stream *Stream) Decode(v interface{}, start *xml.StartElement) error
- func (stream *Stream) Next() (*xml.StartElement, error)
- func (stream *Stream) Send(v interface{}) error
- func (stream *Stream) SendEnd(end *xml.EndElement) error
- func (stream *Stream) SendStart(start *xml.StartElement) (*xml.StartElement, error)
- func (stream *Stream) Skip() error
- func (stream *Stream) UpgradeTLS(config *tls.Config) error
- type StreamConfig
- type XMPP
- Bugs
Constants ¶
const (
// Standard port for XMPP clients to connect to.
XMPP_CLIENT_PORT = 5222
)
Variables ¶
var DiscoPayloadMatcher = MatcherFunc( func(v interface{}) bool { iq, ok := v.(*Iq) if !ok { return false } ns := strings.Split(iq.PayloadName().Space, "#")[0] return ns == discoNamespacePrefix }, )
Matcher instance to match <iq/> stanzas with a disco payload.
var (
FeatureNotImplemented = ErrorCondition{nsErrorStanzas, "feature-not-implemented"}
)
Stanza errors.
Functions ¶
func HomeServerAddrs ¶
Perform a DNS SRV lookup and return an ordered list of "host:port" TCP addresses for the JID's home server. If no SRV records are found then assume the JID's domain is also the home server.
Types ¶
type ClientConfig ¶
type ClientConfig struct { // Don't upgrade the connection to TLS, even if the server supports it. If // the server *requires* TLS then this option is ignored. NoTLS bool // Skip verification of the server's certificate chain. Probably only // useful during development. InsecureSkipVerify bool }
Config structure used to create a new XMPP client connection.
type Disco ¶
type Disco struct {
XMPP *XMPP
}
Service Discovery (XEP-0030) protocol. "Wraps" XMPP instance to provide a more convenient API for Disco clients.
type DiscoIdentity ¶
type DiscoIdentity struct { Category string `xml:"category,attr"` Type string `xml:"type,attr"` Name string `xml:"name,attr"` }
Identity
type DiscoInfo ¶
type DiscoInfo struct { XMLName xml.Name `xml:"http://jabber.org/protocol/disco#info query"` Identity []DiscoIdentity `xml:"identity"` Feature []DiscoFeature `xml:"feature"` }
Iq get/result payload for "info" requests.
type DiscoItem ¶
type DiscoItem struct { JID string `xml:"jid,attr"` Node string `xml:"node,attr"` Name string `xml:"name,attr"` }
Item.
type DiscoItems ¶
type DiscoItems struct { XMLName xml.Name `xml:"http://jabber.org/protocol/disco#items query"` Item []DiscoItem `xml:"item"` }
Iq get/result payload for "items" requests.
type Error ¶
type Error struct { XMLName xml.Name `xml:"error"` Type string `xml:"type,attr"` Payload string `xml:",innerxml"` }
XMPP <error/>. May occur as a top-level stanza or embedded in another stanza, e.g. an <iq type="error"/>.
func NewError ¶
func NewError(errorType string, condition ErrorCondition, text string) *Error
Create a new Error instance using the args as the payload.
func (Error) Condition ¶
func (e Error) Condition() ErrorCondition
Return the error condition from the payload.
type FilterId ¶
type FilterId int64
Uniquly identifies a stream fiter. Used to remove a filter that's no longer needed.
type Iq ¶
type Iq struct { XMLName xml.Name `xml:"iq"` Id string `xml:"id,attr"` Type string `xml:"type,attr"` To string `xml:"to,attr,omitempty"` From string `xml:"from,attr,omitempty"` Payload string `xml:",innerxml"` Error *Error `xml:"error"` }
XMPP <iq/> stanza.
func (*Iq) PayloadDecode ¶
Decode the payload (an XML string) into the given value. See xml.Unmarshal for how the value is decoded.
func (*Iq) PayloadEncode ¶
Encode the value to an XML string and set as the payload. See xml.Marshal for how the value is encoded.
func (*Iq) PayloadName ¶
Return the name of the payload element.
type JID ¶
type JID struct { // Node/local component e.g. the alice of alice@example.com/foo. Node string // Domain component, e.g. the example.com of alice@example.com/foo for a // client or the whole JID of a component. Domain string // Resource component, e.g. the foo of alice@example.com/foo. Resource string }
Jabber Identifier - uniquely identifies an individual entity in a XMPP/Jabber network.
type Matcher ¶
type Matcher interface { // Return true if the stanza, v, matches. Match(v interface{}) (match bool) }
Interface used to test if a stanza matches some application-defined conditions.
type MatcherFunc ¶
type MatcherFunc func(v interface{}) bool
Adapter to allow a plain func to be used as a Matcher.
func (MatcherFunc) Match ¶
func (fn MatcherFunc) Match(v interface{}) bool
Implement Matcher by calling the adapted func.
type Message ¶
type Message struct { XMLName xml.Name `xml:"message"` Id string `xml:"id,attr,omitempty"` Type string `xml:"type,attr,omitempty"` To string `xml:"to,attr,omitempty"` From string `xml:"from,attr,omitempty"` Subject string `xml:"subject,omitempty"` Body string `xml:"body,omitempty"` }
XMPP <message/> stanza.
type Presence ¶
type Presence struct { XMLName xml.Name `xml:"presence"` Id string `xml:"id,attr,omitempty"` Type string `xml:"type,attr,omitempty"` To string `xml:"to,attr,omitempty"` From string `xml:"from,attr,omitempty"` }
XMPP <presence/> stanza.
type Stream ¶
type Stream struct {
// contains filtered or unexported fields
}
func NewStream ¶
func NewStream(addr string, config *StreamConfig) (*Stream, error)
Create a XML stream connection. A Steam is used by an XMPP instance to handle sending and receiving XML data over the net connection.
func (*Stream) Decode ¶
func (stream *Stream) Decode(v interface{}, start *xml.StartElement) error
Decode a stanza. If start is not nil, the stanza for the start element that's already been consumed is read. A nil start will read the next stanza in the stream. See xml.Decoder.DecodeElement for decoding rules.
func (*Stream) Next ¶
func (stream *Stream) Next() (*xml.StartElement, error)
Find start of next stanza. Bad things are very likely to happen if a call to Next() is successful but you don't actually decode or skip the element.
func (*Stream) SendEnd ¶
func (stream *Stream) SendEnd(end *xml.EndElement) error
Send the end element that closes the stream.
func (*Stream) SendStart ¶
func (stream *Stream) SendStart(start *xml.StartElement) (*xml.StartElement, error)
Send the element's start tag. Typically used to open the stream's document.
type StreamConfig ¶
type StreamConfig struct { // Log all sent and received stanzas. // Enabling this option causes stanzas to be buffered in memory before they // are either sent to the server or delivered to the application. It also // causes incoming stanzas to be XML-parsed a second time. LogStanzas bool }
Stream configuration.
type XMPP ¶
type XMPP struct { // JID associated with the stream. Note: this may be negotiated with the // server during setup and so must be used for all messages. JID JID // Channel of incoming messages. Values will be one of Iq, Message, // Presence, Error or error. Will be closed at the end when the stream is // closed or the stream's net connection dies. In chan interface{} // Channel of outgoing messages. Messages must be able to be marshaled by // the standard xml package, however you should try to send one of Iq, // Message or Presence. Out chan interface{} // contains filtered or unexported fields }
Handles XMPP conversations over a Stream. Use NewClientXMPP or NewComponentXMPP to create and configure a XMPP instance. Close the conversation by closing the Out channel, the In channel will be closed when the remote server closes its stream.
func NewClientXMPP ¶
Create a client XMPP over the stream.
func NewComponentXMPP ¶
Create a component XMPP connection over the stream.
func (*XMPP) AddFilter ¶
Add a filter that routes matching stanzas to the returned channel. A FilterId is also returned and can be pased to RemoveFilter to remove the filter again.
func (*XMPP) RemoveFilter ¶
Remove a filter previously added with AddFilter.
Notes ¶
Bugs ¶
authentication incorrectly reports, "No supported SASL mechanism found", for authentication attemtps that fail due to invalid credentials.
ParseJID should fail for incorrectly formatted JIDs.
Filter channels are not closed when the stream is closed.