/*
* Copyright (C) 2011 Canonical, Ltd.
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 3.0 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License version 3.0 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* .
*
* Authored by Mikkel Kamstrup Erlandsen
*/
#include
#include
#include
#include
static gchar *resource_name = NULL;
static gchar *model_name = NULL;
static gchar *peer_name = NULL;
static gboolean linger;
static gboolean private;
static gboolean server;
static gboolean watch_changes;
static GOptionEntry option_entries[] = {
{ "resource", 'r', 0, G_OPTION_ARG_STRING, &resource_name,
"Dump a resource given by name" },
{ "model", 'm', 0, G_OPTION_ARG_STRING, &model_name,
"Dump a model given by name" },
{ "peer", 'p', 0, G_OPTION_ARG_STRING, &peer_name,
"List peers and leader of a swarm" },
{ "linger", '\0', 0, G_OPTION_ARG_NONE, &linger,
"Don't exit, but keep the process running the mainloop" },
{ "private", '\0', 0, G_OPTION_ARG_NONE, &private,
"Use a private (aka peer-2-peer) DBus connection" },
{ "server", '\0', 0, G_OPTION_ARG_NONE, &server,
"Set up a private DBus server. Implies --private and --linger" },
{ "watch-changes", '\0', 0, G_OPTION_ARG_NONE, &watch_changes,
"Watch for changes to the given resource. Implies --linger" },
{ NULL }
};
static void
dump_resource (const gchar *name)
{
DeeResourceManager *rs;
GObject *r;
GError *error;
GVariant *v;
gchar *dump;
rs = dee_resource_manager_get_default ();
error = NULL;
r = dee_resource_manager_load (rs, name, &error);
if (error)
{
g_printerr ("Failed loading resource '%s': %s\n", name, error->message);
exit (4);
}
if (!r)
{
g_printerr ("No parser registered for resource '%s'\n", name);
exit (5);
}
v = dee_serializable_serialize (DEE_SERIALIZABLE (r));
dump = g_variant_print (v, FALSE);
g_printf ("%s\n", dump);
g_free (dump);
g_variant_unref (v);
g_object_unref (r);
}
static guint num_rows_added = 0;
static guint num_rows_changed = 0;
static guint num_rows_deleted = 0;
static void
on_model_trasaction_begin (DeeSharedModel *model, guint64 bsq, guint64 esq,
gpointer user_data)
{
guint n_rows;
gchar *time_str;
GTimeVal time_val;
n_rows = dee_model_get_n_rows (DEE_MODEL (model));
g_get_current_time (&time_val);
time_str = g_time_val_to_iso8601 (&time_val);
g_print ("%s:\n Transaction begin - %u rows (seqnums: "
"%" G_GUINT64_FORMAT " - %" G_GUINT64_FORMAT ")\n",
time_str + 11, n_rows, bsq, esq);
num_rows_added = 0;
num_rows_changed = 0;
num_rows_deleted = 0;
g_free (time_str);
}
static void
increment_callback (DeeModel *model, DeeModelIter *iter, gpointer user_data)
{
guint *int_ptr = (guint*) user_data;
*int_ptr = *int_ptr + 1;
}
static void
on_model_trasaction_end (DeeSharedModel *model, guint64 bsq, guint64 esq,
gpointer user_data)
{
guint n_rows;
n_rows = dee_model_get_n_rows (DEE_MODEL (model));
g_print (" end - %u rows (%u added, %u changed, %u deleted)\n",
n_rows, num_rows_added, num_rows_changed, num_rows_deleted);
}
static void
dump_model (const gchar *name)
{
DeeSharedModel *m;
GMainContext *ctx;
GVariant *v;
gchar *dump;
if (server)
{
m = DEE_SHARED_MODEL (dee_shared_model_new_for_peer (
DEE_PEER (dee_server_new (name))));
dee_model_set_schema (DEE_MODEL (m), "s", "i", NULL);
}
else if (private)
{
m = DEE_SHARED_MODEL (dee_shared_model_new_for_peer (
DEE_PEER (dee_client_new (name))));
}
else
m = DEE_SHARED_MODEL (dee_shared_model_new (name));
ctx = g_main_context_default ();
while (!dee_shared_model_is_synchronized (m))
{
g_main_context_iteration (ctx, TRUE);
}
v = dee_serializable_serialize (DEE_SERIALIZABLE (m));
dump = g_variant_print (v, FALSE);
g_printf ("%s\n", dump);
if (watch_changes)
{
g_signal_connect (m, "begin-transaction",
G_CALLBACK (on_model_trasaction_begin), NULL);
g_signal_connect (m, "end-transaction",
G_CALLBACK (on_model_trasaction_end), NULL);
g_signal_connect (m, "row-added",
G_CALLBACK (increment_callback), &num_rows_added);
g_signal_connect (m, "row-changed",
G_CALLBACK (increment_callback), &num_rows_changed);
g_signal_connect (m, "row-removed",
G_CALLBACK (increment_callback), &num_rows_deleted);
}
if (linger)
{
while (TRUE)
{
g_main_context_iteration (ctx, TRUE);
}
}
g_free (dump);
g_variant_unref (v);
g_object_unref (m);
}
static void
_peer_found_cb (DeePeer *p, const gchar *name)
{
g_printf ("+ %s\n", name);
}
static void
_peer_lost_cb (DeePeer *p, const gchar *name)
{
g_printf ("- %s\n", name);
}
static gboolean timed_out = FALSE;
static gboolean
_timeout_cb ()
{
timed_out = TRUE;
return FALSE;
}
static void
dump_peer (const gchar *name)
{
DeePeer *p;
GMainContext *ctx;
if (server)
p = DEE_PEER (dee_server_new (name));
else if (private)
p = DEE_PEER (dee_client_new (name));
else
p = dee_peer_new (name);
ctx = g_main_context_default ();
g_signal_connect (p, "peer-found", G_CALLBACK (_peer_found_cb), NULL);
g_signal_connect (p, "peer-lost", G_CALLBACK (_peer_lost_cb), NULL);
/* Wait untli we have the leader */
while (!dee_peer_get_swarm_leader (p))
{
g_main_context_iteration (ctx, TRUE);
}
g_printf ("LEADER %s\n", dee_peer_get_swarm_leader (p));
/* If we're serving a private conn stick around indefinitely,
* otherwise quit after 1s */
if (!linger)
g_timeout_add_seconds (1, _timeout_cb, NULL);
while (!timed_out)
{
g_main_context_iteration (ctx, TRUE);
}
}
int
main (int argc, char *argv[])
{
GError *error;
GOptionContext *options;
#if !GLIB_CHECK_VERSION(2, 35, 1)
g_type_init ();
#endif
options = g_option_context_new (NULL);
g_option_context_add_main_entries (options, option_entries, NULL);
error = NULL;
if (!g_option_context_parse (options, &argc, &argv, &error))
{
g_printerr ("Invalid command line: %s\n", error->message);
g_error_free (error);
return 1;
}
if (server)
{
private = TRUE;
linger = TRUE;
}
if (watch_changes)
{
linger = TRUE;
}
if (resource_name)
{
if (model_name || peer_name)
{
g_printerr ("Invalid command line: You must specify precisely one of "
"--resource, --model, or --peer\n");
return 2;
}
dump_resource (resource_name);
}
else if (model_name)
{
if (resource_name || peer_name)
{
g_printerr ("Invalid command line: You must specify precisely one of "
"--resource, --model, or --peer\n");
return 2;
}
dump_model (model_name);
}
else if (peer_name)
{
if (resource_name || model_name)
{
g_printerr ("Invalid command line: You must specify precisely one of "
"--resource, --model, or --peer\n");
return 2;
}
dump_peer (peer_name);
}
else
{
g_printerr ("Invalid command line: Unexpected arguments\n");
return 3;
}
return 0;
}