Skip to content

Commit

Permalink
Introduce Tasks
Browse files Browse the repository at this point in the history
  • Loading branch information
Jakub Filak committed Mar 8, 2016
1 parent dc8f7f7 commit ab817d2
Show file tree
Hide file tree
Showing 6 changed files with 355 additions and 105 deletions.
161 changes: 144 additions & 17 deletions service/report-daemon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,158 @@
#include "report-task.h"
#include "report-dbus-constants.h"

#include <glib-unix.h>
#include <glibmm.h>
#include <giomm.h>

#include <dump_dir.h>

using namespace Glib;

static RefPtr<MainLoop> s_main_loop;
static GDBusObjectManagerServer *object_manager;

static void
on_name_acquired(GDBusConnection *connection,
class ReportDaemonPrivate {
public:
GDBusObjectManagerServer *object_manager;
ReportService *report_service;

bool connected() { return this->object_manager != 0; }
};

ReportDaemon::ReportDaemon() :
d(new ReportDaemonPrivate())
{}

ReportDaemon::~ReportDaemon()
{
delete d;
}

/* static */ ReportDaemon &
ReportDaemon::inst()
{
static ReportDaemon daemon;

return daemon;
}

std::string
ReportDaemon::get_problem_directory(const std::string &problem_entry)
{
std::string problem_dir("/var/tmp");
problem_dir.append(problem_entry.begin() + problem_entry.find_last_of('/'), problem_entry.end());

if (!access(problem_dir.c_str(), R_OK))
return problem_dir;

auto cancellable = Gio::Cancellable::create();
auto connection = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SYSTEM,
cancellable);
if (!connection) {
throw Gio::DBus::Error(Gio::DBus::Error::FAILED,
"Cannot get system bus");
}

auto info = Glib::RefPtr<Gio::DBus::InterfaceInfo>();
auto entry = Gio::DBus::Proxy::create_sync(connection,
"org.freedesktop.problems",
problem_entry,
"org.freedesktop.Problems2.Entry",
cancellable,
info,
Gio::DBus::PROXY_FLAGS_NONE);

if (!entry) {
throw Gio::DBus::Error(Gio::DBus::Error::INVALID_ARGS,
"Problems2 Entry is not accessible");
}


Glib::Variant<std::vector<Glib::ustring> > elements;
entry->get_cached_property(elements, "Elements");

if (!elements) {
throw Gio::DBus::Error(Gio::DBus::Error::FAILED,
"Problems2 Entry does not have property Elements");
}

auto elem_vector = elements.get();
const size_t elems(elem_vector.size());
const size_t dbus_fd_limit(16);

struct dump_dir *dd = dd_create_skeleton(problem_dir.c_str(), -1, 0600, 0);

for (size_t batch = 0; batch < elems; batch += dbus_fd_limit) {
const size_t range(batch + dbus_fd_limit);
auto end(range > elems ? elem_vector.end() : elem_vector.begin() + range);
std::vector<Glib::ustring> b(elem_vector.begin() + batch, end);

auto parameters = Glib::VariantContainerBase::create_tuple({Glib::Variant<std::vector<Glib::ustring> >::create(b),
Glib::Variant<int>::create(1)});

auto in_fds = Gio::UnixFDList::create();
auto out_fds = Gio::UnixFDList::create();
auto reply = entry->call_sync("ReadElements",
parameters,
cancellable,
in_fds,
out_fds,
-1);

batch = range;

Glib::Variant<std::map<std::string, Glib::VariantBase> > data;
reply.get_child(data);
for (auto kv : data.get()) {
Glib::Variant<gint32> fd_pos = Glib::VariantBase::cast_dynamic< Glib::Variant<gint32> >(kv.second);

int fd = out_fds->get(fd_pos.get());
dd_copy_fd(dd, kv.first.c_str(), fd, 0, 0);
close(fd);
}
}
dd_close(dd);
return problem_dir;
}

void
ReportDaemon::settle_connection(GDBusConnection *connection)
{
if (d->connected()) {
g_warning("report-daemon already settled a connection");
return;
}

d->object_manager = g_dbus_object_manager_server_new(REPORTD_DBUS_OBJECT_MANAGER_PATH);

d->report_service = report_service_new(REPORTD_DBUS_SERVICE_PATH);
g_dbus_object_manager_server_export(d->object_manager, G_DBUS_OBJECT_SKELETON(d->report_service));

g_dbus_object_manager_server_set_connection(d->object_manager, connection);
}

/* static */ void
ReportDaemon::on_name_acquired(GDBusConnection *connection,
const gchar *name,
gpointer )
{
g_debug("Session bus with '%s' acquired", name);
ReportDaemon::inst().settle_connection(connection);
}

object_manager = g_dbus_object_manager_server_new(REPORTD_DBUS_OBJECT_MANAGER_PATH);

ReportService *service = report_service_new(REPORTD_DBUS_SERVICE_PATH);
g_dbus_object_manager_server_export(object_manager, G_DBUS_OBJECT_SKELETON(service));

ReportTask *task = report_task_new(REPORTD_DBUS_TASK_BASE_PATH "1");
g_dbus_object_manager_server_export(object_manager, G_DBUS_OBJECT_SKELETON(task));
void
ReportDaemon::register_object(GDBusObjectSkeleton *object)
{
if (!d->connected()) {
/* TODO : throw an exception if the daemon isn't settled yet */
g_warning("report-daemon not yet settled a connection: cannot register an object");
return;
}

g_dbus_object_manager_server_set_connection(object_manager, connection);
g_dbus_object_manager_server_export(d->object_manager, object);
}


static void
on_name_lost(GDBusConnection *,
const gchar *name,
Expand All @@ -52,10 +178,11 @@ on_name_lost(GDBusConnection *,
s_main_loop->quit();
}

void
on_signal_quit(int)
static gboolean
on_signal_quit(gpointer data)
{
s_main_loop->quit();
(*static_cast<RefPtr<MainLoop> *>(data))->quit();
return FALSE;
}

int
Expand All @@ -67,15 +194,15 @@ main(void)
REPORTD_DBUS_BUS_NAME,
G_BUS_NAME_OWNER_FLAGS_NONE,
NULL,
on_name_acquired,
ReportDaemon::on_name_acquired,
on_name_lost,
NULL,
NULL);

s_main_loop = MainLoop::create();

//signal(SIGINT, on_signal_quit);
//signal(SIGTERM, on_signal_quit);
g_unix_signal_add(SIGINT, on_signal_quit, &s_main_loop);
g_unix_signal_add(SIGTERM, on_signal_quit, &s_main_loop);

s_main_loop->run();

Expand Down
26 changes: 24 additions & 2 deletions service/report-daemon.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,30 @@

#include <giomm.h>

G_BEGIN_DECLS
class ReportDaemon {
public:
std::string get_problem_directory (const std::string &);

void register_object (GDBusObjectSkeleton *);


static ReportDaemon& inst();

static void on_name_acquired (GDBusConnection *,
const gchar *,
gpointer);

private:
void settle_connection(GDBusConnection *);

ReportDaemon();
ReportDaemon(const ReportDaemon &) = delete;
ReportDaemon& operator=(const ReportDaemon &) = delete;

class ReportDaemonPrivate *d;

~ReportDaemon();
};

G_END_DECLS

#endif /*__REPORT_DAEMON_H__*/
104 changes: 23 additions & 81 deletions service/report-service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#include "config.h"

#include "report-service.h"
#include "report-task.h"
#include "report-daemon.h"
#include "report-dbus-constants.h"

#include <iostream>
#include <cstring>
Expand All @@ -26,94 +29,32 @@ G_DEFINE_TYPE(ReportService, report_service, G_TYPE_DBUS_OBJECT_SKELETON);

struct _ReportServicePrivate {
ReportDbusService *service_iface;
unsigned long task_cnt;
};

static gboolean
report_service_handle_create_task(ReportDbusService * /*object*/,
GDBusMethodInvocation * /*invocation*/,
const gchar * /*arg_workflow*/,
const gchar * /*arg_problem*/)
report_service_handle_create_task(ReportDbusService * /*object*/,
GDBusMethodInvocation *invocation,
const gchar *arg_workflow,
const gchar *arg_problem,
ReportService *self)
{
return TRUE;
}

static std::string
get_problem_directory(const std::string &problem_entry)
{
std::string problem_dir("/var/tmp");
problem_dir.append(problem_entry.begin() + problem_entry.find_last_of('/'), problem_entry.end());

if (!access(problem_dir.c_str(), R_OK))
return problem_dir;

auto cancellable = Gio::Cancellable::create();
auto connection = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SYSTEM,
cancellable);
if (!connection) {
throw Gio::DBus::Error(Gio::DBus::Error::FAILED,
"Cannot get system bus");
}

auto info = Glib::RefPtr<Gio::DBus::InterfaceInfo>();
auto entry = Gio::DBus::Proxy::create_sync(connection,
"org.freedesktop.problems",
problem_entry,
"org.freedesktop.Problems2.Entry",
cancellable,
info,
Gio::DBus::PROXY_FLAGS_NONE);

if (!entry) {
throw Gio::DBus::Error(Gio::DBus::Error::INVALID_ARGS,
"Problems2 Entry is not accessible");
}


Glib::Variant<std::vector<Glib::ustring> > elements;
entry->get_cached_property(elements, "Elements");

if (!elements) {
throw Gio::DBus::Error(Gio::DBus::Error::FAILED,
"Problems2 Entry does not have property Elements");
if (self->pv->task_cnt == ULONG_MAX) {
g_dbus_method_invocation_return_error(invocation,
G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
"Reportd Service cannot create a new task");
return TRUE;
}

auto elem_vector = elements.get();
const size_t elems(elem_vector.size());
const size_t dbus_fd_limit(16);

struct dump_dir *dd = dd_create_skeleton(problem_dir.c_str(), -1, 0600, 0);

for (size_t batch = 0; batch < elems; batch += dbus_fd_limit) {
const size_t range(batch + dbus_fd_limit);
auto end(range > elems ? elem_vector.end() : elem_vector.begin() + range);
std::vector<Glib::ustring> b(elem_vector.begin() + batch, end);

auto parameters = Glib::VariantContainerBase::create_tuple({Glib::Variant<std::vector<Glib::ustring> >::create(b),
Glib::Variant<int>::create(1)});
unsigned long task_id = self->pv->task_cnt++;
std::string task_path(std::string(REPORTD_DBUS_TASK_BASE_PATH) + std::to_string(task_id));
ReportTask *t = report_task_new(task_path.c_str(), arg_workflow, arg_problem);
ReportDaemon::inst().register_object(G_DBUS_OBJECT_SKELETON(t));

auto in_fds = Gio::UnixFDList::create();
auto out_fds = Gio::UnixFDList::create();
auto reply = entry->call_sync("ReadElements",
parameters,
cancellable,
in_fds,
out_fds,
-1);
GVariant *retval = g_variant_new("(o)", task_path.c_str());
g_dbus_method_invocation_return_value(invocation, retval);

batch = range;

Glib::Variant<std::map<std::string, Glib::VariantBase> > data;
reply.get_child(data);
for (auto kv : data.get()) {
Glib::Variant<gint32> fd_pos = Glib::VariantBase::cast_dynamic< Glib::Variant<gint32> >(kv.second);

int fd = out_fds->get(fd_pos.get());
dd_copy_fd(dd, kv.first.c_str(), fd, 0, 0);
close(fd);
}
}
dd_close(dd);
return problem_dir;
return TRUE;
}

static gboolean
Expand All @@ -124,7 +65,7 @@ report_service_handle_get_workflows(ReportDbusService * /*object*/,
std::string problem_dir;

try {
problem_dir = get_problem_directory(arg_problem);
problem_dir = ReportDaemon::inst().get_problem_directory(arg_problem);
}
catch (const Glib::Error &err) {
g_dbus_method_invocation_return_error(invocation,
Expand Down Expand Up @@ -173,6 +114,7 @@ report_service_init(ReportService *self)
self->pv = G_TYPE_INSTANCE_GET_PRIVATE(self, REPORT_TYPE_SERVICE, ReportServicePrivate);

self->pv->service_iface = report_dbus_service_skeleton_new();
self->pv->task_cnt = 1;

g_signal_connect(self->pv->service_iface,
"handle-create-task",
Expand Down
Loading

0 comments on commit ab817d2

Please sign in to comment.