D-Bus API: added missing Session.Attach() (BMC #7761)
It was always part of the design that multiple clients can use any session. Somehow we forgot to implement Session.Attach(), the call that allows a client which hasn't started a session to register it's interest in the session. In particular, that session won't go away unless the client exits or detaches. This patch adds that missing call, a corresponding capability ("SessionAttach") and a unit test. The unit test covers recursive attach/detach, it does not actually verify that the session remains around.
This commit is contained in:
parent
cb67e29e0a
commit
320e23e31d
|
@ -65,6 +65,12 @@
|
|||
</doc:definition>
|
||||
</doc:item>
|
||||
|
||||
<doc:item><doc:term>SessionAttach</doc:term>
|
||||
<doc:definition>Session.Attach()
|
||||
implemented
|
||||
</doc:definition>
|
||||
</doc:item>
|
||||
|
||||
<doc:item><doc:term>Notifications</doc:term>
|
||||
<doc:definition>Server.DisableNotifications()
|
||||
and Server.EnableNotifications() implemented
|
||||
|
|
|
@ -2,8 +2,18 @@
|
|||
<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||||
<interface name="org.syncevolution.Session">
|
||||
<doc:doc><doc:description>
|
||||
<doc:para>A Session object is used to do do syncs and to modify the server configurations. Clients can create a Session with Server.StartSession() and detach from it with Session.Detach().</doc:para>
|
||||
<doc:para>Commands (other than Detach()) cannot be used before the status changes to "idle" (see GetStatus() and StatusChanged).</doc:para>
|
||||
<doc:para>
|
||||
A Session object is used to do do syncs and to modify
|
||||
the server configurations. Clients can create a Session with
|
||||
Server.StartSession(), attach to a session started by some other
|
||||
client with Session.Attach(), and detach from it with
|
||||
Session.Detach().
|
||||
</doc:para>
|
||||
<doc:para>
|
||||
Commands (other than Attach() and Detach()) cannot be used
|
||||
before the status changes to "idle" (see GetStatus() and
|
||||
StatusChanged).
|
||||
</doc:para>
|
||||
</doc:description></doc:doc>
|
||||
|
||||
<method name="GetFlags">
|
||||
|
|
|
@ -1822,6 +1822,9 @@ class Session : public DBusObjectHelper,
|
|||
/** Cmdline to execute command line args */
|
||||
boost::shared_ptr<CmdlineWrapper> m_cmdline;
|
||||
|
||||
/** Session.Attach() */
|
||||
void attach(const Caller_t &caller);
|
||||
|
||||
/** Session.Detach() */
|
||||
void detach(const Caller_t &caller);
|
||||
|
||||
|
@ -1868,13 +1871,30 @@ class Session : public DBusObjectHelper,
|
|||
static string syncStatusToString(SyncStatus state);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Sessions must always be held in a shared pointer
|
||||
* because some operations depend on that. This
|
||||
* constructor function here ensures that and
|
||||
* also adds a weak pointer to the instance itself,
|
||||
* so that it can create more shared pointers as
|
||||
* needed.
|
||||
*/
|
||||
static boost::shared_ptr<Session> createSession(DBusServer &server,
|
||||
const std::string &peerDeviceID,
|
||||
const std::string &config_name,
|
||||
const std::string &session,
|
||||
const std::vector<std::string> &flags = std::vector<std::string>());
|
||||
~Session();
|
||||
|
||||
private:
|
||||
Session(DBusServer &server,
|
||||
const std::string &peerDeviceID,
|
||||
const std::string &config_name,
|
||||
const std::string &session,
|
||||
const std::vector<std::string> &flags = std::vector<std::string>());
|
||||
~Session();
|
||||
boost::weak_ptr<Session> m_me;
|
||||
|
||||
public:
|
||||
enum {
|
||||
PRI_CMDLINE = -10,
|
||||
PRI_DEFAULT = 0,
|
||||
|
@ -2890,6 +2910,19 @@ string DBusSync::askPassword(const string &passwordName,
|
|||
|
||||
/***************** Session implementation ***********************/
|
||||
|
||||
void Session::attach(const Caller_t &caller)
|
||||
{
|
||||
boost::shared_ptr<Client> client(m_server.findClient(caller));
|
||||
if (!client) {
|
||||
throw runtime_error("unknown client");
|
||||
}
|
||||
boost::shared_ptr<Session> me = m_me.lock();
|
||||
if (!me) {
|
||||
throw runtime_error("session already deleted?!");
|
||||
}
|
||||
client->attach(me);
|
||||
}
|
||||
|
||||
void Session::detach(const Caller_t &caller)
|
||||
{
|
||||
boost::shared_ptr<Client> client(m_server.findClient(caller));
|
||||
|
@ -3163,6 +3196,17 @@ string Session::syncStatusToString(SyncStatus state)
|
|||
};
|
||||
}
|
||||
|
||||
boost::shared_ptr<Session> Session::createSession(DBusServer &server,
|
||||
const std::string &peerDeviceID,
|
||||
const std::string &config_name,
|
||||
const std::string &session,
|
||||
const std::vector<std::string> &flags)
|
||||
{
|
||||
boost::shared_ptr<Session> me(new Session(server, peerDeviceID, config_name, session, flags));
|
||||
me->m_me = me;
|
||||
return me;
|
||||
}
|
||||
|
||||
Session::Session(DBusServer &server,
|
||||
const std::string &peerDeviceID,
|
||||
const std::string &config_name,
|
||||
|
@ -3199,6 +3243,7 @@ Session::Session(DBusServer &server,
|
|||
emitStatus(*this, "StatusChanged"),
|
||||
emitProgress(*this, "ProgressChanged")
|
||||
{
|
||||
add(this, &Session::attach, "Attach");
|
||||
add(this, &Session::detach, "Detach");
|
||||
add(this, &Session::getFlags, "GetFlags");
|
||||
add(this, &Session::getNormalConfigName, "GetConfigName");
|
||||
|
@ -4053,10 +4098,10 @@ void Connection::process(const Caller_t &caller,
|
|||
|
||||
// run session as client or server
|
||||
m_state = PROCESSING;
|
||||
m_session.reset(new Session(m_server,
|
||||
peerDeviceID,
|
||||
config,
|
||||
m_sessionID));
|
||||
m_session = Session::createSession(m_server,
|
||||
peerDeviceID,
|
||||
config,
|
||||
m_sessionID);
|
||||
if (serverMode) {
|
||||
m_session->initServer(SharedBuffer(reinterpret_cast<const char *>(message.second),
|
||||
message.first),
|
||||
|
@ -4691,6 +4736,7 @@ vector<string> DBusServer::getCapabilities()
|
|||
capabilities.push_back("Notifications");
|
||||
capabilities.push_back("Version");
|
||||
capabilities.push_back("SessionFlags");
|
||||
capabilities.push_back("SessionAttach");
|
||||
return capabilities;
|
||||
}
|
||||
|
||||
|
@ -4789,11 +4835,11 @@ void DBusServer::startSessionWithFlags(const Caller_t &caller,
|
|||
caller,
|
||||
watch);
|
||||
std::string new_session = getNextSession();
|
||||
boost::shared_ptr<Session> session(new Session(*this,
|
||||
"is this a client or server session?",
|
||||
server,
|
||||
new_session,
|
||||
flags));
|
||||
boost::shared_ptr<Session> session = Session::createSession(*this,
|
||||
"is this a client or server session?",
|
||||
server,
|
||||
new_session,
|
||||
flags);
|
||||
client->attach(session);
|
||||
session->activate();
|
||||
enqueue(session);
|
||||
|
@ -5737,10 +5783,10 @@ void AutoSyncManager::startTask()
|
|||
m_activeTask.reset(new AutoSyncTask(m_workQueue.front()));
|
||||
m_workQueue.pop_front();
|
||||
string newSession = m_server.getNextSession();
|
||||
m_session.reset(new Session(m_server,
|
||||
"",
|
||||
m_activeTask->m_peer,
|
||||
newSession));
|
||||
m_session = Session::createSession(m_server,
|
||||
"",
|
||||
m_activeTask->m_peer,
|
||||
newSession);
|
||||
m_session->setPriority(Session::PRI_AUTOSYNC);
|
||||
m_session->addListener(this);
|
||||
m_server.enqueue(m_session);
|
||||
|
|
|
@ -554,7 +554,7 @@ class TestDBusServer(unittest.TestCase, DBusUtil):
|
|||
"""check the Server.GetCapabilities() call"""
|
||||
capabilities = self.server.GetCapabilities()
|
||||
capabilities.sort()
|
||||
self.failUnlessEqual(capabilities, ['ConfigChanged', 'GetConfigName', 'Notifications', 'SessionFlags', 'Version'])
|
||||
self.failUnlessEqual(capabilities, ['ConfigChanged', 'GetConfigName', 'Notifications', 'SessionAttach', 'SessionFlags', 'Version'])
|
||||
|
||||
def testVersions(self):
|
||||
"""check the Server.GetVersions() call"""
|
||||
|
@ -910,6 +910,13 @@ class TestDBusSession(unittest.TestCase, DBusUtil):
|
|||
self.failUnlessEqual(self.session.GetFlags(), [])
|
||||
self.failUnlessEqual(self.session.GetConfigName(), "@default");
|
||||
|
||||
def testAttachSession(self):
|
||||
"""attach to running session"""
|
||||
self.session.Attach()
|
||||
self.session.Detach()
|
||||
self.failUnlessEqual(self.session.GetFlags(), [])
|
||||
self.failUnlessEqual(self.session.GetConfigName(), "@default");
|
||||
|
||||
def testCreateSessionWithFlags(self):
|
||||
"""ask for session with some specific flags and config"""
|
||||
self.session.Detach()
|
||||
|
|
Loading…
Reference in New Issue