Thursday, August 25, 2016

Introducing snapd-glib

World, meet snapd-glib. It's a new library that makes it easy for GLib based projects (e.g. software centres) to access the daemon that allows you to query, install and remove Snaps. If C is not for you, you can use all the functionality in Python (using GObject Introspection) and Vala. In the future it will support Qt/QML through a wrapper library.

snapd uses a REST API and snapd-glib very closely matches that. The behaviour is best understood by reading the documentation of that API. To give you a taste of how it works, here's an example that shows how to find and install the VLC snap.

Step 1: Connecting to snapd

The connection to snapd is controlled through the SnapdClient object. This object has all the methods required to communicate with snapd. Create and connect with:

    g_autoptr(SnapdClient) c = snapd_client_new ();
    if (!snapd_client_connect_sync (c, NULL, &error))
        // Something went wrong


Step 2: Find the VLC snap 

Asking snapd to perform a find causes it to contact the remote Snap store. This can take some time so consider using an asynchronous call for this. This is the synchronous version:

    g_autoptr(GPtrArray) snaps =
        snapd_client_find_sync (c,
                                SNAPD_FIND_FLAGS_NONE, "vlc",
                                NULL, NULL, &error);
    if (snaps == NULL)
        // Something went wrong
    for (int i = 0; i < snaps->len; i++) {
        SnapdSnap *snap = snaps->pdata[i];
        // Do something with this snap information
    }


Step 3: Authenticate 

Some methods require authorisation in the form of a Macaroon (the link is quite complex but in practise it's just a couple of strings). To get a Macaroon you need to provide credentials to snapd. In Ubuntu this is your Ubuntu account, but different snapd installations may use another authentication provider.

Convert credentials to authorization with:

    g_autoptr(SnapdAuthData) auth_data =
        snapd_login_sync (email, password, code,
                          NULL, &error);
    if (auth_data == NULL)
        return EXIT_FAILURE;

    snapd_client_set_auth_data (c, auth_data)

Once you have a Macaroon you can store it somewhere and re-use it next time you need it. Then the authorization can be created with:

    g_autoptr(SnapdAuthData) auth_data =
        snapd_auth_data_new (macaroon, discharges);
    snapd_client_set_auth_data (c, auth_data);

Step 4: Install VLC 

In step 2 we could determine the VLC snap has the name "vlc". Since this involves downloading ~100Mb and is going to take some time the asynchronous method is used. There is a callback that gives updates on the progress of the install and one that is called when the operation completes:
 
    snapd_client_install_async (c,
                                "vlc", NULL,
                                progress_cb, NULL,
                                NULL,
                                install_cb, NULL);


static void
progress_cb (SnapdClient *client,

             SnapdTask *main_task, GPtrArray *tasks,
             gpointer user_data)
{

    // Tell the user what's happening
}

static void
install_cb (GObject *object, GAsyncResult *result,

            gpointer user_data)
{
    g_autoptr(GError) error = NULL;

    if (snapd_client_install_finish (SNAPD_CLIENT (object),

                                     result, &error))
        // It installed!
    else
        // Something went wrong...
}


Conclusion 

With snapd-glib and the above code as a starting point you should be able to start integrating Snap support into your project. Have fun!