Cmdline: move cmdline to dbus server (MB#5043)
Implement cmdline with support of dbus server. To enable cmdline with dbus server, use the option '--use-daemon yes/no' in case that you enable dbus service when configuration. In a typical scenario, a new session is created for the purpose of execution of arguments. It is scheduled with other sessions but with a highest priority. Once it becomes active, command line call 'Session.Execute', a newly added method to execute command line arguments. The config name of a session should be known for dbus clients like command line. A new property 'configName' is added in the properties when calling 'Session.GetConfig'. CTRL-C handling are processed once executing a real sync to dbus server. It is mapped to invoke 'Session.Suspend' and 'Session.Abort'. The meaning of '--enable-dbus-service' is expanded accordingly. '--status' without server means printing all running session in the dbus server. '--monitor' could accept an optional config name. If one is given, only attach to a session of that config, otherwise print an error. If none is given, pick the first.
This commit is contained in:
parent
c6ee383995
commit
3fc7e529ea
|
@ -348,7 +348,8 @@ AM_CONDITIONAL([COND_CORE], [test "$enable_core" = "yes"])
|
|||
|
||||
AC_ARG_ENABLE(dbus-service,
|
||||
AS_HELP_STRING([--enable-dbus-service],
|
||||
[enables building the dbus service executable and the wrapper library for it]),
|
||||
[enables building the dbus service executable and all related features
|
||||
(the DBus wrapper library, command line usage of server, etc).]),
|
||||
enable_dbus_service="$enableval",
|
||||
[if test $enable_gui == "no"; then
|
||||
enable_dbus_service="no"
|
||||
|
@ -380,6 +381,7 @@ if test $enable_dbus_service == "yes"; then
|
|||
if test $HAVE_LIBNOTIFY == "yes"; then
|
||||
AC_DEFINE(HAS_NOTIFY, 1, [define if libnotify could be used in dbus service])
|
||||
fi
|
||||
AC_DEFINE(DBUS_SERVICE, 1, [define if dbus service is enabled])
|
||||
fi
|
||||
AC_SUBST(DBUS_CFLAGS)
|
||||
AC_SUBST(DBUS_LIBS)
|
||||
|
|
|
@ -122,9 +122,9 @@ endif
|
|||
# SYNCEVOLUTION_LDADD will be replaced with libsyncebook.la/libsyncecal.la/libsyncsqlite.la
|
||||
# if linking statically against them, empty otherwise;
|
||||
# either way this does not lead to a dependency on those libs - done explicitly
|
||||
syncevolution_LDADD = $(CORE_LDADD) $(KEYRING_LIBS)
|
||||
syncevolution_LDADD = gdbus/libgdbus.la $(CORE_LDADD) $(KEYRING_LIBS)
|
||||
syncevolution_LDFLAGS = $(CORE_LD_FLAGS)
|
||||
syncevolution_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) $(CORE_CXXFLAGS) $(KEYRING_CFLAGS)
|
||||
syncevolution_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) $(CORE_CXXFLAGS) $(KEYRING_CFLAGS) -I$(srcdir)/gdbus
|
||||
syncevolution_DEPENDENCIES = $(EXTRA_LTLIBRARIES) $(CORE_DEP) # $(SYNTHESIS_DEP)
|
||||
|
||||
# rule which is only relevant when compiling Synthesis in subdirectory
|
||||
|
|
|
@ -4027,9 +4027,9 @@ public:
|
|||
};
|
||||
|
||||
/*
|
||||
* A DBus Client Call object handling 0 argument and 1 return value.
|
||||
* A DBus Client Call object handling zero or more parameter and
|
||||
* zero return value.
|
||||
*/
|
||||
template <class R>
|
||||
class DBusClientCall0
|
||||
{
|
||||
const std::string m_destination;
|
||||
|
@ -4038,6 +4038,114 @@ class DBusClientCall0
|
|||
const std::string m_method;
|
||||
const DBusConnectionPtr m_conn;
|
||||
|
||||
/** called by libdbus on error or completion of call */
|
||||
static void dbusCallback (DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
DBusMessagePtr reply = dbus_pending_call_steal_reply (call);
|
||||
const char* errname = dbus_message_get_error_name (reply.get());
|
||||
std::string error;
|
||||
if (errname) {
|
||||
error = errname;
|
||||
}
|
||||
//unmarshal the return results and call user callback
|
||||
(*static_cast <Callback_t *>(user_data))(error);
|
||||
}
|
||||
|
||||
/**
|
||||
* called by libdbus to free the user_data pointer set in
|
||||
* dbus_pending_call_set_notify()
|
||||
*/
|
||||
static void callDataUnref(void *user_data) {
|
||||
delete static_cast <Callback_t *>(user_data);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* called when result of call is available or an error occurred (non-empty string)
|
||||
*/
|
||||
typedef boost::function<void (const std::string &)> Callback_t;
|
||||
|
||||
DBusClientCall0 (const DBusCallObject &object)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
m_method (object.getMethod()),
|
||||
m_conn (object.getConnection())
|
||||
{
|
||||
}
|
||||
|
||||
DBusClientCall0 (const DBusRemoteObject &object, const std::string &method)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
m_method (method),
|
||||
m_conn (object.getConnection())
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
void operator () (const A1 &a1, const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
append_retvals(msg, a1);
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
};
|
||||
|
||||
/** 1 return value and 0 or more parameters */
|
||||
template <class R>
|
||||
class DBusClientCall1
|
||||
{
|
||||
const std::string m_destination;
|
||||
const std::string m_path;
|
||||
const std::string m_interface;
|
||||
const std::string m_method;
|
||||
const DBusConnectionPtr m_conn;
|
||||
|
||||
/** called by libdbus on error or completion of call */
|
||||
static void dbusCallback (DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
|
@ -4067,11 +4175,11 @@ class DBusClientCall0
|
|||
|
||||
public:
|
||||
/**
|
||||
* called when result of call is available (R) or an error occurred (non-empty string)
|
||||
* called when the call is returned or an error occurred (non-empty string)
|
||||
*/
|
||||
typedef boost::function<void (const R &, const std::string &)> Callback_t;
|
||||
|
||||
DBusClientCall0 (const DBusCallObject &object)
|
||||
DBusClientCall1 (const DBusCallObject &object)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
|
@ -4080,7 +4188,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
DBusClientCall0 (const DBusRemoteObject &object, const std::string &method)
|
||||
DBusClientCall1 (const DBusRemoteObject &object, const std::string &method)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
|
@ -4113,6 +4221,207 @@ public:
|
|||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
void operator () (const A1 &a1, const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
append_retvals(msg, a1);
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
void operator () (const A1 &a1, const A2 &a2, const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
append_retvals(msg, a1);
|
||||
append_retvals(msg, a2);
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
};
|
||||
|
||||
/** 3 return value and 0 or more parameters */
|
||||
template <class R1, class R2, class R3>
|
||||
class DBusClientCall3
|
||||
{
|
||||
const std::string m_destination;
|
||||
const std::string m_path;
|
||||
const std::string m_interface;
|
||||
const std::string m_method;
|
||||
const DBusConnectionPtr m_conn;
|
||||
|
||||
/** called by libdbus on error or completion of call */
|
||||
static void dbusCallback (DBusPendingCall *call, void *user_data)
|
||||
{
|
||||
DBusMessagePtr reply = dbus_pending_call_steal_reply (call);
|
||||
const char* errname = dbus_message_get_error_name (reply.get());
|
||||
std::string error;
|
||||
typename dbus_traits<R1>::host_type r1;
|
||||
typename dbus_traits<R2>::host_type r2;
|
||||
typename dbus_traits<R3>::host_type r3;
|
||||
if (!errname) {
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(reply.get(), &iter);
|
||||
//why need connection?
|
||||
dbus_traits<R1>::get(NULL, reply.get(), iter, r1);
|
||||
dbus_traits<R2>::get(NULL, reply.get(), iter, r2);
|
||||
dbus_traits<R3>::get(NULL, reply.get(), iter, r3);
|
||||
} else {
|
||||
error = errname;
|
||||
}
|
||||
//unmarshal the return results and call user callback
|
||||
(*static_cast <Callback_t *>(user_data))(r1, r2, r3, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* called by libdbus to free the user_data pointer set in
|
||||
* dbus_pending_call_set_notify()
|
||||
*/
|
||||
static void callDataUnref(void *user_data) {
|
||||
delete static_cast <Callback_t *>(user_data);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* called when the call is returned or an error occurred (non-empty string)
|
||||
*/
|
||||
typedef boost::function<void (const R1 &, const R2 &, const R3 &, const std::string &)> Callback_t;
|
||||
|
||||
DBusClientCall3 (const DBusCallObject &object)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
m_method (object.getMethod()),
|
||||
m_conn (object.getConnection())
|
||||
{
|
||||
}
|
||||
|
||||
DBusClientCall3 (const DBusRemoteObject &object, const std::string &method)
|
||||
:m_destination (object.getDestination()),
|
||||
m_path (object.getPath()),
|
||||
m_interface (object.getInterface()),
|
||||
m_method (method),
|
||||
m_conn (object.getConnection())
|
||||
{
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
|
||||
template <class A1>
|
||||
void operator () (const A1 &a1, const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
append_retvals(msg, a1);
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
|
||||
template <class A1, class A2>
|
||||
void operator () (const A1 &a1, const A2 &a2, const Callback_t &callback)
|
||||
{
|
||||
DBusPendingCall *call;
|
||||
DBusMessagePtr msg(dbus_message_new_method_call(
|
||||
m_destination.c_str(),
|
||||
m_path.c_str(),
|
||||
m_interface.c_str(),
|
||||
m_method.c_str()));
|
||||
if (!msg) {
|
||||
throw std::runtime_error("dbus_message_new_method_call() failed");
|
||||
}
|
||||
append_retvals(msg, a1);
|
||||
append_retvals(msg, a2);
|
||||
|
||||
//parameter marshaling (none)
|
||||
if (!dbus_connection_send_with_reply(m_conn.get(), msg.get(), &call, -1)) {
|
||||
throw std::runtime_error("dbus_connection_send failed");
|
||||
}
|
||||
|
||||
DBusPendingCallPtr mCall (call);
|
||||
Callback_t *data = new Callback_t(callback);
|
||||
dbus_pending_call_set_notify(mCall.get(),
|
||||
dbusCallback,
|
||||
data,
|
||||
callDataUnref);
|
||||
}
|
||||
};
|
||||
|
||||
class SignalWatch
|
||||
|
@ -4149,6 +4458,52 @@ class SignalWatch
|
|||
virtual ~SignalWatch() {}
|
||||
};
|
||||
|
||||
class SignalWatch0 : public SignalWatch
|
||||
{
|
||||
typedef boost::function<void (void)> Callback_t;
|
||||
guint m_tag;
|
||||
Callback_t *m_callback;
|
||||
|
||||
public:
|
||||
SignalWatch0(const DBusRemoteObject &object,
|
||||
const std::string &signal)
|
||||
: SignalWatch(object, signal), m_tag(0), m_callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SignalWatch0()
|
||||
{
|
||||
if(m_tag) {
|
||||
g_dbus_remove_watch(m_object.getConnection(), m_tag);
|
||||
}
|
||||
if(m_callback) {
|
||||
delete m_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
if(isMatched(msg, data) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
SignalWatch0 *watch = static_cast<SignalWatch0* >(data);
|
||||
(*watch->m_callback)();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
m_callback = new Callback_t(callback);
|
||||
std::string rule = makeSignalRule();
|
||||
m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
|
||||
rule.c_str(),
|
||||
internalCallback,
|
||||
this,
|
||||
NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A1>
|
||||
class SignalWatch1 : public SignalWatch
|
||||
{
|
||||
|
@ -4257,4 +4612,244 @@ class SignalWatch2 : public SignalWatch
|
|||
}
|
||||
};
|
||||
|
||||
template <typename A1, typename A2, typename A3>
|
||||
class SignalWatch3 : public SignalWatch
|
||||
{
|
||||
typedef boost::function<void (const A1 &, const A2 &, const A3 &)> Callback_t;
|
||||
|
||||
guint m_tag;
|
||||
Callback_t *m_callback;
|
||||
public:
|
||||
SignalWatch3(const DBusRemoteObject &object,
|
||||
const std::string &signal)
|
||||
: SignalWatch(object, signal), m_tag(0), m_callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SignalWatch3()
|
||||
{
|
||||
if(m_tag) {
|
||||
g_dbus_remove_watch(m_object.getConnection(), m_tag);
|
||||
}
|
||||
if(m_callback) {
|
||||
delete m_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
if(isMatched(msg, data) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
SignalWatch3<A1, A2, A3> *watch = static_cast<SignalWatch3<A1, A2, A3> *>(data);
|
||||
|
||||
typename dbus_traits<A1>::host_type a1;
|
||||
typename dbus_traits<A2>::host_type a2;
|
||||
typename dbus_traits<A3>::host_type a3;
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
dbus_traits<A1>::get(conn, msg, iter, a1);
|
||||
dbus_traits<A2>::get(conn, msg, iter, a2);
|
||||
dbus_traits<A3>::get(conn, msg, iter, a3);
|
||||
(*watch->m_callback)(a1, a2, a3);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
m_callback = new Callback_t(callback);
|
||||
std::string rule = makeSignalRule();
|
||||
m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
|
||||
rule.c_str(),
|
||||
internalCallback,
|
||||
this,
|
||||
NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A1, typename A2, typename A3, typename A4>
|
||||
class SignalWatch4 : public SignalWatch
|
||||
{
|
||||
typedef boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &)> Callback_t;
|
||||
|
||||
guint m_tag;
|
||||
Callback_t *m_callback;
|
||||
public:
|
||||
SignalWatch4(const DBusRemoteObject &object,
|
||||
const std::string &signal)
|
||||
: SignalWatch(object, signal), m_tag(0), m_callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SignalWatch4()
|
||||
{
|
||||
if(m_tag) {
|
||||
g_dbus_remove_watch(m_object.getConnection(), m_tag);
|
||||
}
|
||||
if(m_callback) {
|
||||
delete m_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
if(isMatched(msg, data) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
SignalWatch4<A1, A2, A3, A4> *watch = static_cast<SignalWatch4<A1, A2, A3, A4> *>(data);
|
||||
|
||||
typename dbus_traits<A1>::host_type a1;
|
||||
typename dbus_traits<A2>::host_type a2;
|
||||
typename dbus_traits<A3>::host_type a3;
|
||||
typename dbus_traits<A4>::host_type a4;
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
dbus_traits<A1>::get(conn, msg, iter, a1);
|
||||
dbus_traits<A2>::get(conn, msg, iter, a2);
|
||||
dbus_traits<A3>::get(conn, msg, iter, a3);
|
||||
dbus_traits<A4>::get(conn, msg, iter, a4);
|
||||
(*watch->m_callback)(a1, a2, a3, a4);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
m_callback = new Callback_t(callback);
|
||||
std::string rule = makeSignalRule();
|
||||
m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
|
||||
rule.c_str(),
|
||||
internalCallback,
|
||||
this,
|
||||
NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A1, typename A2, typename A3, typename A4, typename A5>
|
||||
class SignalWatch5 : public SignalWatch
|
||||
{
|
||||
typedef boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &, const A5 &)> Callback_t;
|
||||
|
||||
guint m_tag;
|
||||
Callback_t *m_callback;
|
||||
public:
|
||||
SignalWatch5(const DBusRemoteObject &object,
|
||||
const std::string &signal)
|
||||
: SignalWatch(object, signal), m_tag(0), m_callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SignalWatch5()
|
||||
{
|
||||
if(m_tag) {
|
||||
g_dbus_remove_watch(m_object.getConnection(), m_tag);
|
||||
}
|
||||
if(m_callback) {
|
||||
delete m_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
if(isMatched(msg, data) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
SignalWatch5<A1, A2, A3, A4, A5> *watch = static_cast<SignalWatch5<A1, A2, A3, A4, A5> *>(data);
|
||||
|
||||
typename dbus_traits<A1>::host_type a1;
|
||||
typename dbus_traits<A2>::host_type a2;
|
||||
typename dbus_traits<A3>::host_type a3;
|
||||
typename dbus_traits<A4>::host_type a4;
|
||||
typename dbus_traits<A5>::host_type a5;
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
dbus_traits<A1>::get(conn, msg, iter, a1);
|
||||
dbus_traits<A2>::get(conn, msg, iter, a2);
|
||||
dbus_traits<A3>::get(conn, msg, iter, a3);
|
||||
dbus_traits<A4>::get(conn, msg, iter, a4);
|
||||
dbus_traits<A5>::get(conn, msg, iter, a5);
|
||||
(*watch->m_callback)(a1, a2, a3, a4, a5);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
m_callback = new Callback_t(callback);
|
||||
std::string rule = makeSignalRule();
|
||||
m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
|
||||
rule.c_str(),
|
||||
internalCallback,
|
||||
this,
|
||||
NULL);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename A1, typename A2, typename A3, typename A4, typename A5, typename A6>
|
||||
class SignalWatch6 : public SignalWatch
|
||||
{
|
||||
typedef boost::function<void (const A1 &, const A2 &, const A3 &, const A4 &, const A5 &, const A6 &)> Callback_t;
|
||||
|
||||
guint m_tag;
|
||||
Callback_t *m_callback;
|
||||
public:
|
||||
SignalWatch6(const DBusRemoteObject &object,
|
||||
const std::string &signal)
|
||||
: SignalWatch(object, signal), m_tag(0), m_callback(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SignalWatch6()
|
||||
{
|
||||
if(m_tag) {
|
||||
g_dbus_remove_watch(m_object.getConnection(), m_tag);
|
||||
}
|
||||
if(m_callback) {
|
||||
delete m_callback;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean internalCallback(DBusConnection *conn, DBusMessage *msg, void *data)
|
||||
{
|
||||
if(isMatched(msg, data) == FALSE) {
|
||||
return TRUE;
|
||||
}
|
||||
SignalWatch6<A1, A2, A3, A4, A5, A6> *watch = static_cast<SignalWatch6<A1, A2, A3, A4, A5, A6> *>(data);
|
||||
|
||||
typename dbus_traits<A1>::host_type a1;
|
||||
typename dbus_traits<A2>::host_type a2;
|
||||
typename dbus_traits<A3>::host_type a3;
|
||||
typename dbus_traits<A4>::host_type a4;
|
||||
typename dbus_traits<A5>::host_type a5;
|
||||
typename dbus_traits<A6>::host_type a6;
|
||||
|
||||
DBusMessageIter iter;
|
||||
dbus_message_iter_init(msg, &iter);
|
||||
dbus_traits<A1>::get(conn, msg, iter, a1);
|
||||
dbus_traits<A2>::get(conn, msg, iter, a2);
|
||||
dbus_traits<A3>::get(conn, msg, iter, a3);
|
||||
dbus_traits<A4>::get(conn, msg, iter, a4);
|
||||
dbus_traits<A5>::get(conn, msg, iter, a5);
|
||||
dbus_traits<A6>::get(conn, msg, iter, a6);
|
||||
(*watch->m_callback)(a1, a2, a3, a4, a5, a6);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void operator () (const Callback_t &callback)
|
||||
{
|
||||
m_callback = new Callback_t(callback);
|
||||
std::string rule = makeSignalRule();
|
||||
m_tag = g_dbus_add_signal_watch(m_object.getConnection(),
|
||||
rule.c_str(),
|
||||
internalCallback,
|
||||
this,
|
||||
NULL);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // INCL_GDBUS_CXX_BRIDGE
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <syncevo/SyncSource.h>
|
||||
#include <syncevo/SyncML.h>
|
||||
#include <syncevo/FileConfigNode.h>
|
||||
#include <syncevo/Cmdline.h>
|
||||
|
||||
#include <synthesis/san.h>
|
||||
|
||||
|
@ -1716,7 +1717,9 @@ class Session : public DBusObjectHelper,
|
|||
|
||||
enum RunOperation {
|
||||
OP_SYNC = 0,
|
||||
OP_RESTORE
|
||||
OP_RESTORE = 1,
|
||||
OP_CMDLINE = 2,
|
||||
OP_NULL
|
||||
};
|
||||
|
||||
static string runOpToString(RunOperation op);
|
||||
|
@ -1726,6 +1729,9 @@ class Session : public DBusObjectHelper,
|
|||
/** listener to listen to changes of sync */
|
||||
SessionListener *m_listener;
|
||||
|
||||
/** Cmdline to execute command line args */
|
||||
boost::shared_ptr<CmdlineWrapper> m_cmdline;
|
||||
|
||||
/** Session.Detach() */
|
||||
void detach(const Caller_t &caller);
|
||||
|
||||
|
@ -1743,6 +1749,9 @@ class Session : public DBusObjectHelper,
|
|||
/** Session.checkPresence() */
|
||||
void checkPresence (string &status);
|
||||
|
||||
/** Session.Execute() */
|
||||
void execute(const vector<string> &args);
|
||||
|
||||
/**
|
||||
* Must be called each time that properties changing the
|
||||
* overall status are changed. Ensures that the corresponding
|
||||
|
@ -1776,6 +1785,7 @@ public:
|
|||
~Session();
|
||||
|
||||
enum {
|
||||
PRI_CMDLINE = -10,
|
||||
PRI_DEFAULT = 0,
|
||||
PRI_CONNECTION = 10,
|
||||
PRI_AUTOSYNC = 20
|
||||
|
@ -1816,7 +1826,7 @@ public:
|
|||
/**
|
||||
* TRUE if the session is ready to take over control
|
||||
*/
|
||||
bool readyToRun() { return (m_syncStatus != SYNC_DONE) && m_sync; }
|
||||
bool readyToRun() { return (m_syncStatus != SYNC_DONE) && (m_runOperation != OP_NULL); }
|
||||
|
||||
/**
|
||||
* transfer control to the session for the duration of the sync,
|
||||
|
@ -1927,8 +1937,28 @@ class CmdlineWrapper
|
|||
/** stream for command line out and err arguments */
|
||||
std::ostream m_cmdlineOutStream;
|
||||
|
||||
/**
|
||||
* implement factory method to create DBusSync instances
|
||||
* This can check 'abort' and 'suspend' command from clients.
|
||||
*/
|
||||
class DBusCmdline : public Cmdline {
|
||||
Session &m_session;
|
||||
public:
|
||||
DBusCmdline(Session &session,
|
||||
const vector<string> &args,
|
||||
ostream &out,
|
||||
ostream &err)
|
||||
:Cmdline(args, out, err), m_session(session)
|
||||
{}
|
||||
|
||||
SyncContext* createSyncClient() {
|
||||
return new DBusSync(m_server, m_session);
|
||||
}
|
||||
};
|
||||
|
||||
/** instance to run command line arguments */
|
||||
Cmdline m_cmdline;
|
||||
DBusCmdline m_cmdline;
|
||||
|
||||
public:
|
||||
/**
|
||||
* constructor to create cmdline instance.
|
||||
|
@ -1938,7 +1968,7 @@ public:
|
|||
*/
|
||||
CmdlineWrapper(Session &session, const vector<string> &args)
|
||||
: m_cmdlineOutStream(&m_outStreamBuf),
|
||||
m_cmdline(args, m_cmdlineOutStream, m_cmdlineOutStream)
|
||||
m_cmdline(session, args, m_cmdlineOutStream, m_cmdlineOutStream)
|
||||
{}
|
||||
|
||||
void parse() { m_cmdline.parse(); }
|
||||
|
@ -2407,6 +2437,9 @@ void ReadOperations::getConfig(bool getTemplate,
|
|||
}
|
||||
}
|
||||
|
||||
//insert 'configName'
|
||||
localConfigs.insert(pair<string, string>("configName", m_configName));
|
||||
|
||||
config.insert(pair<string,map<string, string> >("", localConfigs));
|
||||
|
||||
/* get configurations from sources */
|
||||
|
@ -2746,8 +2779,9 @@ void Session::setConfig(bool update, bool temporary,
|
|||
if (!m_active) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "session is not active, call not allowed at this time");
|
||||
}
|
||||
if (m_sync) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "sync started, cannot change configuration at this time");
|
||||
if (m_runOperation != OP_NULL) {
|
||||
string msg = StringPrintf("%s started, cannot change configuration at this time", runOpToString(m_runOperation).c_str());
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
}
|
||||
if (!update && temporary) {
|
||||
throw std::runtime_error("Clearing existing configuration and temporary configuration changes which only affects the duration of the session are mutually exclusive");
|
||||
|
@ -2828,8 +2862,11 @@ void Session::sync(const std::string &mode, const SourceModes_t &source_modes)
|
|||
if (!m_active) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "session is not active, call not allowed at this time");
|
||||
}
|
||||
if (m_sync) {
|
||||
string msg = StringPrintf("%s started, cannot start(again)", runOpToString(m_runOperation).c_str());
|
||||
if (m_runOperation == OP_SYNC) {
|
||||
string msg = StringPrintf("%s started, cannot start again", runOpToString(m_runOperation).c_str());
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
} else if (m_runOperation != OP_NULL) {
|
||||
string msg = StringPrintf("%s started, cannot start sync", runOpToString(m_runOperation).c_str());
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
}
|
||||
|
||||
|
@ -2888,7 +2925,7 @@ void Session::sync(const std::string &mode, const SourceModes_t &source_modes)
|
|||
|
||||
void Session::abort()
|
||||
{
|
||||
if (!m_sync) {
|
||||
if (m_runOperation != OP_SYNC && m_runOperation != OP_CMDLINE) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "sync not started, cannot abort at this time");
|
||||
}
|
||||
m_syncStatus = SYNC_ABORT;
|
||||
|
@ -2900,7 +2937,7 @@ void Session::abort()
|
|||
|
||||
void Session::suspend()
|
||||
{
|
||||
if (!m_sync) {
|
||||
if (m_runOperation != OP_SYNC && m_runOperation != OP_CMDLINE) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "sync not started, cannot suspend at this time");
|
||||
}
|
||||
m_syncStatus = SYNC_SUSPEND;
|
||||
|
@ -3007,7 +3044,7 @@ Session::Session(DBusServer &server,
|
|||
m_restoreBefore(true),
|
||||
m_restoreSrcTotal(0),
|
||||
m_restoreSrcEnd(0),
|
||||
m_runOperation(OP_SYNC),
|
||||
m_runOperation(OP_NULL),
|
||||
m_listener(NULL),
|
||||
emitStatus(*this, "StatusChanged"),
|
||||
emitProgress(*this, "ProgressChanged")
|
||||
|
@ -3026,6 +3063,7 @@ Session::Session(DBusServer &server,
|
|||
add(this, &Session::getProgress, "GetProgress");
|
||||
add(this, &Session::restore, "Restore");
|
||||
add(this, &Session::checkPresence, "checkPresence");
|
||||
add(this, &Session::execute, "Execute");
|
||||
add(emitStatus);
|
||||
add(emitProgress);
|
||||
}
|
||||
|
@ -3193,7 +3231,7 @@ void Session::sourceProgress(sysync::TProgressEventEnum type,
|
|||
|
||||
void Session::run()
|
||||
{
|
||||
if (m_sync) {
|
||||
if (m_runOperation != OP_NULL) {
|
||||
try {
|
||||
m_syncStatus = SYNC_RUNNING;
|
||||
fireStatus(true);
|
||||
|
@ -3224,6 +3262,8 @@ void Session::run()
|
|||
m_sync->restore(m_restoreDir,
|
||||
m_restoreBefore ? SyncContext::DATABASE_BEFORE_SYNC : SyncContext::DATABASE_AFTER_SYNC);
|
||||
break;
|
||||
case OP_CMDLINE:
|
||||
m_cmdline->run();
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
@ -3238,7 +3278,7 @@ void Session::run()
|
|||
m_syncStatus = SYNC_DONE;
|
||||
m_stepIsWaiting = false;
|
||||
fireStatus(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Session::setFilters(SyncConfig &config)
|
||||
|
@ -3266,10 +3306,13 @@ void Session::restore(const string &dir, bool before, const std::vector<std::str
|
|||
if (!m_active) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "session is not active, call not allowed at this time");
|
||||
}
|
||||
if (m_sync) {
|
||||
if (m_runOperation == OP_RESTORE) {
|
||||
string msg = StringPrintf("restore started, cannot restore again");
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
} else if (m_runOperation != OP_NULL) {
|
||||
// actually this never happen currently, for during the real restore process,
|
||||
// it never poll the sources in default main context
|
||||
string msg = StringPrintf("%s started, cannot restore(again)", runOpToString(m_runOperation).c_str());
|
||||
string msg = StringPrintf("%s started, cannot restore", runOpToString(m_runOperation).c_str());
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
}
|
||||
|
||||
|
@ -3308,11 +3351,32 @@ string Session::runOpToString(RunOperation op)
|
|||
return "sync";
|
||||
case OP_RESTORE:
|
||||
return "restore";
|
||||
case OP_CMDLINE:
|
||||
return "cmdline";
|
||||
default:
|
||||
return "";
|
||||
};
|
||||
}
|
||||
|
||||
void Session::execute(const vector<string> &args)
|
||||
{
|
||||
if (!m_active) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "session is not active, call not allowed at this time");
|
||||
}
|
||||
if (m_runOperation == OP_CMDLINE) {
|
||||
SE_THROW_EXCEPTION(InvalidCall, "cmdline started, cannot start again");
|
||||
} else if (m_runOperation != OP_NULL) {
|
||||
string msg = StringPrintf("%s started, cannot start cmdline", runOpToString(m_runOperation).c_str());
|
||||
SE_THROW_EXCEPTION(InvalidCall, msg);
|
||||
}
|
||||
//create ostream with a specified streambuf
|
||||
m_cmdline.reset(new CmdlineWrapper(*this, args));
|
||||
//args are checked before transferred to dbus server
|
||||
m_cmdline->parse();
|
||||
m_runOperation = OP_CMDLINE;
|
||||
g_main_loop_quit(loop);
|
||||
}
|
||||
|
||||
inline void insertPair(std::map<string, string> ¶ms,
|
||||
const string &key,
|
||||
const string &value)
|
||||
|
@ -4781,7 +4845,7 @@ gboolean DBusServer::connmanPoll (gpointer dbusserver)
|
|||
}connman (conn);
|
||||
|
||||
typedef std::map <std::string, boost::variant <std::vector <std::string> > > PropDict;
|
||||
DBusClientCall0<PropDict> getProp(connman);
|
||||
DBusClientCall1<PropDict> getProp(connman);
|
||||
getProp (boost::bind(&DBusServer::connmanCallback, me, _1, _2));
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -5094,7 +5158,7 @@ BluezManager::BluezManager(DBusServer &server) :
|
|||
m_bluezConn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, true, NULL);
|
||||
if(m_bluezConn) {
|
||||
m_done = false;
|
||||
DBusClientCall0<DBusObject_t> getAdapter(*this, "DefaultAdapter");
|
||||
DBusClientCall1<DBusObject_t> getAdapter(*this, "DefaultAdapter");
|
||||
getAdapter(boost::bind(&BluezManager::defaultAdapterCb, this, _1, _2 ));
|
||||
m_adapterChanged.reset(new SignalWatch1<DBusObject_t>(*this, "DefaultAdapterChanged"));
|
||||
(*m_adapterChanged)(boost::bind(&BluezManager::defaultAdapterChanged, this, _1));
|
||||
|
@ -5130,7 +5194,7 @@ BluezManager::BluezAdapter::BluezAdapter(BluezManager &manager, const string &pa
|
|||
: m_manager(manager), m_path(path), m_devNo(0), m_devReplies(0),
|
||||
m_deviceRemoved(*this, "DeviceRemoved"), m_deviceAdded(*this, "DeviceCreated")
|
||||
{
|
||||
DBusClientCall0<std::vector<DBusObject_t> > listDevices(*this, "ListDevices");
|
||||
DBusClientCall1<std::vector<DBusObject_t> > listDevices(*this, "ListDevices");
|
||||
listDevices(boost::bind(&BluezAdapter::listDevicesCb, this, _1, _2));
|
||||
//m_deviceRemoved.reset(new SignalWatch1<DBusObject_t>(*this, "DeviceRemoved"));
|
||||
m_deviceRemoved(boost::bind(&BluezAdapter::deviceRemoved, this, _1));
|
||||
|
@ -5182,7 +5246,7 @@ void BluezManager::BluezAdapter::deviceCreated(const DBusObject_t &object)
|
|||
BluezManager::BluezDevice::BluezDevice (BluezAdapter &adapter, const string &path)
|
||||
: m_adapter(adapter), m_path(path), m_reply(false), m_propertyChanged(*this, "PropertyChanged")
|
||||
{
|
||||
DBusClientCall0<PropDict> getProperties(*this, "GetProperties");
|
||||
DBusClientCall1<PropDict> getProperties(*this, "GetProperties");
|
||||
getProperties(boost::bind(&BluezDevice::getPropertiesCb, this, _1, _2));
|
||||
|
||||
m_propertyChanged(boost::bind(&BluezDevice::propertyChanged, this, _1, _2));
|
||||
|
|
|
@ -55,6 +55,21 @@ Cmdline::Cmdline(int argc, const char * const * argv, ostream &out, ostream &err
|
|||
m_validSourceProps(SyncSourceConfig::getRegistry())
|
||||
{}
|
||||
|
||||
Cmdline::Cmdline(const vector<string> &args, ostream &out, ostream &err) :
|
||||
m_args(args),
|
||||
m_out(out),
|
||||
m_err(err),
|
||||
m_validSyncProps(SyncConfig::getRegistry()),
|
||||
m_validSourceProps(SyncSourceConfig::getRegistry())
|
||||
{
|
||||
m_argc = args.size();
|
||||
m_argvArray.reset(new const char *[args.size()]);
|
||||
for(int i = 0; i < m_argc; i++) {
|
||||
m_argvArray[i] = m_args[i].c_str();
|
||||
}
|
||||
m_argv = m_argvArray.get();
|
||||
}
|
||||
|
||||
bool Cmdline::parse()
|
||||
{
|
||||
int opt = 1;
|
||||
|
@ -159,6 +174,22 @@ bool Cmdline::parse()
|
|||
} else if(boost::iequals(m_argv[opt], "--keyring")||
|
||||
boost::iequals(m_argv[opt], "-k")) {
|
||||
m_keyring = true;
|
||||
} else if(boost::iequals(m_argv[opt], "--use-daemon")) {
|
||||
opt++;
|
||||
if (opt >= m_argc) {
|
||||
usage(true, string("missing parameter for ") + cmdOpt(m_argv[opt - 1]));
|
||||
return false;
|
||||
}
|
||||
if(boost::iequals(m_argv[opt], "yes")) {
|
||||
m_useDaemon = "yes";
|
||||
} else if(boost::iequals(m_argv[opt], "no")) {
|
||||
m_useDaemon = "no";
|
||||
} else {
|
||||
usage(true, string("parameter '") + m_restore + "' for " + cmdOpt(m_argv[opt - 1]) + " must be 'yes' or 'no'");
|
||||
}
|
||||
} else if(boost::iequals(m_argv[opt], "--monitor")||
|
||||
boost::iequals(m_argv[opt], "-m")) {
|
||||
m_monitor = true;
|
||||
} else {
|
||||
usage(false, string(m_argv[opt]) + ": unknown parameter");
|
||||
return false;
|
||||
|
@ -176,6 +207,35 @@ bool Cmdline::parse()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Cmdline::isSync()
|
||||
{
|
||||
//make sure command line arguments really try to run sync
|
||||
if(m_usage || m_version) {
|
||||
return false;
|
||||
} else if(m_printServers || boost::trim_copy(m_server) == "?") {
|
||||
return false;
|
||||
} else if(m_printTemplates || m_dontrun) {
|
||||
return false;
|
||||
} else if(m_argc == 1 || (!m_useDaemon.empty() && m_argc == 3)) {
|
||||
return false;
|
||||
} else if(m_printConfig || m_remove) {
|
||||
return false;
|
||||
} else if (m_server == "" && m_argc > 1) {
|
||||
return false;
|
||||
} else if(m_configure || m_migrate) {
|
||||
return false;
|
||||
} else if(m_status || m_printSessions) {
|
||||
return false;
|
||||
} else if(!m_restore.empty()) {
|
||||
return false;
|
||||
} else if(m_dryrun) {
|
||||
return false;
|
||||
} else if(!m_run && (m_syncProps.size() || m_sourceProps.size())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Cmdline::run() {
|
||||
// --dry-run is only supported by some operations.
|
||||
// Be very strict about it and make sure it is off in all
|
||||
|
@ -204,7 +264,7 @@ bool Cmdline::run() {
|
|||
}
|
||||
} else if (m_dontrun) {
|
||||
// user asked for information
|
||||
} else if (m_argc == 1) {
|
||||
} else if (m_argc == 1 || (!m_useDaemon.empty() && m_argc == 3)) {
|
||||
// no parameters: list databases and short usage
|
||||
const SourceRegistry ®istry(SyncSource::getSourceRegistry());
|
||||
boost::shared_ptr<FilterConfigNode> sharedNode(new VolatileConfigNode());
|
||||
|
@ -1102,6 +1162,10 @@ void Cmdline::usage(bool full, const string &error, const string ¶m)
|
|||
" they were not stored there already:" << endl <<
|
||||
" --keyring --configure --sync-property proxyPassword=foo" << endl <<
|
||||
"" << endl <<
|
||||
"--use-daemon [yes/no]" << endl <<
|
||||
" Run operations in cooperation with the background sync daemon;" << endl <<
|
||||
" enabled by default if it is installed" << endl <<
|
||||
"" << endl <<
|
||||
" When passwords were stored in the keyring, their value is set to '-'" << endl <<
|
||||
" in the configuration. This means that when running a synchronization" << endl <<
|
||||
" without the --keyring argument, the password has to be entered" << endl <<
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
using namespace std;
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/scoped_array.hpp>
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
SE_BEGIN_CXX
|
||||
|
@ -42,6 +43,7 @@ public:
|
|||
* @param err stderr stream for error messages
|
||||
*/
|
||||
Cmdline(int argc, const char * const *argv, ostream &out, ostream &err);
|
||||
Cmdline(const vector<string> &args, ostream &out, ostream &err);
|
||||
|
||||
/**
|
||||
* parse the command line options
|
||||
|
@ -52,6 +54,20 @@ public:
|
|||
|
||||
bool run();
|
||||
|
||||
string useDaemon() { return m_useDaemon; }
|
||||
|
||||
/** whether '--monitor' is set */
|
||||
bool monitor() { return m_monitor; }
|
||||
|
||||
/** whether 'status' is set */
|
||||
bool status() { return m_status; }
|
||||
|
||||
/* server name */
|
||||
string getConfigName() { return m_server; }
|
||||
|
||||
/* check whether command line runs sync. It should be called after parsing. */
|
||||
bool isSync();
|
||||
|
||||
protected:
|
||||
class Bool {
|
||||
public:
|
||||
|
@ -62,10 +78,16 @@ protected:
|
|||
bool m_value;
|
||||
};
|
||||
|
||||
// vector to store strings for arguments
|
||||
vector<string> m_args;
|
||||
|
||||
int m_argc;
|
||||
const char * const * m_argv;
|
||||
ostream &m_out, &m_err;
|
||||
|
||||
//array to store pointers of arguments
|
||||
boost::scoped_array<const char *> m_argvArray;
|
||||
|
||||
Bool m_quiet;
|
||||
Bool m_dryrun;
|
||||
Bool m_status;
|
||||
|
@ -81,6 +103,8 @@ protected:
|
|||
Bool m_printSessions;
|
||||
Bool m_dontrun;
|
||||
Bool m_keyring;
|
||||
Bool m_monitor;
|
||||
string m_useDaemon;
|
||||
FilterConfigNode::ConfigFilter m_syncProps, m_sourceProps;
|
||||
const ConfigPropertyRegistry &m_validSyncProps;
|
||||
const ConfigPropertyRegistry &m_validSourceProps;
|
||||
|
|
|
@ -200,6 +200,7 @@ class LoggerBase : public Logger
|
|||
} \
|
||||
} while(false)
|
||||
|
||||
#define SE_LOG_SHOW(_instance, _prefix, _format, _args...) SE_LOG(Logger::SHOW, _instance, _prefix, _format, ##_args)
|
||||
#define SE_LOG_ERROR(_instance, _prefix, _format, _args...) SE_LOG(Logger::ERROR, _instance, _prefix, _format, ##_args)
|
||||
#define SE_LOG_WARNING(_instance, _prefix, _format, _args...) SE_LOG(Logger::WARNING, _instance, _prefix, _format, ##_args)
|
||||
#define SE_LOG_INFO(_instance, _prefix, _format, _args...) SE_LOG(Logger::INFO, _instance, _prefix, _format, ##_args)
|
||||
|
|
|
@ -421,6 +421,14 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
|
|||
*/
|
||||
static void resetSignals() { s_flags = SuspendFlags(); }
|
||||
|
||||
/**
|
||||
* handleSignals() is called in a signal handler,
|
||||
* which can only call reentrant functions. Our
|
||||
* logging code is not reentrant and thus has
|
||||
* to be called outside of the signal handler.
|
||||
*/
|
||||
static void printSignals();
|
||||
|
||||
bool getRemoteInitiated() {return m_remoteInitiated;}
|
||||
void setRemoteInitiated(bool remote) {m_remoteInitiated = remote;}
|
||||
|
||||
|
@ -716,14 +724,6 @@ class SyncContext : public SyncConfig, public ConfigUserInterface {
|
|||
*/
|
||||
string getSynthesisDatadir() { return getRootPath() + "/.synthesis"; }
|
||||
|
||||
/**
|
||||
* handleSignals() is called in a signal handler,
|
||||
* which can only call reentrant functions. Our
|
||||
* logging code is not reentrant and thus has
|
||||
* to be called outside of the signal handler.
|
||||
*/
|
||||
static void printSignals();
|
||||
|
||||
/**
|
||||
* return true if "delayedabort" session variable is true
|
||||
*/
|
||||
|
|
|
@ -38,6 +38,24 @@ using namespace std;
|
|||
#include <dlfcn.h>
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
|
||||
#include <gdbus-cxx-bridge.h>
|
||||
|
||||
struct SourceStatus {
|
||||
string m_mode;
|
||||
string m_status;
|
||||
uint32_t m_error;
|
||||
};
|
||||
template<> struct dbus_traits<SourceStatus> :
|
||||
public dbus_struct_traits<SourceStatus,
|
||||
dbus_member<SourceStatus, string, &SourceStatus::m_mode,
|
||||
dbus_member<SourceStatus, string, &SourceStatus::m_status,
|
||||
dbus_member_single<SourceStatus, uint32_t, &SourceStatus::m_error> > > >
|
||||
{};
|
||||
#endif
|
||||
|
||||
SE_BEGIN_CXX
|
||||
|
||||
#if defined(ENABLE_MAEMO) && defined (ENABLE_EBOOK)
|
||||
|
@ -83,6 +101,244 @@ class KeyringSyncCmdline : public Cmdline {
|
|||
}
|
||||
};
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
class RemoteSession;
|
||||
typedef map<string, StringMap> Config_t;
|
||||
|
||||
/**
|
||||
* Act as a dbus server. All requests to dbus server
|
||||
* are passed through this class.
|
||||
*/
|
||||
class RemoteDBusServer : public DBusRemoteObject
|
||||
{
|
||||
public:
|
||||
RemoteDBusServer();
|
||||
|
||||
virtual const char *getDestination() const {return "org.syncevolution";}
|
||||
virtual const char *getPath() const {return "/org/syncevolution/Server";}
|
||||
virtual const char *getInterface() const {return "org.syncevolution.Server";}
|
||||
virtual DBusConnection *getConnection() const {return m_conn.get();}
|
||||
GMainLoop *getLoop() { return m_loop; }
|
||||
|
||||
/**
|
||||
* check whether the server is started and can be attached.
|
||||
* If not, report an error message
|
||||
*/
|
||||
bool checkStarted();
|
||||
|
||||
/**
|
||||
* execute arguments from command line
|
||||
* @param args the arguments of command line
|
||||
* @param config the config name parsed from arguments if has
|
||||
* @param runSync arguments to run a sync
|
||||
* @return true if successfully
|
||||
*/
|
||||
bool execute(const vector<string> &args, const string &config, bool runSync);
|
||||
|
||||
/**
|
||||
* To implement the feature of '--monitor' option, monitor a
|
||||
* given config if there is a session running.
|
||||
* If config is empty, then peak a running session to monitor.
|
||||
* @param config the config name parsed from arguments if has
|
||||
* @return true if successfully
|
||||
*/
|
||||
bool monitor(const string &config);
|
||||
|
||||
/**
|
||||
* To implement the feature of '--status' without a server.
|
||||
* get and print all running sessions in the dbus server
|
||||
*/
|
||||
bool runningSessions();
|
||||
|
||||
/** whether the dbus call(s) has/have completed */
|
||||
bool done() { return m_replyTotal == m_replyCounter; }
|
||||
|
||||
/** one reply returns. Increase reply counter. */
|
||||
void replyInc();
|
||||
|
||||
/** set whether there is an error */
|
||||
void setResult(bool result) { m_result = result; }
|
||||
|
||||
private:
|
||||
/** call 'Attach' until it returns */
|
||||
void attachSync();
|
||||
|
||||
/** callback of 'Server.Attach' */
|
||||
void attachCb(const string &error);
|
||||
|
||||
/** callback of 'Server.GetSessions' */
|
||||
void getSessionsCb(const vector<string> &sessions, const string &error);
|
||||
|
||||
/** callback of 'Server.SessionChanged' */
|
||||
void sessionChangedCb(const DBusObject_t &object, bool active);
|
||||
|
||||
/** callback of 'Server.LogOutput' */
|
||||
void logOutputCb(const DBusObject_t &object, uint32_t level, const string &log);
|
||||
|
||||
/** callback of calling 'Server.StartSession' */
|
||||
void startSessionCb(const DBusObject_t &session, const string &error);
|
||||
|
||||
/** update active session vector according to 'SessionChanged' signal */
|
||||
void updateSessions(const string &session, bool active);
|
||||
|
||||
/** check m_session is active */
|
||||
bool isActive();
|
||||
|
||||
/** get all running sessions. Used internally. */
|
||||
void getRunningSessions();
|
||||
|
||||
/** set the total number of replies we must wait */
|
||||
void resetReplies(int total = 1)
|
||||
{
|
||||
m_replyTotal = total;
|
||||
m_replyCounter = 0;
|
||||
}
|
||||
|
||||
/** signal handler for 'CTRL-C' */
|
||||
static void handleSignal(int sig);
|
||||
|
||||
// session used for signal handler,
|
||||
// used to call 'suspend' and 'abort'
|
||||
static boost::shared_ptr<RemoteSession> g_session;
|
||||
|
||||
// the main loop
|
||||
GMainLoop *m_loop;
|
||||
// connection
|
||||
DBusConnectionPtr m_conn;
|
||||
// whether client can attach to the daemon.
|
||||
// It is also used to indicate whether daemon is ready to use.
|
||||
bool m_attached;
|
||||
// error flag
|
||||
bool m_result;
|
||||
// config name
|
||||
string m_configName;
|
||||
// active session object path
|
||||
boost::shared_ptr<string> m_activeSession;
|
||||
// session created or monitored
|
||||
boost::shared_ptr<RemoteSession> m_session;
|
||||
// active sessions after listening to 'SessionChanged' signals
|
||||
vector<string> m_activeSessions;
|
||||
// all sessions in dbus server
|
||||
vector<boost::shared_ptr<RemoteSession> > m_sessions;
|
||||
// the number of total dbus calls
|
||||
unsigned int m_replyTotal;
|
||||
// the number of returned dbus calls
|
||||
unsigned int m_replyCounter;
|
||||
// sessions which are running
|
||||
vector<boost::weak_ptr<RemoteSession> > m_runSessions;
|
||||
// listen to dbus server signal 'SessionChanged'
|
||||
boost::shared_ptr<SignalWatch2<DBusObject_t, bool> > m_sessionChanged;
|
||||
// listen to dbus server signal 'LogOutput'
|
||||
boost::shared_ptr<SignalWatch3<DBusObject_t, uint32_t, string> > m_logOutput;
|
||||
};
|
||||
|
||||
/**
|
||||
* Act as a session. All requests to a session are passed
|
||||
* through this class.
|
||||
*/
|
||||
class RemoteSession : public DBusRemoteObject
|
||||
{
|
||||
public:
|
||||
RemoteSession(RemoteDBusServer &server, const std::string &path);
|
||||
virtual const char *getDestination() const {return "org.syncevolution";}
|
||||
virtual const char *getPath() const {return m_path.c_str();}
|
||||
virtual const char *getInterface() const {return "org.syncevolution.Session";}
|
||||
virtual DBusConnection *getConnection() const {return m_server.getConnection();}
|
||||
|
||||
/**
|
||||
* call 'Execute' method of 'Session' in dbus server
|
||||
* without waiting for return
|
||||
*/
|
||||
void executeAsync(const vector<string> &args);
|
||||
|
||||
/**
|
||||
* call 'GetStatus' method of 'Session' in dbus server
|
||||
* without waiting for return
|
||||
*/
|
||||
void getStatusAsync();
|
||||
|
||||
/**
|
||||
* call 'Suspend' method of 'Session' in dbus server
|
||||
* without waiting for return
|
||||
*/
|
||||
void suspendAsync();
|
||||
|
||||
/**
|
||||
* call 'Abort' method of 'Session' in dbus server
|
||||
* without waiting for return
|
||||
*/
|
||||
void abortAsync();
|
||||
|
||||
/**
|
||||
* call 'GetConfig' method of 'Session' in dbus server
|
||||
* without waiting for return
|
||||
*/
|
||||
void getConfigAsync();
|
||||
|
||||
/** get config name of this session */
|
||||
string configName() { return m_configName; }
|
||||
|
||||
/** status 'done' is sent by session */
|
||||
bool statusDone() { return boost::iequals(m_status, "done"); }
|
||||
|
||||
/** get current status */
|
||||
string status() { return m_status; }
|
||||
|
||||
/** monitor status of the sesion until it is done */
|
||||
void monitorSync();
|
||||
|
||||
/** pass through logoutput and print them if m_output is true */
|
||||
void logOutput(Logger::Level level, const string &log);
|
||||
|
||||
/** set whether to print output */
|
||||
void setOutput(bool output) { m_output = output; }
|
||||
|
||||
typedef std::map<std::string, SourceStatus> SourceStatuses_t;
|
||||
|
||||
private:
|
||||
/** callback of calling 'Session.Execute' */
|
||||
void executeCb(const string &error);
|
||||
|
||||
/** callback of 'Session.GetStatus' */
|
||||
void getStatusCb(const string &status,
|
||||
uint32_t errorCode,
|
||||
const SourceStatuses_t &sourceStatus,
|
||||
const string &error);
|
||||
|
||||
/** callback of 'Session.GetConfig' */
|
||||
void getConfigCb(const Config_t &config, const string &error);
|
||||
|
||||
/** callback of 'Session.StatusChanged' */
|
||||
void statusChangedCb(const string &status,
|
||||
uint32_t errorCode,
|
||||
const SourceStatuses_t &sourceStatus);
|
||||
|
||||
/** callback of 'Session.Suspend' */
|
||||
void suspendCb(const string &);
|
||||
|
||||
/** callback of 'Session.Abort' */
|
||||
void abortCb(const string &);
|
||||
|
||||
/** dbus server */
|
||||
RemoteDBusServer &m_server;
|
||||
|
||||
/* whether to log output */
|
||||
bool m_output;
|
||||
|
||||
/** object path */
|
||||
string m_path;
|
||||
|
||||
/** config name of the session */
|
||||
string m_configName;
|
||||
|
||||
/** current status */
|
||||
string m_status;
|
||||
|
||||
/** signal watch 'StatusChanged' */
|
||||
SignalWatch3<std::string, uint32_t, SourceStatuses_t> m_statusChanged;
|
||||
};
|
||||
#endif
|
||||
|
||||
extern "C"
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
|
@ -130,8 +386,6 @@ int main( int argc, char **argv )
|
|||
free(exe);
|
||||
|
||||
try {
|
||||
EDSAbiWrapperInit();
|
||||
|
||||
/*
|
||||
* don't log errors to cerr: LogRedirect cannot distinguish
|
||||
* between our valid error messages and noise from other
|
||||
|
@ -139,12 +393,92 @@ int main( int argc, char **argv )
|
|||
* level DEVELOPER, while output is at most INFO)
|
||||
*/
|
||||
KeyringSyncCmdline cmdline(argc, argv, std::cout, std::cout);
|
||||
if (cmdline.parse() &&
|
||||
cmdline.run()) {
|
||||
return 0;
|
||||
} else {
|
||||
if(!cmdline.parse()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(cmdline.monitor()) {
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
// monitor a session
|
||||
RemoteDBusServer server;
|
||||
if(server.checkStarted() && server.monitor(cmdline.getConfigName())) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: can't monitor running a session. "
|
||||
"this syncevolution binary was compiled without support of daemon. "
|
||||
"Try to re-configure with '--enable-dbus-service' option.");
|
||||
return 1;
|
||||
#endif
|
||||
} else if(cmdline.status() &&
|
||||
cmdline.getConfigName().empty()) {
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
// '--status' and no server name, try to get running sessions
|
||||
RemoteDBusServer server;
|
||||
if(server.checkStarted() && server.runningSessions()) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#else
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: can't get all running sessions. "
|
||||
"this syncevolution binary was compiled without support of daemon. "
|
||||
"Try to re-configure with '--enable-dbus-service' option.");
|
||||
return 1;
|
||||
#endif
|
||||
} else if(boost::iequals(cmdline.useDaemon(), "yes") ||
|
||||
cmdline.useDaemon().empty()){
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
RemoteDBusServer server;
|
||||
|
||||
vector<string> arguments;
|
||||
for(int i = 0; i < argc; i++) {
|
||||
arguments.push_back(argv[i]);
|
||||
}
|
||||
|
||||
bool result;
|
||||
result = server.execute(arguments, cmdline.getConfigName(), cmdline.isSync());
|
||||
//if '--use-daemon' is not set as 'yes' and can't execute
|
||||
//successfully using daemon, falling back to run sync in the process
|
||||
if(boost::iequals(cmdline.useDaemon(), "yes") && result == false) {
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: this syncevolution can't run by using daemon. "
|
||||
"Either run syncevolution with '--use-daemon no' or without option.");
|
||||
return 1;
|
||||
} else if(result == true) {
|
||||
return 0;
|
||||
} else if(cmdline.useDaemon().empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "WARNING: can't run syncevolution with daemon. "
|
||||
"Try to run your arguments directly.");
|
||||
}
|
||||
#else
|
||||
if(boost::iequals(cmdline.useDaemon(), "yes")) {
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: this syncevolution binary was compiled without support of daemon. "
|
||||
"Either run syncevolution with '--use-daemon no' or without option.");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// if forcing not using daemon or trying to use daemon with failures,
|
||||
// run arguments in the process
|
||||
if(cmdline.useDaemon().empty() ||
|
||||
boost::iequals(cmdline.useDaemon(), "no")) {
|
||||
EDSAbiWrapperInit();
|
||||
|
||||
/*
|
||||
* don't log errors to cerr: LogRedirect cannot distinguish
|
||||
* between our valid error messages and noise from other
|
||||
* libs, therefore it would get suppressed (logged at
|
||||
* level DEVELOPER, while output is at most INFO)
|
||||
*/
|
||||
if (cmdline.run()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} catch ( const std::exception &ex ) {
|
||||
SE_LOG_ERROR(NULL, NULL, "%s", ex.what());
|
||||
} catch (...) {
|
||||
|
@ -154,4 +488,497 @@ int main( int argc, char **argv )
|
|||
return 1;
|
||||
}
|
||||
|
||||
#ifdef DBUS_SERVICE
|
||||
/********************** RemoteDBusServer implementation **************************/
|
||||
RemoteDBusServer::RemoteDBusServer()
|
||||
:m_attached(false), m_result(true),
|
||||
m_replyTotal(0), m_replyCounter(0)
|
||||
{
|
||||
m_loop = g_main_loop_new (NULL, FALSE);
|
||||
m_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, true, NULL);
|
||||
|
||||
if(m_conn) {
|
||||
//check whether we can attach to the daemon
|
||||
attachSync();
|
||||
if(m_attached) {
|
||||
m_sessionChanged.reset(new SignalWatch2<DBusObject_t, bool>(*this,"SessionChanged"));
|
||||
(*m_sessionChanged)(boost::bind(&RemoteDBusServer::sessionChangedCb, this, _1, _2));
|
||||
m_logOutput.reset(new SignalWatch3<DBusObject_t, uint32_t, string>(*this,"LogOutput"));
|
||||
(*m_logOutput)(boost::bind(&RemoteDBusServer::logOutputCb, this, _1, _2, _3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteDBusServer::checkStarted()
|
||||
{
|
||||
if(!m_attached) {
|
||||
SE_LOG_SHOW(NULL, NULL,"The Daemon can't be started successfully. Try to check it is successfully setup.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void RemoteDBusServer::attachSync()
|
||||
{
|
||||
resetReplies();
|
||||
DBusClientCall0 attach(*this, "Attach");
|
||||
attach(boost::bind(&RemoteDBusServer::attachCb, this, _1));
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDBusServer::attachCb(const string &error)
|
||||
{
|
||||
replyInc();
|
||||
if(error.empty()) {
|
||||
// don't print error information, leave it to caller
|
||||
m_attached = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDBusServer::logOutputCb(const DBusObject_t &object,
|
||||
uint32_t level,
|
||||
const string &log)
|
||||
{
|
||||
if(m_session &&
|
||||
(boost::equals(object.c_str(), getPath()) ||
|
||||
boost::equals(m_session->getPath(), object.c_str()))) {
|
||||
m_session->logOutput((Logger::Level)level, log);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDBusServer::sessionChangedCb(const DBusObject_t &object, bool active)
|
||||
{
|
||||
// update active sessions if needed
|
||||
updateSessions(object, active);
|
||||
g_main_loop_quit(m_loop);
|
||||
}
|
||||
|
||||
boost::shared_ptr<RemoteSession> RemoteDBusServer::g_session;
|
||||
void RemoteDBusServer::handleSignal(int sig)
|
||||
{
|
||||
SyncContext::handleSignal(sig);
|
||||
if(g_session) {
|
||||
const SuspendFlags &flags = SyncContext::getSuspendFlags();
|
||||
if(flags.state == SuspendFlags::CLIENT_SUSPEND) {
|
||||
g_session->suspendAsync();
|
||||
} else if(flags.state == SuspendFlags::CLIENT_ABORT) {
|
||||
g_session->abortAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteDBusServer::execute(const vector<string> &args, const string &peer, bool runSync)
|
||||
{
|
||||
//the basic workflow is:
|
||||
//1) start a session
|
||||
//2) waiting for the session becomes active
|
||||
//3) execute 'arguments' once it is active
|
||||
|
||||
// start a new session
|
||||
DBusClientCall1<DBusObject_t> call(*this, "StartSession");
|
||||
call(peer, boost::bind(&RemoteDBusServer::startSessionCb, this, _1, _2));
|
||||
|
||||
// wait until 'StartSession' returns
|
||||
resetReplies();
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
if(m_session) {
|
||||
|
||||
//if session is not active, just wait
|
||||
while(!isActive()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
Logger::Level level = LoggerBase::instance().getLevel();
|
||||
LoggerBase::instance().setLevel(Logger::DEBUG);
|
||||
resetReplies();
|
||||
m_session->executeAsync(args);
|
||||
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
//if encoutering errors, return
|
||||
if(!m_result) {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
//g_session is used to pass 'abort' or 'suspend' commands
|
||||
//make sure session is ready to run
|
||||
g_session = m_session;
|
||||
|
||||
//set up signal handlers to send 'suspend' or 'abort' to dbus server
|
||||
//only do this once session is executing and can suspend and abort
|
||||
struct sigaction new_action, old_action;
|
||||
struct sigaction old_term_action;
|
||||
|
||||
if(runSync) {
|
||||
memset(&new_action, 0, sizeof(new_action));
|
||||
new_action.sa_handler = handleSignal;
|
||||
sigemptyset(&new_action.sa_mask);
|
||||
sigaction(SIGINT, NULL, &old_action);
|
||||
if (old_action.sa_handler == SIG_DFL) {
|
||||
sigaction(SIGINT, &new_action, NULL);
|
||||
}
|
||||
|
||||
sigaction(SIGTERM, NULL, &old_term_action);
|
||||
if (old_term_action.sa_handler == SIG_DFL) {
|
||||
sigaction(SIGTERM, &new_action, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
//wait until status is 'done'
|
||||
while(!m_session->statusDone()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
if(runSync) {
|
||||
sigaction (SIGINT, &old_action, NULL);
|
||||
sigaction (SIGTERM, &old_term_action, NULL);
|
||||
}
|
||||
|
||||
//reset session
|
||||
g_session.reset();
|
||||
//restore logging level
|
||||
LoggerBase::instance().setLevel(level);
|
||||
}
|
||||
return m_result;
|
||||
}
|
||||
|
||||
void RemoteDBusServer::startSessionCb(const DBusObject_t &sessionPath, const string &error)
|
||||
{
|
||||
replyInc();
|
||||
if(!error.empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: %s", error.c_str());
|
||||
m_result = false;
|
||||
g_main_loop_quit(m_loop);
|
||||
return;
|
||||
}
|
||||
m_session.reset(new RemoteSession(*this, sessionPath));
|
||||
g_main_loop_quit(m_loop);
|
||||
}
|
||||
|
||||
bool RemoteDBusServer::isActive()
|
||||
{
|
||||
/** if current session is active and then start to call 'Execute' method */
|
||||
if(m_session) {
|
||||
BOOST_FOREACH(const string &session, m_activeSessions) {
|
||||
if(boost::equals(m_session->getPath(), session.c_str())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void RemoteDBusServer::getRunningSessions()
|
||||
{
|
||||
//get all sessions
|
||||
DBusClientCall1<vector<string> > sessions(*this, "GetSessions");
|
||||
sessions(boost::bind(&RemoteDBusServer::getSessionsCb, this, _1, _2));
|
||||
resetReplies();
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
// get status of each session
|
||||
resetReplies(m_sessions.size());
|
||||
BOOST_FOREACH(boost::shared_ptr<RemoteSession> &session, m_sessions) {
|
||||
session->getStatusAsync();
|
||||
}
|
||||
|
||||
// waiting for all sessions 'GetStatus'
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
// collect running sessions
|
||||
BOOST_FOREACH(boost::shared_ptr<RemoteSession> &session, m_sessions) {
|
||||
if(boost::istarts_with(session->status(), "running")) {
|
||||
m_runSessions.push_back(boost::weak_ptr<RemoteSession>(session));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteDBusServer::runningSessions()
|
||||
{
|
||||
//the basic working flow is:
|
||||
//1) get all sessions
|
||||
//2) check each session and collect running sessions
|
||||
//3) get config name of running sessions and print them
|
||||
getRunningSessions();
|
||||
|
||||
if(m_runSessions.empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "No running session(s) just now");
|
||||
} else {
|
||||
SE_LOG_SHOW(NULL, NULL, "Running session(s): ");
|
||||
|
||||
resetReplies(m_runSessions.size());
|
||||
BOOST_FOREACH(boost::weak_ptr<RemoteSession> &session, m_runSessions) {
|
||||
boost::shared_ptr<RemoteSession> lock = session.lock();
|
||||
if(lock) {
|
||||
lock->getConfigAsync();
|
||||
}
|
||||
}
|
||||
|
||||
//wait for 'GetConfig' returns
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
// print all running sessions
|
||||
BOOST_FOREACH(boost::weak_ptr<RemoteSession> &session, m_runSessions) {
|
||||
boost::shared_ptr<RemoteSession> lock = session.lock();
|
||||
if(!lock->configName().empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, " %s (%s)", lock->configName().c_str(), lock->getPath());
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_result;
|
||||
}
|
||||
|
||||
void RemoteDBusServer::getSessionsCb(const vector<string> &sessions, const string &error)
|
||||
{
|
||||
replyInc();
|
||||
if(!error.empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: %s", error.c_str());
|
||||
m_result = false;
|
||||
g_main_loop_quit(m_loop);
|
||||
return;
|
||||
}
|
||||
|
||||
//create local objects for sessions
|
||||
BOOST_FOREACH(const DBusObject_t &value, sessions) {
|
||||
boost::shared_ptr<RemoteSession> session(new RemoteSession(*this, value));
|
||||
m_sessions.push_back(session);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDBusServer::updateSessions(const string &session, bool active)
|
||||
{
|
||||
if(active) {
|
||||
//add it into active list
|
||||
m_activeSessions.push_back(session);
|
||||
} else {
|
||||
//if inactive, remove it from active list
|
||||
for(vector<string>::iterator it = m_activeSessions.begin();
|
||||
it != m_activeSessions.end(); ++it) {
|
||||
if(boost::equals(session, *it)) {
|
||||
m_activeSessions.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteDBusServer::replyInc()
|
||||
{
|
||||
// increase counter and check whether all replies are returned
|
||||
m_replyCounter++;
|
||||
if(done()) {
|
||||
g_main_loop_quit(m_loop);
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteDBusServer::monitor(const string &peer)
|
||||
{
|
||||
//the basic working flow is:
|
||||
//1) get all sessions
|
||||
//2) check each session and collect running sessions
|
||||
//3) peak one session with the given peer and monitor it
|
||||
getRunningSessions();
|
||||
if(peer.empty()) {
|
||||
//peak the first running sessions
|
||||
BOOST_FOREACH(boost::weak_ptr<RemoteSession> &session, m_runSessions) {
|
||||
boost::shared_ptr<RemoteSession> lock = session.lock();
|
||||
if(lock) {
|
||||
m_session = lock;
|
||||
resetReplies();
|
||||
m_session->getConfigAsync();
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
m_session->monitorSync();
|
||||
return m_result;
|
||||
}
|
||||
}
|
||||
//if no running session
|
||||
SE_LOG_SHOW(NULL, NULL, "No session is going to be monitored.");
|
||||
} else {
|
||||
string peerNorm = SyncConfig::normalizeConfigString(peer);
|
||||
|
||||
// get config names of running sessions
|
||||
resetReplies(m_runSessions.size());
|
||||
BOOST_FOREACH(boost::weak_ptr<RemoteSession> &session, m_runSessions) {
|
||||
boost::shared_ptr<RemoteSession> lock = session.lock();
|
||||
lock->getConfigAsync();
|
||||
}
|
||||
//wait for 'GetConfig' returns
|
||||
while(!done()) {
|
||||
g_main_loop_run(m_loop);
|
||||
}
|
||||
|
||||
//find a session with the given name
|
||||
vector<boost::shared_ptr<RemoteSession> >::iterator it = m_sessions.begin();
|
||||
while(it != m_sessions.end()) {
|
||||
string tempNorm = (*it)->configName();
|
||||
if(boost::iequals(peerNorm, tempNorm)) {
|
||||
m_session = *it;
|
||||
//monitor the session status
|
||||
m_session->monitorSync();
|
||||
return m_result;
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
||||
if(it == m_sessions.end()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "'%s' is not running", peer.c_str());
|
||||
}
|
||||
}
|
||||
return m_result;
|
||||
}
|
||||
|
||||
|
||||
/********************** RemoteSession implementation **************************/
|
||||
RemoteSession::RemoteSession(RemoteDBusServer &server,
|
||||
const string &path)
|
||||
:m_server(server), m_output(false), m_path(path),
|
||||
m_statusChanged(*this, "StatusChanged")
|
||||
{
|
||||
m_statusChanged(boost::bind(&RemoteSession::statusChangedCb, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
void RemoteSession::executeAsync(const vector<string> &args)
|
||||
{
|
||||
//start to print outputs
|
||||
m_output = true;
|
||||
DBusClientCall0 call(*this, "Execute");
|
||||
call(args, boost::bind(&RemoteSession::executeCb, this, _1));
|
||||
}
|
||||
|
||||
void RemoteSession::executeCb(const string &error)
|
||||
{
|
||||
m_server.replyInc();
|
||||
if(!error.empty()) {
|
||||
SE_LOG_SHOW(NULL, NULL, "ERROR: %s", error.c_str());
|
||||
m_server.setResult(false);
|
||||
//end to print outputs
|
||||
m_output = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::statusChangedCb(const string &status,
|
||||
uint32_t errorCode,
|
||||
const SourceStatuses_t &sourceStatus)
|
||||
{
|
||||
m_status = status;
|
||||
if(status == "done") {
|
||||
//if session is done, quit the loop
|
||||
g_main_loop_quit(m_server.getLoop());
|
||||
m_output = false;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::getStatusAsync()
|
||||
{
|
||||
DBusClientCall3<string, uint32_t, SourceStatuses_t> call(*this, "GetStatus");
|
||||
call(boost::bind(&RemoteSession::getStatusCb, this, _1, _2, _3, _4));
|
||||
}
|
||||
|
||||
void RemoteSession::getStatusCb(const string &status,
|
||||
uint32_t errorCode,
|
||||
const SourceStatuses_t &sourceStatus,
|
||||
const string &error)
|
||||
{
|
||||
m_server.replyInc();
|
||||
if(!error.empty()) {
|
||||
//ignore the error
|
||||
return;
|
||||
}
|
||||
m_status = status;
|
||||
}
|
||||
|
||||
void RemoteSession::getConfigAsync()
|
||||
{
|
||||
DBusClientCall1<Config_t> call(*this, "GetConfig");
|
||||
call(false, boost::bind(&RemoteSession::getConfigCb, this, _1, _2));
|
||||
}
|
||||
|
||||
void RemoteSession::getConfigCb(const Config_t &config, const string &error)
|
||||
{
|
||||
m_server.replyInc();
|
||||
if(!error.empty()) {
|
||||
//ignore the error
|
||||
return;
|
||||
}
|
||||
// set config name
|
||||
Config_t::const_iterator it = config.find("");
|
||||
if(it != config.end()) {
|
||||
StringMap global = it->second;
|
||||
StringMap::iterator git = global.find("configName");
|
||||
if(git != global.end()) {
|
||||
m_configName = git->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::suspendAsync()
|
||||
{
|
||||
DBusClientCall0 suspend(*this, "Suspend");
|
||||
suspend(boost::bind(&RemoteSession::suspendCb, this, _1));
|
||||
}
|
||||
|
||||
void RemoteSession::suspendCb(const string &error)
|
||||
{
|
||||
//avoid logging messages in handleSignal
|
||||
SyncContext::printSignals();
|
||||
if(!error.empty()) {
|
||||
m_server.setResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::abortCb(const string &error)
|
||||
{
|
||||
//avoid logging messages in handleSignal
|
||||
SyncContext::printSignals();
|
||||
if(!error.empty()) {
|
||||
m_server.setResult(false);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::abortAsync()
|
||||
{
|
||||
DBusClientCall0 abort(*this, "Abort");
|
||||
abort(boost::bind(&RemoteSession::abortCb, this, _1));
|
||||
}
|
||||
|
||||
void RemoteSession::logOutput(Logger::Level level, const string &log)
|
||||
{
|
||||
if(m_output) {
|
||||
SE_LOG(level, NULL, NULL, "%s", log.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteSession::monitorSync()
|
||||
{
|
||||
m_output = true;
|
||||
Logger::Level level = LoggerBase::instance().getLevel();
|
||||
LoggerBase::instance().setLevel(Logger::DEBUG);
|
||||
SE_LOG(Logger::SHOW, NULL, NULL, "Monitoring '%s' (%s)\n", m_configName.c_str(), getPath());
|
||||
|
||||
while(!statusDone()) {
|
||||
g_main_loop_run(m_server.getLoop());
|
||||
}
|
||||
|
||||
SE_LOG(Logger::SHOW, NULL, NULL, "Monitoring done");
|
||||
LoggerBase::instance().setLevel(level);
|
||||
m_output = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
SE_END_CXX
|
||||
|
|
Loading…
Reference in a new issue