/libstrophe

Rust ergonomic wrapper for libstrophe

Primary LanguageRust

libstrophe

Documentation

See full documentation

Usage

Add this to your Cargo.toml:

[dependencies]
libstrophe = "0.19.3"

Maintenance Build Status Documentation

libstrophe - ergonomic wrapper for Rust

This library provides high level ergonomic bindings for libstrophe, an XMPP client library.

Documentation

The documentation for this library covers only Rust specific bits and refers to original library documentation in most other cases.

Workflow

The general workflow is quite similar to what you get with the C library. The topmost object is Context. It contains platform-specific bits like logging and memory allocation. Plus an event loop used to keep things going. This crate wraps logging with the facilities provided by log crate (provided the default rust-log feature is enabled). Memory allocation is also handled by Rust native means. When a Connection is created it will temporarily consume the Context. After all of the setup is done, call one of the connect_*() methods to retrieve the Context back. In this manner a single Context can be used for multiple Connections consequently. When you're done with setting up Connections for the Context, use run() or run_once() methods to start the event loop rolling.

Safety

This create tries to be as safe as possible. Yet it's not always possible to guarantee that when wrapping a C library. The following assumptions are made which might not necessary be true and thus might introduce unsafety:

  • Context event loop methods are borrowing self immutably considering it immutable (or more specifically having interior mutability)

The main objects in this crate are marked as Send and it should be indeed be safe to send them between threads. Yet, no major investigation of the library source code has been performed to ensure that this is true.

Initialization and shutdown

You don't need to call the initialization function, it's done automatically when creating a Context. Yet you might want to call the shutdown() function when your application terminates. Be aware though that the initialization can be called only once in the program lifetime so you won't be able to use the library properly after you called shutdown().

Callbacks

The crate has the ability to store callbacks taking ownership of them so you can pass closures and not care about storing them externally. There are some things to note about it though. It's not always possible to know whether the underlying library accepted the callback. The crate will keep the closure internally in either case, though it may not ever be called by the library. You can still remove the callback with the corresponding *handler_delete() or *handler_clear() method.

Due to the way the the C libstrophe library is implemented and how Rust optimizes monomorphization, your callbacks must actually be compiled to different function with separate addresses when you pass them to the same handler setup method. So if you want to pass 2 callbacks hander_add ensure that their code is unique and rust didn't merge them into a single function behind the scenes. You can test whether 2 callbacks are same or not with the Connection::*handlers_same() family of functions. If it returns true than you will only be able to pass one of them to the corresponding handler function, the other will be silently ignored.

Due to the fact that the crate uses userdata to pass the actual user callback, it's not possible to use userdata inside the callbacks for your own data. So if you need to have a state between callback invocations you must use closures.

Because the main objects are marked as Send and we store callbacks inside them, all callbacks must also be Send.

Examples

let connection_handler = |ctx: &libstrophe::Context,
                          _conn: &mut libstrophe::Connection,
                          _evt: libstrophe::ConnectionEvent| {
   ctx.stop();
};

let ctx = libstrophe::Context::new_with_default_logger();
let mut conn = libstrophe::Connection::new(ctx);
conn.set_jid("example@127.0.0.1");
conn.set_pass("password");
let ctx = conn.connect_client(None, None, connection_handler).unwrap();
ctx.run();
libstrophe::shutdown();

For more complete examples see this crate src/examples directory and libstrophe examples.

Crate features

The following features are provided:

  • rust-log - enabled by default, makes the create integrate into Rust logging facilities
  • libstrophe-0_9_3 - enabled by default, enables functionality specific to libstrophe-0.9.3
  • libstrophe-0_10_0 - enabled by default, enables functionality specific to libstrophe-0.10.0
  • libstrophe-0_11_0 - enabled by default, enables functionality specific to libstrophe-0.11.0
  • libstrophe-0_12_0 - enabled by default, enables functionality specific to libstrophe-0.12.0
  • buildtime_bindgen - forces regeneration of the bindings instead of relying on the pre-generated sources

License: LGPL-3.0