Presence Detection: listen connman signals instead of polling (mb#10438)

This commit is contained in:
Chen Congwu 2010-04-01 10:15:20 +08:00
parent 82465b359b
commit 5ec64c4504
2 changed files with 182 additions and 91 deletions

View File

@ -877,9 +877,14 @@ class PresenceStatus {
:m_httpPresence (false), m_btPresence (false), m_initiated (false), m_server (server),
m_httpTimer(), m_btTimer()
{
init();
}
enum TransportType{
HTTP_TRANSPORT,
BT_TRANSPORT,
INVALID_TRANSPORT
};
void init();
/* Implement DBusServer::checkPresence*/
@ -888,6 +893,7 @@ class PresenceStatus {
void updateConfigPeers (const std::string &peer, const ReadOperations::Config_t &config);
void updatePresenceStatus (bool httpPresence, bool btPresence);
void updatePresenceStatus (bool newStatus, TransportType type);
bool getHttpPresence() { return m_httpPresence; }
bool getBtPresence() { return m_btPresence; }
@ -895,6 +901,32 @@ class PresenceStatus {
Timer& getBtTimer() { return m_btTimer; }
};
/*
* Implements org.moblin.connman.Manager
* GetProperty : getPropCb
* PropertyChanged: propertyChanged
**/
class ConnmanClient : public DBusRemoteObject
{
public:
ConnmanClient (DBusServer &server);
virtual const char *getDestination() const {return "org.moblin.connman";}
virtual const char *getPath() const {return "/";}
virtual const char *getInterface() const {return "org.moblin.connman.Manager";}
virtual DBusConnection *getConnection() const {return m_connmanConn.get();}
void propertyChanged(const string &name,
const boost::variant<vector<string>, string> &prop);
void getPropCb(const std::map <std::string, boost::variant <std::vector <std::string> > >& props, const string &error);
private:
DBusServer &m_server;
DBusConnectionPtr m_connmanConn;
SignalWatch2 <string,boost::variant<vector<string>, string> > m_propertyChanged;
};
/**
* Implements the main org.syncevolution.Server interface.
*
@ -1107,12 +1139,10 @@ class DBusServer : public DBusObjectHelper,
string,
const std::string &> logOutput;
static gboolean connmanPoll (gpointer dbus_server);
DBusConnectionPtr m_connmanConn;
friend class Session;
PresenceStatus m_presence;
ConnmanClient m_connman;
/** manager to automatic sync */
AutoSyncManager m_autoSync;
@ -1193,8 +1223,6 @@ public:
PresenceStatus& getPresenceStatus() {return m_presence;}
DBusConnectionPtr getConnmanConnection() {return m_connmanConn;}
void clearPeerTempls() { m_matchedTempls.clear(); }
void addPeerTempl(const string &templName, const boost::shared_ptr<SyncConfig::TemplateDescription> peerTempl);
@ -4331,6 +4359,15 @@ void PresenceStatus::updateConfigPeers (const std::string &peer, const ReadOpera
}
}
void PresenceStatus::updatePresenceStatus (bool newStatus, PresenceStatus::TransportType type) {
if (type == PresenceStatus::HTTP_TRANSPORT) {
updatePresenceStatus (newStatus, m_btPresence);
} else if (type == PresenceStatus::BT_TRANSPORT) {
updatePresenceStatus (m_httpPresence, newStatus);
}else {
}
}
void PresenceStatus::updatePresenceStatus (bool httpPresence, bool btPresence) {
bool httpChanged = (m_httpPresence != httpPresence);
bool btChanged = (m_btPresence != btPresence);
@ -4380,6 +4417,99 @@ void PresenceStatus::updatePresenceStatus (bool httpPresence, bool btPresence) {
}
}
/********************** Connman Client implementation **************/
ConnmanClient::ConnmanClient(DBusServer &server):
m_server(server),
m_propertyChanged(*this, "PropertyChanged")
{
const char *connmanTest = getenv ("DBUS_TEST_CONNMAN");
m_connmanConn = g_dbus_setup_bus (connmanTest ? DBUS_BUS_SESSION: DBUS_BUS_SYSTEM, NULL, true, NULL);
if (m_connmanConn){
typedef std::map <std::string, boost::variant <std::vector <std::string> > > PropDict;
DBusClientCall1<PropDict> getProp(*this,"GetProperties");
getProp (boost::bind(&ConnmanClient::getPropCb, this, _1, _2));
m_propertyChanged.activate(boost::bind(&ConnmanClient::propertyChanged, this, _1, _2));
}else{
SE_LOG_ERROR (NULL, NULL, "DBus connection setup for connman failed");
}
}
void ConnmanClient::getPropCb (const std::map <std::string,
boost::variant <std::vector <std::string> > >& props, const string &error){
if (!error.empty()) {
if (error == "org.freedesktop.DBus.Error.ServiceUnknown") {
// ensure there is still first set of singal set in case of no
// connman available
m_server.getPresenceStatus().updatePresenceStatus (true, true);
SE_LOG_DEBUG (NULL, NULL, "No connman service available %s", error.c_str());
return;
}
SE_LOG_DEBUG (NULL, NULL, "error in connmanCallback %s", error.c_str());
return;
}
typedef std::pair <std::string, boost::variant <std::vector <std::string> > > element;
bool httpPresence = false, btPresence = false;
BOOST_FOREACH (element entry, props) {
//match connected for HTTP based peers (wifi/wimax/ethernet)
if (entry.first == "ConnectedTechnologies") {
std::vector <std::string> connected = boost::get <std::vector <std::string> > (entry.second);
BOOST_FOREACH (std::string tech, connected) {
if (boost::iequals (tech, "wifi") || boost::iequals (tech, "ethernet")
|| boost::iequals (tech, "wimax")) {
httpPresence = true;
break;
}
}
} else if (entry.first == "AvailableTechnologies") {
std::vector <std::string> enabled = boost::get <std::vector <std::string> > (entry.second);
BOOST_FOREACH (std::string tech, enabled){
if (boost::iequals (tech, "bluetooth")) {
btPresence = true;
break;
}
}
} else {
continue;
}
}
//now delivering the signals
m_server.getPresenceStatus().updatePresenceStatus (httpPresence, btPresence);
}
void ConnmanClient::propertyChanged(const string &name,
const boost::variant<vector<string>, string> &prop)
{
bool httpPresence=false, btPresence=false;
bool httpChanged=false, btChanged=false;
if (boost::iequals(name, "ConnectedTechnologies")) {
httpChanged=true;
vector<string> connected = boost::get<vector<string> >(prop);
BOOST_FOREACH (std::string tech, connected) {
if (boost::iequals (tech, "wifi") || boost::iequals (tech, "ethernet")
|| boost::iequals (tech, "wimax")) {
httpPresence=true;
break;
}
}
} else if (boost::iequals (name, "AvailableTechnologies")){
btChanged=true;
vector<string> enabled = boost::get<vector<string> >(prop);
BOOST_FOREACH (std::string tech, enabled){
if (boost::iequals (tech, "bluetooth")) {
btPresence = true;
break;
}
}
}
if(httpChanged) {
m_server.getPresenceStatus().updatePresenceStatus (httpPresence, PresenceStatus::HTTP_TRANSPORT);
} else if (btChanged) {
m_server.getPresenceStatus().updatePresenceStatus (btPresence, PresenceStatus::BT_TRANSPORT);
} else {
}
}
/********************** DBusServer implementation ******************/
void DBusServer::clientGone(Client *c)
@ -4545,6 +4675,7 @@ DBusServer::DBusServer(GMainLoop *loop, const DBusConnectionPtr &conn, int durat
infoRequest(*this, "InfoRequest"),
logOutput(*this, "LogOutput"),
m_presence(*this),
m_connman(*this),
m_autoSync(*this),
m_autoTerm(m_autoSync.preventTerm() ? -1 : duration), //if there is any task in auto sync, prevent auto termination
m_parentLogger(LoggerBase::instance())
@ -4572,12 +4703,6 @@ DBusServer::DBusServer(GMainLoop *loop, const DBusConnectionPtr &conn, int durat
LoggerBase::pushLogger(this);
setLevel(LoggerBase::DEBUG);
const char *connmanTest = getenv ("DBUS_TEST_CONNMAN");
m_connmanConn = g_dbus_setup_bus (connmanTest ? DBUS_BUS_SESSION: DBUS_BUS_SYSTEM, NULL, true, NULL);
if (m_connmanConn) {
m_pollConnman = g_timeout_add_seconds (10, connmanPoll, static_cast <gpointer> (this));
}
}
DBusServer::~DBusServer()
@ -4838,74 +4963,6 @@ void DBusServer::removeInfoReq(const InfoReq &req)
}
}
gboolean DBusServer::connmanPoll (gpointer dbusserver)
{
DBusServer *me = static_cast<DBusServer *>(dbusserver);
DBusConnectionPtr conn = me->getConnmanConnection();
struct ConnmanClient : public DBusCallObject
{
DBusConnectionPtr m_connection;
ConnmanClient (DBusConnectionPtr conn ) : m_connection (conn) {}
virtual const char *getDestination() const {return "org.moblin.connman";}
virtual const char *getPath() const {return "/";}
virtual const char *getInterface() const {return "org.moblin.connman.Manager";}
virtual const char *getMethod() const {return "GetProperties"; }
virtual DBusConnection *getConnection() const {return m_connection.get();}
}connman (conn);
typedef std::map <std::string, boost::variant <std::vector <std::string> > > PropDict;
DBusClientCall1<PropDict> getProp(connman);
getProp (boost::bind(&DBusServer::connmanCallback, me, _1, _2));
return TRUE;
}
void DBusServer::connmanCallback (const std::map <std::string, boost::variant <std::vector <std::string> > >& props, const string &error)
{
if (!error.empty()) {
if (error == "org.freedesktop.DBus.Error.ServiceUnknown") {
// no connman available, remove connmanPoll.
m_pollConnman.set(0);
// ensure there is still first set of singal set in case of no
// connman available
m_presence.updatePresenceStatus (true, true);
SE_LOG_DEBUG (NULL, NULL, "No connman service available %s", error.c_str());
return;
}
SE_LOG_DEBUG (NULL, NULL, "error in connmanCallback %s", error.c_str());
return;
}
typedef std::pair <std::string, boost::variant <std::vector <std::string> > > element;
bool httpPresence = false, btPresence = false;
BOOST_FOREACH (element entry, props) {
//match connected for HTTP based peers (wifi/wimax/ethernet)
if (entry.first == "ConnectedTechnologies") {
std::vector <std::string> connected = boost::get <std::vector <std::string> > (entry.second);
BOOST_FOREACH (std::string tech, connected) {
if (boost::iequals (tech, "wifi") || boost::iequals (tech, "ethernet")
|| boost::iequals (tech, "wimax")) {
httpPresence = true;
break;
}
}
} else if (entry.first == "EnabledTechnologies") {
std::vector <std::string> enabled = boost::get <std::vector <std::string> > (entry.second);
BOOST_FOREACH (std::string tech, enabled){
if (boost::iequals (tech, "bluetooth")) {
btPresence = true;
break;
}
}
} else {
continue;
}
}
//now delivering the signals
m_presence.updatePresenceStatus (httpPresence, btPresence);
}
void DBusServer::getDeviceList(SyncConfig::DeviceList &devices)
{
//wait bluez or other device managers

View File

@ -666,27 +666,53 @@ class Connman (dbus.service.Object):
if (self.count == 1):
loop.quit()
return {"ConnectedTechnologies":["ethernet", "some other stuff"],
"EnabledTechnologies": ["bluetooth"]}
"AvailableTechnologies": ["bluetooth"]}
elif (self.count == 2):
""" unplug the ethernet cable """
loop.quit()
return {"ConnectedTechnologies":["some other stuff"],
"EnabledTechnologies": ["bluetooth"]}
"AvailableTechnologies": ["bluetooth"]}
elif (self.count == 3):
""" replug the ethernet cable """
loop.quit()
return {"ConnectedTechnologies":["ethernet", "some other stuff"],
"EnabledTechnologies": ["bluetooth"]}
"AvailableTechnologies": ["bluetooth"]}
elif (self.count == 4):
""" nothing presence """
loop.quit()
return {"ConnectedTechnologies":[""],
"EnabledTechnologies": [""]}
"AvailableTechnologies": [""]}
elif (self.count == 5):
""" come back the same time """
loop.quit()
return {"ConnectedTechnologies":["ethernet", "some other stuff"],
"EnabledTechnologies": ["bluetooth"]}
"AvailableTechnologies": ["bluetooth"]}
@dbus.service.signal(dbus_interface='org.moblin.connman.Manager', signature='sv')
def PropertyChanged(self, key, value):
pass
def emitSignal(self):
self.count = self.count+1
if (self.count == 2):
""" unplug the ethernet cable """
self.PropertyChanged("ConnectedTechnologies",["some other stuff"])
return
elif (self.count == 3):
""" replug the ethernet cable """
self.PropertyChanged("ConnectedTechnologies", ["ethernet", "some other stuff"])
return
elif (self.count == 4):
""" nothing presence """
self.PropertyChanged("ConnectedTechnologies", [""])
self.PropertyChanged("AvailableTechnologies", [""])
return
elif (self.count == 5):
""" come back the same time """
self.PropertyChanged("ConnectedTechnologies", ["ethernet", "some other stuff"])
self.PropertyChanged("AvailableTechnologies", ["bluetooth"])
return
def reset(self):
self.count = 0
@ -709,6 +735,7 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
self.failUnlessEqual (status, "")
self.failUnlessEqual (server, "foo")
self.failUnlessEqual (transport, "http://http-only-1")
loop.quit()
match = bus.add_signal_receiver(cb_http_presence,
'Presence',
@ -720,13 +747,14 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
loop.run()
time.sleep(1)
self.setUpSession("foo")
self.session.SetConfig(True, True, {"" : {"syncURL":
self.session.SetConfig(True, False, {"" : {"syncURL":
"obex-bt://temp-bluetooth-peer-changed-from-http"}})
def cb_bt_presence(server, status, transport):
self.failUnlessEqual (status, "")
self.failUnlessEqual (server, "foo")
self.failUnlessEqual (transport,
"obex-bt://temp-bluetooth-peer-changed-from-http")
loop.quit()
match.remove()
match = bus.add_signal_receiver(cb_bt_presence,
'Presence',
@ -735,6 +763,7 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
None,
byte_arrays=True,
utf8_strings=True)
self.conn.emitSignal()
loop.run()
time.sleep(1)
self.session.Detach()
@ -744,6 +773,9 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
self.session.Detach()
self.foo = "random string"
self.bar = "random string"
match.remove()
self.conn.emitSignal()
self.conn.emitSignal()
def cb_bt_http_presence(server, status, transport):
if (server == "foo"):
self.foo = status
@ -751,8 +783,8 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
self.bar = status
else:
self.fail("wrong server config")
loop.quit()
match.remove()
match = bus.add_signal_receiver(cb_bt_http_presence,
'Presence',
'org.syncevolution.Server',
@ -760,6 +792,8 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
None,
byte_arrays=True,
utf8_strings=True)
#count=5, 2 signals recevied
self.conn.emitSignal()
loop.run()
loop.run()
time.sleep(1)
@ -798,7 +832,7 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
"http://http-client-mixed"])
#count = 2
loop.run()
self.conn.emitSignal()
time.sleep(1)
(status, transports) = self.server.CheckPresence ("foo")
self.failUnlessEqual (status, "no transport")
@ -819,9 +853,9 @@ class TestDBusServerPresence(unittest.TestCase, DBusUtil):
time.sleep(1)
status = self.session.checkPresence()
self.failUnlessEqual (status, "")
loop.run()
loop.run()
loop.run()
self.conn.emitSignal()
self.conn.emitSignal()
self.conn.emitSignal()
#count = 4
time.sleep(1)
status = self.session.checkPresence()