Copied from a draft of an upcoming blog post. Further reading moved to the front for easy access:
- Docs: https://pkg.go.dev/mellium.im/xmpp@master - Website: https://mellium.im/xmpp - A Message Styling retrospective: https://blog.samwhited.com/2020/11/message-styling/ - An overview of the Mellium project and its design: https://blog.samwhited.com/2020/06/xmpp-in-go/ - A guide to designing (not programming) XMPP related Go packages: https://blog.samwhited.com/2020/02/extensions-in-mellium/ --- Last year the main Go module of the Mellium project, [`mellium.im/xmpp`] received a huge number of updates, bug fixes, and API overhauls, many of which will be released in the upcoming `v0.18.0` release. Some of the highlights include: - WebSocket support - The ability to negotiate multiple virtual hosts - More server side implementations of stream features such as SASL and resource binding - An implementation of [Message styling][XEP-0393] - [Chat marker][XEP-0333] support - Support for [XEP-0202: Entity Time][XEP-0202] and [XEP-0082: XMPP Date and Time Profiles][XEP-0082] - Integration testing against common servers and clients - Better fallback behavior when looking up XMPP servers - Easier sending of IQs without having to think about XML tokens - Easier APIs for registering handlers against specific IQ payloads - XMPP URI and IRI parsing support The full (much longer) list can be found in the [changelog]. [changelog]: https://mellium.im/xmpp/changelog ## Message Styling The change to `mellium.im/xmpp` that I'm most proud of in the past year might be the Message Styling implementation which can be found at [`mellium.im/xmpp/styling`]. The actual styling implementation comprises three parts: the [`Style`] type, the `Scan` function, and the [`Decoder`] type. The [`Style`] type is a `uint32` that represents a bitmask of styles such as "strong and emph" or "pre-formatted text and block quoted". It only contains information about the styles, not about metadata related to the styles or the token stream. For example, given a style you can know that the text is in a blockquote, but not the level of nesting (if any) of the blockquote, or you might know that it is in a strong span, but not where the start and endpoints of that span are. The package provides the various styles and a handful of masks for various common combinations as constants for the users convenience. For more, see my retrspective post, [_Message Styling_][Message Styling]. ## Stream Initialization and Virtual Hosts XMPP servers likely want to serve more than one domain, but prior to the upcoming v0.18.0 release this was difficult or impossible. This required changes to the [`Negotiator`] type to allow input and output streams to be stored on the session, and to the built-in `Negotiator`'s [`StreamConfig`] type which is used for configuring options on the built in default negotiator to allow the user to select the features in a callback. Unfortunately, these are breaking changes, but it should be one of the last major API changes before we can begin thinking about stabilizing the API in v1.0.0. The `S2S` option was also removed from the `StreamConfig` in favor of new functions for receiving and negotiating a stream which mark the s2s state bit on the session before beginning negotiation. This removes a long standing redundancy, and also a bug where the first stream feature negotiated wouldn't know that the session was a server-to-server session because it couldn't be set until the negotiator function returned for the first time. The current list of stream negotiation functions is: - [`DialClientSession`] - [`DialServerSession`] - [`DialSession`] - [`NewClientSession`] - [`NewServerSession`] - [`NewSession`] - [`ReceiveClientSession`] - [`ReceiveServerSession`] - [`ReceiveSession`] [`Negotiator`]: https://pkg.go.dev/mellium.im/xmpp#Negotiator [`StreamConfig`]: https://pkg.go.dev/mellium.im/xmpp#StreamConfig [`DialClientSession`]: https://pkg.go.dev/mellium.im/xmpp#DialClientSession [`DialServerSession`]: https://pkg.go.dev/mellium.im/xmpp#DialServerSession [`DialSession`]: https://pkg.go.dev/mellium.im/xmpp#DialSession [`NewClientSession`]: https://pkg.go.dev/mellium.im/xmpp#NewClientSession [`NewServerSession`]: https://pkg.go.dev/mellium.im/xmpp#NewServerSession [`NewSession`]: https://pkg.go.dev/mellium.im/xmpp#NewSession [`ReceiveClientSession`]: https://pkg.go.dev/mellium.im/xmpp#ReceiveClientSession [`ReceiveServerSession`]: https://pkg.go.dev/mellium.im/xmpp#ReceiveServerSession [`ReceiveSession`]: https://pkg.go.dev/mellium.im/xmpp#ReceiveSession ## Testing While it's not an exciting user-facing feature, one of the most valuable changes this year has been the addition of integration testing against [Prosody], Ejabberd, McAbber (Loudmouth), and `sendxmpp(1)`. We've already caught several issues both in Mellium and in some of the services we're testing against thanks to the new tests! This is all facilitated by the [`internal/integration`] package which provides a framework for starting an external application, generating certificates, and passing around file handles. It works by creating a temporary directory where any config files can be stored, then launching the process using that temp directory as a working directory. It also provides generic options for writing files to that directory that can be used by the child packages, such as [`prosody`], to write more specific options that write the prosody config file. The integration testing packages also provide functionality for running sub-tests, each one of which will get its own child process with all the configuration automatically. For example, to test sending a ping to Prosody and Ejabberd and receiving a ping on Prosody we might write something like the following: ``` func TestIntegrationSendPing(t *testing.T) { prosodyRun := prosody.Test(context.TODO(), t, integration.Log(), prosody.ListenC2S(), ) prosodyRun(integrationSendPing) prosodyRun(integrationRecvPing) ejabberdRun := ejabberd.Test(context.TODO(), t, integration.Log(), ejabberd.ListenC2S(), ) ejabberdRun(integrationSendPing) } func integrationSendPing(ctx context.Context, t *testing.T, cmd *integration.Cmd) { … } func integrationRecvPing(ctx context.Context, t *testing.T, cmd *integration.Cmd) { … } ``` More complex options for loading Prosody extensions, generating and using certificates and enabling TLS, changing the default username and server host, etc. are also available. [Prosody]: https://prosody.im/ [Ejabberd]: https://www.ejabberd.im/ [McAbber]: https://mcabber.com/ [`sendxmpp(1)`]: https://sendxmpp.hostname.sk/ [`internal/integration`]: https://pkg.go.dev/mellium.im/xmpp/internal/integration [`prosody`]: https://pkg.go.dev/mellium.im/xmpp/internal/integration/prosody [XEP-0202]: https://xmpp.org/extensions/xep-0202.html [XEP-0082]: https://xmpp.org/extensions/xep-0082.html [XEP-0333]: https://xmpp.org/extensions/xep-0333.html [`mellium.im/xmpp`]: https://pkg.go.dev/mellium.im/xmpp [XEP-0393]: https://xmpp.org/extensions/xep-0393.html [`mellium.im/xmpp/styling`]: https://pkg.go.dev/mellium.im/xmpp/styling [`Style`]: https://pkg.go.dev/mellium.im/xmpp/styling#Style [`Scan`]: https://pkg.go.dev/mellium.im/xmpp/styling#Scan [`Decoder`]: https://pkg.go.dev/mellium.im/xmpp/styling#Decoder _______________________________________________ Standards mailing list Info: https://mail.jabber.org/mailman/listinfo/standards Unsubscribe: [email protected] _______________________________________________
