go-xmpp v0.5.0

ProcessOne
· 2 min read
Send by email

A new version of the go-xmpp library, which can be used to write XMPP clients or components in Go, has been released. It’s available on GitHub.

You can find the full changelog here : CHANGELOG

This version essentially adds support for Stream Management (XEP-0198), and post-connect/post-reconnect hooks for XMPP clients. Read more below !

Support for Stream Management (XEP-0198)

Acking

“Acking” is the tracking of stanzas at the client level, meaning at higher levels than TCP for instance.
The receiving entity keeps a counter of successfully processed stanzas for a given session, and can communicate this counter to the other entity.

In go-xmpp, if Client.Config.StreamManagementEnable is set to “true”, all sent stanzas will be both sent and put into a queue.
If an ack request is made to the server, depending on the response, some stanzas will be discarded, because the server already handled them, or resent because the server never got them.

Here’s how one would ask for acks :

r := stanza.SMRequest{}
client.Send(r)

Resumption

Stream resume capabilities were also added in this release.

Stream resumption allows to resume a session with the server without going through the entire ceremony of the protocol; it essentially skips some steps.

When a client is created using go-xmpp, one can specify a handler for the client’s event manager. Basically, every time the client changes states (connected -> disconnected for instance), the handler is executed.

Here’s we would use the handler to resume an interrupted stream :

  // Create a client. Skipped for brevity

  // Create a handler for that client. Triggered when changing state
  handler := func(e Event) error {
        switch e.State.state {
      // Some states are skipped. 
      // See "StreamManager" in the lib for a more thorough example)
        case StateDisconnected:
            // Reconnect on disconnection
            return client.Resume()
        case StatePermanentError:
            // Do not attempt to reconnect
        }
        return nil
    }

  // Add the handler to the client
  client.SetHandler(handler)

Now a disconnection because of network outage would trigger a stream resumption.

Post-(re)connect hooks

To help with designing clients, two post connection hooks were added to Client :

  • PostConnectHook
    Will be triggered when calling Client.Connect(). Can be used to retrieve the roster for instance.
  • PostResumeHook
    Will be triggered when using Client.Resume(). Do different operations when reconnecting, and skipping roster if we already have it for example.

One would just assign them as follows :

   config := Config{
        TransportConfiguration: TransportConfiguration{
            Address: testServerAddress,
        },
        Jid:        "test@localhost",
        Credential: Password("test"),
        Insecure:   true}

    var client *Client
    var err error
    router := NewRouter()
  // client default handler omitted for brevity
    if client, err = NewClient(&config, router, clientDefaultErrorHandler); err != nil {
    log.Fatalf("connect create XMPP client: %s", err)
    }

    // Assign hooks to the client
    client.PostConnectHook = func() error {
        go func() {
            // ask server for roster, omitted here
        }()
        return nil
    }
    client.PostResumeHook = func() error {
        go func() {
            // do something else when we try to resume. We already have the roster if this gets triggered
        }()
        return nil
    }

And that’s it ! Hooks will be triggered automatically when relevant.