PIM Manager: initial D-Bus binding
Adds a subset of the D-Bus API to syncevo-dbus-server. Views are resources that are attached to the client and thus get destroyed automatically when the client disconnects from D-Bus. In addition, failures for calls to the client's ViewAgent delete the view. In this case, the client stays connected, because it might only have destroyed one agent with others still active.
This commit is contained in:
parent
7651b432c2
commit
a8118eff89
|
@ -143,9 +143,13 @@ int main(int argc, char **argv, char **envp)
|
|||
// make this object the main owner of the connection
|
||||
boost::scoped_ptr<DBusObject> obj(new DBusObject(conn, "foo", "bar", true));
|
||||
|
||||
boost::scoped_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
|
||||
boost::shared_ptr<SyncEvo::Server> server(new SyncEvo::Server(loop, shutdownRequested, restart, conn, duration));
|
||||
server->activate();
|
||||
|
||||
#ifdef ENABLE_DBUS_PIM
|
||||
boost::shared_ptr<GDBusCXX::DBusObjectHelper> manager(SyncEvo::CreateContactManager(server));
|
||||
#endif
|
||||
|
||||
if (gdbus) {
|
||||
unsetenv("G_DBUS_DEBUG");
|
||||
}
|
||||
|
@ -153,6 +157,9 @@ int main(int argc, char **argv, char **envp)
|
|||
dbus_bus_connection_undelay(conn);
|
||||
server->run();
|
||||
SE_LOG_DEBUG(NULL, NULL, "cleaning up");
|
||||
#ifdef ENABLE_DBUS_PIM
|
||||
manager.reset();
|
||||
#endif
|
||||
server.reset();
|
||||
obj.reset();
|
||||
guard.reset();
|
||||
|
|
277
src/dbus/server/pim/manager.cpp
Normal file
277
src/dbus/server/pim/manager.cpp
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) version 3.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "manager.h"
|
||||
#include "../resource.h"
|
||||
#include "../client.h"
|
||||
|
||||
SE_BEGIN_CXX
|
||||
|
||||
static const char * const MANAGER_SERVICE = "org._01.pim.contacts";
|
||||
static const char * const MANAGER_PATH = "/org/01/pim/contacts";
|
||||
static const char * const MANAGER_IFACE = "org._01.pim.contacts.Manager";
|
||||
static const char * const AGENT_IFACE = "org._01.pim.contacts.ViewAgent";
|
||||
static const char * const CONTROL_IFACE = "org._01.pim.contacts.ViewControl";
|
||||
|
||||
Manager::Manager(const boost::shared_ptr<Server> &server) :
|
||||
DBusObjectHelper(server->getConnection(),
|
||||
MANAGER_PATH,
|
||||
MANAGER_IFACE),
|
||||
m_server(server)
|
||||
{
|
||||
// TODO: claim MANAGER_SERVICE name on connection
|
||||
|
||||
// Prevent automatic shut down during idle times, because we need
|
||||
// to keep our unified address book available.
|
||||
m_server->autoTermRef();
|
||||
}
|
||||
|
||||
|
||||
void Manager::init()
|
||||
{
|
||||
// TODO: restore sort order
|
||||
m_sortOrder = "first/last";
|
||||
initFolks();
|
||||
initSorting();
|
||||
|
||||
add(this, &Manager::start, "Start");
|
||||
add(this, &Manager::stop, "Stop");
|
||||
add(this, &Manager::setSortOrder, "SetSortOrder");
|
||||
add(this, &Manager::getSortOrder, "GetSortOrder");
|
||||
add(this, &Manager::search, "Search");
|
||||
|
||||
// Ready, make it visible via D-Bus.
|
||||
activate();
|
||||
}
|
||||
|
||||
void Manager::initFolks()
|
||||
{
|
||||
m_folks = IndividualAggregator::create();
|
||||
}
|
||||
|
||||
void Manager::initSorting()
|
||||
{
|
||||
// TODO: mirror m_sortOrder in m_folks main view
|
||||
}
|
||||
|
||||
Manager::~Manager()
|
||||
{
|
||||
m_server->autoTermUnref();
|
||||
}
|
||||
|
||||
boost::shared_ptr<Manager> Manager::create(const boost::shared_ptr<Server> &server)
|
||||
{
|
||||
boost::shared_ptr<Manager> manager(new Manager(server));
|
||||
manager->m_self = manager;
|
||||
manager->init();
|
||||
return manager;
|
||||
}
|
||||
|
||||
boost::shared_ptr<GDBusCXX::DBusObjectHelper> CreateContactManager(const boost::shared_ptr<Server> &server)
|
||||
{
|
||||
return Manager::create(server);
|
||||
}
|
||||
|
||||
void Manager::start()
|
||||
{
|
||||
m_folks->start();
|
||||
}
|
||||
|
||||
void Manager::stop()
|
||||
{
|
||||
// TODO: if there are no active searches, then recreate aggregator
|
||||
if (true) {
|
||||
initFolks();
|
||||
initSorting();
|
||||
}
|
||||
}
|
||||
|
||||
void Manager::setSortOrder(const std::string &order)
|
||||
{
|
||||
// TODO: check string and change order,
|
||||
// store persistently
|
||||
m_sortOrder = order;
|
||||
initSorting();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects a normal IndividualView to a D-Bus client.
|
||||
* Provides the org.01.pim.contacts.ViewControl API.
|
||||
*/
|
||||
class ViewResource : public Resource, public GDBusCXX::DBusObjectHelper
|
||||
{
|
||||
static unsigned int m_counter;
|
||||
|
||||
boost::weak_ptr<ViewResource> m_self;
|
||||
GDBusCXX::DBusRemoteObject m_viewAgent;
|
||||
boost::shared_ptr<IndividualView> m_view;
|
||||
boost::weak_ptr<Client> m_owner;
|
||||
GDBusCXX::DBusClientCall0 m_contactsModified,
|
||||
m_contactsAdded,
|
||||
m_contactsRemoved;
|
||||
|
||||
ViewResource(const boost::shared_ptr<IndividualView> view,
|
||||
const boost::shared_ptr<Client> &owner,
|
||||
GDBusCXX::connection_type *connection,
|
||||
const GDBusCXX::Caller_t &ID,
|
||||
const GDBusCXX::DBusObject_t &agentPath) :
|
||||
GDBusCXX::DBusObjectHelper(connection,
|
||||
StringPrintf("%s/view%d", MANAGER_PATH, m_counter++),
|
||||
CONTROL_IFACE),
|
||||
m_viewAgent(connection,
|
||||
agentPath,
|
||||
AGENT_IFACE,
|
||||
ID),
|
||||
m_view(view),
|
||||
m_owner(owner),
|
||||
// use ViewAgent interface
|
||||
m_contactsModified(m_viewAgent, "ContactsModified"),
|
||||
m_contactsAdded(m_viewAgent, "ContactsAdded"),
|
||||
m_contactsRemoved(m_viewAgent, "ContactsRemoved")
|
||||
{}
|
||||
|
||||
/**
|
||||
* Invokes one of m_contactsModified/Added/Removed. A failure of
|
||||
* the asynchronous call indicates that the client is dead and
|
||||
* that its view can be purged.
|
||||
*/
|
||||
void sendChange(const GDBusCXX::DBusClientCall0 &call,
|
||||
int start, int count)
|
||||
{
|
||||
call.start(boost::bind(ViewResource::sendDone,
|
||||
m_self,
|
||||
_1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Used as callback for sending changes to the ViewAgent. Only
|
||||
* holds weak references and thus does not prevent deleting view
|
||||
* or client.
|
||||
*/
|
||||
static void sendDone(const boost::weak_ptr<ViewResource> &self,
|
||||
const std::string &error)
|
||||
{
|
||||
if (!error.empty()) {
|
||||
// remove view because it is no longer needed
|
||||
SE_LOG_DEBUG(NULL, NULL, "ViewAgent method call failed, deleting view: %s", error.c_str());
|
||||
boost::shared_ptr<ViewResource> r = self.lock();
|
||||
if (r) {
|
||||
r->close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void init(boost::shared_ptr<ViewResource> self)
|
||||
{
|
||||
m_self = self;
|
||||
|
||||
// activate D-Bus interface
|
||||
add(this, &ViewResource::readContacts, "ReadContacts");
|
||||
add(this, &ViewResource::close, "Close");
|
||||
add(this, &ViewResource::refineSearch, "RefineSearch");
|
||||
activate();
|
||||
|
||||
// TODO: aggregate changes into batches
|
||||
m_view->m_modifiedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
|
||||
this,
|
||||
boost::cref(m_contactsModified),
|
||||
_1,
|
||||
1).track(self));
|
||||
m_view->m_addedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
|
||||
this,
|
||||
boost::cref(m_contactsAdded),
|
||||
_1,
|
||||
1).track(self));
|
||||
m_view->m_removedSignal.connect(IndividualView::ChangeSignal_t::slot_type(&ViewResource::sendChange,
|
||||
this,
|
||||
boost::cref(m_contactsRemoved),
|
||||
_1,
|
||||
1).track(self));
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
static boost::shared_ptr<ViewResource> create(const boost::shared_ptr<IndividualView> &view,
|
||||
const boost::shared_ptr<Client> &owner,
|
||||
GDBusCXX::connection_type *connection,
|
||||
const GDBusCXX::Caller_t &ID,
|
||||
const GDBusCXX::DBusObject_t &agentPath)
|
||||
{
|
||||
boost::shared_ptr<ViewResource> viewResource(new ViewResource(view, owner,
|
||||
connection,
|
||||
ID,
|
||||
agentPath));
|
||||
viewResource->init(viewResource);
|
||||
return viewResource;
|
||||
}
|
||||
|
||||
/** org.01.pim.contacts.ViewControl.ReadContacts() */
|
||||
void readContacts(int start, int count, std::vector<FolksIndividualCXX> &contacts)
|
||||
{
|
||||
// TODO
|
||||
SE_THROW("not implemented");
|
||||
}
|
||||
|
||||
/** org.01.pim.contacts.ViewControl.Close() */
|
||||
void close()
|
||||
{
|
||||
// Removing the resource from its owner will drop the last
|
||||
// reference and delete it when we return.
|
||||
boost::shared_ptr<ViewResource> r = m_self.lock();
|
||||
if (r) {
|
||||
boost::shared_ptr<Client> c = m_owner.lock();
|
||||
if (c) {
|
||||
c->detach(r.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** ViewControl.RefineSearch() */
|
||||
void refineSearch(const StringMap &filter)
|
||||
{
|
||||
// TODO
|
||||
SE_THROW("not implemented");
|
||||
}
|
||||
};
|
||||
unsigned int ViewResource::m_counter;
|
||||
|
||||
GDBusCXX::DBusObject_t Manager::search(const GDBusCXX::Caller_t &ID,
|
||||
const boost::shared_ptr<GDBusCXX::Watch> &watch,
|
||||
const StringMap &filter,
|
||||
const GDBusCXX::DBusObject_t &agentPath)
|
||||
{
|
||||
// Create and track view which is owned by the caller.
|
||||
boost::shared_ptr<Client> client = m_server->addClient(ID, watch);
|
||||
|
||||
boost::shared_ptr<IndividualView> view;
|
||||
// TODO: parse filter
|
||||
view = m_folks->getMainView();
|
||||
|
||||
boost::shared_ptr<ViewResource> viewResource(ViewResource::create(view,
|
||||
client,
|
||||
getConnection(),
|
||||
ID,
|
||||
agentPath));
|
||||
client->attach(boost::shared_ptr<Resource>(viewResource));
|
||||
|
||||
// created local resource
|
||||
return viewResource->getPath();
|
||||
}
|
||||
|
||||
SE_END_CXX
|
81
src/dbus/server/pim/manager.h
Normal file
81
src/dbus/server/pim/manager.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* Copyright (C) 2012 Intel Corporation
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) version 3.
|
||||
*
|
||||
* 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 for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301 USA
|
||||
*/
|
||||
|
||||
/**
|
||||
* The D-Bus IPC binding for folks.h and SyncEvolution's
|
||||
* PBAP support.
|
||||
*/
|
||||
|
||||
#ifndef INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
|
||||
#define INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
|
||||
|
||||
#include "folks.h"
|
||||
#include "../server.h"
|
||||
|
||||
#include <syncevo/declarations.h>
|
||||
SE_BEGIN_CXX
|
||||
|
||||
/**
|
||||
* Implementation of org._01.pim.contacts.Manager.
|
||||
*/
|
||||
class Manager : public GDBusCXX::DBusObjectHelper
|
||||
{
|
||||
boost::weak_ptr<Manager> m_self;
|
||||
boost::shared_ptr<Server> m_server;
|
||||
boost::shared_ptr<IndividualAggregator> m_folks;
|
||||
std::string m_sortOrder;
|
||||
|
||||
Manager(const boost::shared_ptr<Server> &server);
|
||||
void init();
|
||||
void initFolks();
|
||||
void initSorting();
|
||||
|
||||
/** Manager.Start() */
|
||||
void start();
|
||||
/** Manager.Stop() */
|
||||
void stop();
|
||||
/** Manager.SetSortOrder() */
|
||||
void setSortOrder(const std::string &order);
|
||||
/** Manager.GetSortOrder() */
|
||||
std::string getSortOrder() { return m_sortOrder; }
|
||||
/** Manager.Search() */
|
||||
GDBusCXX::DBusObject_t search(const GDBusCXX::Caller_t &ID,
|
||||
const boost::shared_ptr<GDBusCXX::Watch> &watch,
|
||||
const StringMap &filter,
|
||||
const GDBusCXX::DBusObject_t &agentPath);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Creates an instance of the Manager which runs as part
|
||||
* of the given server, using the same D-Bus connection
|
||||
* and using the server's services (tracking clients,
|
||||
* startup/shutdown).
|
||||
*
|
||||
* While the Manager exists, it blocks auto-termination
|
||||
* of the server and serves method calls as part of the
|
||||
* main event loop.
|
||||
*/
|
||||
static boost::shared_ptr<Manager> create(const boost::shared_ptr<Server> &server);
|
||||
|
||||
~Manager();
|
||||
};
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
#endif // INCL_SYNCEVO_DBUS_SERVER_PIM_MANAGER
|
|
@ -51,7 +51,8 @@ src_dbus_server_libsyncevodbusserver_la_CXXFLAGS = $(SYNCEVOLUTION_CXXFLAGS) $(C
|
|||
|
||||
if COND_DBUS_PIM
|
||||
src_dbus_server_server_cpp_files += \
|
||||
src/dbus/server/pim/folks.cpp
|
||||
src/dbus/server/pim/folks.cpp \
|
||||
src/dbus/server/pim/manager.cpp
|
||||
src_dbus_server_libsyncevodbusserver_la_LIBADD += $(FOLKS_LIBS)
|
||||
src_dbus_server_libsyncevodbusserver_la_CXXFLAGS += $(FOLKS_CFLAGS)
|
||||
endif
|
||||
|
|
|
@ -650,6 +650,11 @@ public:
|
|||
virtual bool isProcessSafe() const { return false; }
|
||||
};
|
||||
|
||||
// extensions to the D-Bus server, created dynamically by main()
|
||||
#ifdef ENABLE_DBUS_PIM
|
||||
boost::shared_ptr<GDBusCXX::DBusObjectHelper> CreateContactManager(const boost::shared_ptr<Server> &server);
|
||||
#endif
|
||||
|
||||
SE_END_CXX
|
||||
|
||||
#endif // SYNCEVO_DBUS_SERVER_H
|
||||
|
|
Loading…
Reference in a new issue