Redo PS connection handling; ensure valid network connection before talking to server
This commit is contained in:
parent
66dfd363ba
commit
5e2ea16e3a
@ -22,6 +22,7 @@ import dbus
|
|||||||
import dbus.service
|
import dbus.service
|
||||||
from dbus.gobject_service import ExportedGObject
|
from dbus.gobject_service import ExportedGObject
|
||||||
from ConfigParser import ConfigParser, NoOptionError
|
from ConfigParser import ConfigParser, NoOptionError
|
||||||
|
import psutils
|
||||||
|
|
||||||
from sugar import env, profile, util
|
from sugar import env, profile, util
|
||||||
import logging
|
import logging
|
||||||
@ -132,9 +133,19 @@ class Buddy(ExportedGObject):
|
|||||||
logging.debug("Invalid init property '%s'; ignoring..." % key)
|
logging.debug("Invalid init property '%s'; ignoring..." % key)
|
||||||
del kwargs[key]
|
del kwargs[key]
|
||||||
|
|
||||||
|
# Set icon after superclass init, because it sends DBus and GObject
|
||||||
|
# signals when set
|
||||||
|
icon_data = None
|
||||||
|
if kwargs.has_key(_PROP_ICON):
|
||||||
|
icon_data = kwargs[_PROP_ICON]
|
||||||
|
del kwargs[_PROP_ICON]
|
||||||
|
|
||||||
ExportedGObject.__init__(self, bus_name, self._object_path,
|
ExportedGObject.__init__(self, bus_name, self._object_path,
|
||||||
gobject_properties=kwargs)
|
gobject_properties=kwargs)
|
||||||
|
|
||||||
|
if icon_data:
|
||||||
|
self.props.icon = icon_data
|
||||||
|
|
||||||
def do_get_property(self, pspec):
|
def do_get_property(self, pspec):
|
||||||
"""Retrieve current value for the given property specifier
|
"""Retrieve current value for the given property specifier
|
||||||
|
|
||||||
@ -399,176 +410,6 @@ class Buddy(ExportedGObject):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
self._valid = False
|
self._valid = False
|
||||||
|
|
||||||
|
|
||||||
NM_SERVICE = 'org.freedesktop.NetworkManager'
|
|
||||||
NM_IFACE = 'org.freedesktop.NetworkManager'
|
|
||||||
NM_IFACE_DEVICES = 'org.freedesktop.NetworkManager.Devices'
|
|
||||||
NM_PATH = '/org/freedesktop/NetworkManager'
|
|
||||||
|
|
||||||
class IP4AddressMonitor(gobject.GObject):
|
|
||||||
"""This class, and direct buddy IPv4 address access, will go away quite soon"""
|
|
||||||
|
|
||||||
__gsignals__ = {
|
|
||||||
'address-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
|
||||||
([gobject.TYPE_PYOBJECT]))
|
|
||||||
}
|
|
||||||
|
|
||||||
__gproperties__ = {
|
|
||||||
'address' : (str, None, None, None, gobject.PARAM_READABLE)
|
|
||||||
}
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
gobject.GObject.__init__(self)
|
|
||||||
self._nm_present = False
|
|
||||||
self._matches = []
|
|
||||||
self._addr = None
|
|
||||||
self._nm_obj = None
|
|
||||||
|
|
||||||
sys_bus = dbus.SystemBus()
|
|
||||||
bus_object = sys_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
|
|
||||||
try:
|
|
||||||
if bus_object.GetNameOwner(NM_SERVICE, dbus_interface='org.freedesktop.DBus'):
|
|
||||||
self._nm_present = True
|
|
||||||
except dbus.DBusException:
|
|
||||||
pass
|
|
||||||
|
|
||||||
if self._nm_present:
|
|
||||||
self._connect_to_nm()
|
|
||||||
else:
|
|
||||||
addr = self._get_address_fallback()
|
|
||||||
self._update_address(addr)
|
|
||||||
|
|
||||||
def do_get_property(self, pspec):
|
|
||||||
if pspec.name == "address":
|
|
||||||
return self._addr
|
|
||||||
|
|
||||||
def _update_address(self, new_addr):
|
|
||||||
if new_addr == "0.0.0.0":
|
|
||||||
new_addr = None
|
|
||||||
if new_addr == self._addr:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._addr = new_addr
|
|
||||||
logging.debug("IP4 address now '%s'" % new_addr)
|
|
||||||
self.emit('address-changed', new_addr)
|
|
||||||
|
|
||||||
def _connect_to_nm(self):
|
|
||||||
"""Connect to NM device state signals to tell when the IPv4 address changes"""
|
|
||||||
try:
|
|
||||||
sys_bus = dbus.SystemBus()
|
|
||||||
proxy = sys_bus.get_object(NM_SERVICE, NM_PATH)
|
|
||||||
self._nm_obj = dbus.Interface(proxy, NM_IFACE)
|
|
||||||
except dbus.DBusException, err:
|
|
||||||
logging.debug("Error finding NetworkManager: %s" % err)
|
|
||||||
self._nm_present = False
|
|
||||||
return
|
|
||||||
|
|
||||||
sys_bus = dbus.SystemBus()
|
|
||||||
match = sys_bus.add_signal_receiver(self._nm_device_active_cb,
|
|
||||||
signal_name="DeviceNowActive",
|
|
||||||
dbus_interface=NM_IFACE)
|
|
||||||
self._matches.append(match)
|
|
||||||
|
|
||||||
match = sys_bus.add_signal_receiver(self._nm_device_no_longer_active_cb,
|
|
||||||
signal_name="DeviceNoLongerActive",
|
|
||||||
dbus_interface=NM_IFACE,
|
|
||||||
named_service=NM_SERVICE)
|
|
||||||
self._matches.append(match)
|
|
||||||
|
|
||||||
match = sys_bus.add_signal_receiver(self._nm_state_change_cb,
|
|
||||||
signal_name="StateChange",
|
|
||||||
dbus_interface=NM_IFACE,
|
|
||||||
named_service=NM_SERVICE)
|
|
||||||
self._matches.append(match)
|
|
||||||
|
|
||||||
state = self._nm_obj.state()
|
|
||||||
if state == 3: # NM_STATE_CONNECTED
|
|
||||||
self._query_devices()
|
|
||||||
|
|
||||||
def _device_properties_cb(self, *props):
|
|
||||||
active = props[4]
|
|
||||||
if not active:
|
|
||||||
return
|
|
||||||
act_stage = props[5]
|
|
||||||
# HACK: OLPC NM has an extra stage, so activated == 8 on OLPC
|
|
||||||
# but 7 everywhere else
|
|
||||||
if act_stage != 8 and act_stage != 7:
|
|
||||||
# not activated
|
|
||||||
return
|
|
||||||
self._update_address(props[6])
|
|
||||||
|
|
||||||
def _device_properties_error_cb(self, err):
|
|
||||||
logging.debug("Error querying device properties: %s" % err)
|
|
||||||
|
|
||||||
def _query_device_properties(self, device):
|
|
||||||
sys_bus = dbus.SystemBus()
|
|
||||||
proxy = sys_bus.get_object(NM_SERVICE, device)
|
|
||||||
dev = dbus.Interface(proxy, NM_IFACE_DEVICES)
|
|
||||||
dev.getProperties(reply_handler=self._device_properties_cb,
|
|
||||||
error_handler=self._device_properties_error_cb)
|
|
||||||
|
|
||||||
def _get_devices_cb(self, ops):
|
|
||||||
"""Query each device's properties"""
|
|
||||||
for op in ops:
|
|
||||||
self._query_device_properties(op)
|
|
||||||
|
|
||||||
def _get_devices_error_cb(self, err):
|
|
||||||
logging.debug("Error getting NetworkManager devices: %s" % err)
|
|
||||||
|
|
||||||
def _query_devices(self):
|
|
||||||
"""Query NM for a list of network devices"""
|
|
||||||
self._nm_obj.getDevices(reply_handler=self._get_devices_cb,
|
|
||||||
error_handler=self._get_devices_error_cb)
|
|
||||||
|
|
||||||
def _nm_device_active_cb(self, device, ssid=None):
|
|
||||||
self._query_device_properties(device)
|
|
||||||
|
|
||||||
def _nm_device_no_longer_active_cb(self, device):
|
|
||||||
self._update_address(None)
|
|
||||||
|
|
||||||
def _nm_state_change_cb(self, new_state):
|
|
||||||
if new_state == 4: # NM_STATE_DISCONNECTED
|
|
||||||
self._update_address(None)
|
|
||||||
|
|
||||||
def handle_name_owner_changed(self, name, old, new):
|
|
||||||
"""Clear state when NM goes away"""
|
|
||||||
if name != NM_SERVICE:
|
|
||||||
return
|
|
||||||
if (old and len(old)) and (not new and not len(new)):
|
|
||||||
# NM went away
|
|
||||||
self._nm_present = False
|
|
||||||
for match in self._matches:
|
|
||||||
match.remove()
|
|
||||||
self._matches = []
|
|
||||||
self._update_address(None)
|
|
||||||
elif (not old and not len(old)) and (new and len(new)):
|
|
||||||
# NM started up
|
|
||||||
self._nm_present = True
|
|
||||||
self._connect_to_nm()
|
|
||||||
|
|
||||||
def _get_iface_address(self, iface):
|
|
||||||
import socket
|
|
||||||
import fcntl
|
|
||||||
import struct
|
|
||||||
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
|
||||||
fd = s.fileno()
|
|
||||||
SIOCGIFADDR = 0x8915
|
|
||||||
addr = fcntl.ioctl(fd, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24]
|
|
||||||
s.close()
|
|
||||||
return socket.inet_ntoa(addr)
|
|
||||||
|
|
||||||
def _get_address_fallback(self):
|
|
||||||
import commands
|
|
||||||
(s, o) = commands.getstatusoutput("/sbin/route -n")
|
|
||||||
if s != 0:
|
|
||||||
return
|
|
||||||
for line in o.split('\n'):
|
|
||||||
fields = line.split(" ")
|
|
||||||
if fields[0] == "0.0.0.0":
|
|
||||||
iface = fields[len(fields) - 1]
|
|
||||||
return self._get_iface_address(iface)
|
|
||||||
return None
|
|
||||||
|
|
||||||
class GenericOwner(Buddy):
|
class GenericOwner(Buddy):
|
||||||
"""Common functionality for Local User-like objects
|
"""Common functionality for Local User-like objects
|
||||||
|
|
||||||
@ -617,7 +458,7 @@ class GenericOwner(Buddy):
|
|||||||
signal_name="NameOwnerChanged",
|
signal_name="NameOwnerChanged",
|
||||||
dbus_interface="org.freedesktop.DBus")
|
dbus_interface="org.freedesktop.DBus")
|
||||||
|
|
||||||
self._ip4_addr_monitor = IP4AddressMonitor()
|
self._ip4_addr_monitor = psutils.IP4AddressMonitor.get_instance()
|
||||||
self._ip4_addr_monitor.connect("address-changed", self._ip4_address_changed_cb)
|
self._ip4_addr_monitor.connect("address-changed", self._ip4_address_changed_cb)
|
||||||
|
|
||||||
def _ip4_address_changed_cb(self, monitor, address):
|
def _ip4_address_changed_cb(self, monitor, address):
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
import dbus, dbus.glib, gobject
|
||||||
|
import logging
|
||||||
|
|
||||||
|
|
||||||
def bytes_to_string(bytes):
|
def bytes_to_string(bytes):
|
||||||
"""The function converts a D-BUS byte array provided by dbus to string format.
|
"""The function converts a D-BUS byte array provided by dbus to string format.
|
||||||
@ -28,3 +31,183 @@ def bytes_to_string(bytes):
|
|||||||
# Python string
|
# Python string
|
||||||
ret = ''.join([str(item) for item in bytes])
|
ret = ''.join([str(item) for item in bytes])
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
|
NM_SERVICE = 'org.freedesktop.NetworkManager'
|
||||||
|
NM_IFACE = 'org.freedesktop.NetworkManager'
|
||||||
|
NM_IFACE_DEVICES = 'org.freedesktop.NetworkManager.Devices'
|
||||||
|
NM_PATH = '/org/freedesktop/NetworkManager'
|
||||||
|
|
||||||
|
_ip4am = None
|
||||||
|
|
||||||
|
class IP4AddressMonitor(gobject.GObject):
|
||||||
|
"""This class, and direct buddy IPv4 address access, will go away quite soon"""
|
||||||
|
|
||||||
|
__gsignals__ = {
|
||||||
|
'address-changed': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
|
||||||
|
([gobject.TYPE_PYOBJECT]))
|
||||||
|
}
|
||||||
|
|
||||||
|
__gproperties__ = {
|
||||||
|
'address' : (str, None, None, None, gobject.PARAM_READABLE)
|
||||||
|
}
|
||||||
|
|
||||||
|
def get_instance():
|
||||||
|
"""Retrieve (or create) the IP4Address monitor singleton instance"""
|
||||||
|
global _ip4am
|
||||||
|
if not _ip4am:
|
||||||
|
_ip4am = IP4AddressMonitor()
|
||||||
|
return _ip4am
|
||||||
|
get_instance = staticmethod(get_instance)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
gobject.GObject.__init__(self)
|
||||||
|
self._nm_present = False
|
||||||
|
self._matches = []
|
||||||
|
self._addr = None
|
||||||
|
self._nm_obj = None
|
||||||
|
|
||||||
|
sys_bus = dbus.SystemBus()
|
||||||
|
bus_object = sys_bus.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
|
||||||
|
try:
|
||||||
|
if bus_object.GetNameOwner(NM_SERVICE, dbus_interface='org.freedesktop.DBus'):
|
||||||
|
self._nm_present = True
|
||||||
|
except dbus.DBusException:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if self._nm_present:
|
||||||
|
self._connect_to_nm()
|
||||||
|
else:
|
||||||
|
addr = self._get_address_fallback()
|
||||||
|
self._update_address(addr)
|
||||||
|
|
||||||
|
def do_get_property(self, pspec):
|
||||||
|
if pspec.name == "address":
|
||||||
|
return self._addr
|
||||||
|
|
||||||
|
def _update_address(self, new_addr):
|
||||||
|
if new_addr == "0.0.0.0":
|
||||||
|
new_addr = None
|
||||||
|
if new_addr == self._addr:
|
||||||
|
return
|
||||||
|
|
||||||
|
self._addr = new_addr
|
||||||
|
logging.debug("IP4 address now '%s'" % new_addr)
|
||||||
|
self.emit('address-changed', new_addr)
|
||||||
|
|
||||||
|
def _connect_to_nm(self):
|
||||||
|
"""Connect to NM device state signals to tell when the IPv4 address changes"""
|
||||||
|
try:
|
||||||
|
sys_bus = dbus.SystemBus()
|
||||||
|
proxy = sys_bus.get_object(NM_SERVICE, NM_PATH)
|
||||||
|
self._nm_obj = dbus.Interface(proxy, NM_IFACE)
|
||||||
|
except dbus.DBusException, err:
|
||||||
|
logging.debug("Error finding NetworkManager: %s" % err)
|
||||||
|
self._nm_present = False
|
||||||
|
return
|
||||||
|
|
||||||
|
sys_bus = dbus.SystemBus()
|
||||||
|
match = sys_bus.add_signal_receiver(self._nm_device_active_cb,
|
||||||
|
signal_name="DeviceNowActive",
|
||||||
|
dbus_interface=NM_IFACE)
|
||||||
|
self._matches.append(match)
|
||||||
|
|
||||||
|
match = sys_bus.add_signal_receiver(self._nm_device_no_longer_active_cb,
|
||||||
|
signal_name="DeviceNoLongerActive",
|
||||||
|
dbus_interface=NM_IFACE,
|
||||||
|
named_service=NM_SERVICE)
|
||||||
|
self._matches.append(match)
|
||||||
|
|
||||||
|
match = sys_bus.add_signal_receiver(self._nm_state_change_cb,
|
||||||
|
signal_name="StateChange",
|
||||||
|
dbus_interface=NM_IFACE,
|
||||||
|
named_service=NM_SERVICE)
|
||||||
|
self._matches.append(match)
|
||||||
|
|
||||||
|
state = self._nm_obj.state()
|
||||||
|
if state == 3: # NM_STATE_CONNECTED
|
||||||
|
self._query_devices()
|
||||||
|
|
||||||
|
def _device_properties_cb(self, *props):
|
||||||
|
active = props[4]
|
||||||
|
if not active:
|
||||||
|
return
|
||||||
|
act_stage = props[5]
|
||||||
|
# HACK: OLPC NM has an extra stage, so activated == 8 on OLPC
|
||||||
|
# but 7 everywhere else
|
||||||
|
if act_stage != 8 and act_stage != 7:
|
||||||
|
# not activated
|
||||||
|
return
|
||||||
|
self._update_address(props[6])
|
||||||
|
|
||||||
|
def _device_properties_error_cb(self, err):
|
||||||
|
logging.debug("Error querying device properties: %s" % err)
|
||||||
|
|
||||||
|
def _query_device_properties(self, device):
|
||||||
|
sys_bus = dbus.SystemBus()
|
||||||
|
proxy = sys_bus.get_object(NM_SERVICE, device)
|
||||||
|
dev = dbus.Interface(proxy, NM_IFACE_DEVICES)
|
||||||
|
dev.getProperties(reply_handler=self._device_properties_cb,
|
||||||
|
error_handler=self._device_properties_error_cb)
|
||||||
|
|
||||||
|
def _get_devices_cb(self, ops):
|
||||||
|
"""Query each device's properties"""
|
||||||
|
for op in ops:
|
||||||
|
self._query_device_properties(op)
|
||||||
|
|
||||||
|
def _get_devices_error_cb(self, err):
|
||||||
|
logging.debug("Error getting NetworkManager devices: %s" % err)
|
||||||
|
|
||||||
|
def _query_devices(self):
|
||||||
|
"""Query NM for a list of network devices"""
|
||||||
|
self._nm_obj.getDevices(reply_handler=self._get_devices_cb,
|
||||||
|
error_handler=self._get_devices_error_cb)
|
||||||
|
|
||||||
|
def _nm_device_active_cb(self, device, ssid=None):
|
||||||
|
self._query_device_properties(device)
|
||||||
|
|
||||||
|
def _nm_device_no_longer_active_cb(self, device):
|
||||||
|
self._update_address(None)
|
||||||
|
|
||||||
|
def _nm_state_change_cb(self, new_state):
|
||||||
|
if new_state == 4: # NM_STATE_DISCONNECTED
|
||||||
|
self._update_address(None)
|
||||||
|
|
||||||
|
def handle_name_owner_changed(self, name, old, new):
|
||||||
|
"""Clear state when NM goes away"""
|
||||||
|
if name != NM_SERVICE:
|
||||||
|
return
|
||||||
|
if (old and len(old)) and (not new and not len(new)):
|
||||||
|
# NM went away
|
||||||
|
self._nm_present = False
|
||||||
|
for match in self._matches:
|
||||||
|
match.remove()
|
||||||
|
self._matches = []
|
||||||
|
self._update_address(None)
|
||||||
|
elif (not old and not len(old)) and (new and len(new)):
|
||||||
|
# NM started up
|
||||||
|
self._nm_present = True
|
||||||
|
self._connect_to_nm()
|
||||||
|
|
||||||
|
def _get_iface_address(self, iface):
|
||||||
|
import socket
|
||||||
|
import fcntl
|
||||||
|
import struct
|
||||||
|
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
|
fd = s.fileno()
|
||||||
|
SIOCGIFADDR = 0x8915
|
||||||
|
addr = fcntl.ioctl(fd, SIOCGIFADDR, struct.pack('256s', iface[:15]))[20:24]
|
||||||
|
s.close()
|
||||||
|
return socket.inet_ntoa(addr)
|
||||||
|
|
||||||
|
def _get_address_fallback(self):
|
||||||
|
import commands
|
||||||
|
(s, o) = commands.getstatusoutput("/sbin/route -n")
|
||||||
|
if s != 0:
|
||||||
|
return
|
||||||
|
for line in o.split('\n'):
|
||||||
|
fields = line.split(" ")
|
||||||
|
if fields[0] == "0.0.0.0":
|
||||||
|
iface = fields[len(fields) - 1]
|
||||||
|
return self._get_iface_address(iface)
|
||||||
|
return None
|
||||||
|
@ -136,11 +136,22 @@ class ServerPlugin(gobject.GObject):
|
|||||||
self._owner.connect("icon-changed", self._owner_icon_changed_cb)
|
self._owner.connect("icon-changed", self._owner_icon_changed_cb)
|
||||||
|
|
||||||
self._account = self._get_account_info()
|
self._account = self._get_account_info()
|
||||||
|
|
||||||
self._conn = self._init_connection()
|
|
||||||
self._conn_status = CONNECTION_STATUS_DISCONNECTED
|
self._conn_status = CONNECTION_STATUS_DISCONNECTED
|
||||||
|
|
||||||
self._reconnect_id = 0
|
# Monitor IPv4 address as an indicator of the network connection
|
||||||
|
self._ip4am = psutils.IP4AddressMonitor.get_instance()
|
||||||
|
self._ip4am.connect('address-changed', self._ip4_address_changed_cb)
|
||||||
|
|
||||||
|
def _ip4_address_changed_cb(self, ip4am, address):
|
||||||
|
logging.debug("::: IP4 address now %s" % address)
|
||||||
|
if address:
|
||||||
|
logging.debug("::: valid IP4 address, conn_status %s" % self._conn_status)
|
||||||
|
if self._conn_status == CONNECTION_STATUS_DISCONNECTED:
|
||||||
|
logging.debug("::: will connect")
|
||||||
|
self.start()
|
||||||
|
else:
|
||||||
|
logging.debug("::: invalid IP4 address, will disconnect")
|
||||||
|
self.cleanup()
|
||||||
|
|
||||||
def _owner_property_changed_cb(self, owner, properties):
|
def _owner_property_changed_cb(self, owner, properties):
|
||||||
"""Local user's configuration properties have changed
|
"""Local user's configuration properties have changed
|
||||||
@ -229,6 +240,14 @@ class ServerPlugin(gobject.GObject):
|
|||||||
"""Retrieve our telepathy.client.Connection object"""
|
"""Retrieve our telepathy.client.Connection object"""
|
||||||
return self._conn
|
return self._conn
|
||||||
|
|
||||||
|
def _connect_reply_cb(self):
|
||||||
|
"""Handle connection success"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _connect_error_cb(self, exception):
|
||||||
|
"""Handle connection failure"""
|
||||||
|
logging.debug("Connect error: %s" % exception)
|
||||||
|
|
||||||
def _init_connection(self):
|
def _init_connection(self):
|
||||||
"""Set up our connection
|
"""Set up our connection
|
||||||
|
|
||||||
@ -262,7 +281,12 @@ class ServerPlugin(gobject.GObject):
|
|||||||
conn[CONN_INTERFACE_PRESENCE].connect_to_signal('PresenceUpdate',
|
conn[CONN_INTERFACE_PRESENCE].connect_to_signal('PresenceUpdate',
|
||||||
self._presence_update_cb)
|
self._presence_update_cb)
|
||||||
|
|
||||||
return conn
|
self._conn = conn
|
||||||
|
status = self._conn[CONN_INTERFACE].GetStatus()
|
||||||
|
if status == CONNECTION_STATUS_DISCONNECTED:
|
||||||
|
self._conn[CONN_INTERFACE].Connect(reply_handler=self._connect_reply_cb,
|
||||||
|
error_handler=self._connect_error_cb)
|
||||||
|
self._handle_connection_status_change(self._conn, status)
|
||||||
|
|
||||||
def _request_list_channel(self, name):
|
def _request_list_channel(self, name):
|
||||||
"""Request a contact-list channel from Telepathy
|
"""Request a contact-list channel from Telepathy
|
||||||
@ -297,16 +321,14 @@ class ServerPlugin(gobject.GObject):
|
|||||||
|
|
||||||
if local_pending:
|
if local_pending:
|
||||||
# accept pending subscriptions
|
# accept pending subscriptions
|
||||||
#print 'pending: %r' % local_pending
|
|
||||||
publish[CHANNEL_INTERFACE_GROUP].AddMembers(local_pending, '')
|
publish[CHANNEL_INTERFACE_GROUP].AddMembers(local_pending, '')
|
||||||
|
|
||||||
not_subscribed = list(set(publish_handles) - set(subscribe_handles))
|
|
||||||
self_handle = self._conn[CONN_INTERFACE].GetSelfHandle()
|
self_handle = self._conn[CONN_INTERFACE].GetSelfHandle()
|
||||||
self._online_contacts[self_handle] = self._account['account']
|
self._online_contacts[self_handle] = self._account['account']
|
||||||
|
|
||||||
for handle in not_subscribed:
|
# request subscriptions from people subscribed to us if we're not subscribed to them
|
||||||
# request subscriptions from people subscribed to us if we're not subscribed to them
|
not_subscribed = list(set(publish_handles) - set(subscribe_handles))
|
||||||
subscribe[CHANNEL_INTERFACE_GROUP].AddMembers([self_handle], '')
|
subscribe[CHANNEL_INTERFACE_GROUP].AddMembers(not_subscribed, '')
|
||||||
|
|
||||||
if CONN_INTERFACE_BUDDY_INFO not in self._conn.get_valid_interfaces():
|
if CONN_INTERFACE_BUDDY_INFO not in self._conn.get_valid_interfaces():
|
||||||
logging.debug('OLPC information not available')
|
logging.debug('OLPC information not available')
|
||||||
@ -334,8 +356,8 @@ class ServerPlugin(gobject.GObject):
|
|||||||
self._set_self_avatar()
|
self._set_self_avatar()
|
||||||
|
|
||||||
# Request presence for everyone on the channel
|
# Request presence for everyone on the channel
|
||||||
self._conn[CONN_INTERFACE_PRESENCE].GetPresence(subscribe_handles,
|
subscribe_handles = subscribe[CHANNEL_INTERFACE_GROUP].GetMembers()
|
||||||
ignore_reply=True)
|
self._conn[CONN_INTERFACE_PRESENCE].RequestPresence(subscribe_handles)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _set_self_avatar_cb(self, token):
|
def _set_self_avatar_cb(self, token):
|
||||||
@ -504,31 +526,38 @@ class ServerPlugin(gobject.GObject):
|
|||||||
return handle
|
return handle
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _status_changed_cb(self, state, reason):
|
def _handle_connection_status_change(self, status, reason):
|
||||||
"""Handle notification of connection-status change
|
if status == self._conn_status:
|
||||||
|
return
|
||||||
|
|
||||||
state -- CONNECTION_STATUS_*
|
if status == CONNECTION_STATUS_CONNECTING:
|
||||||
reason -- integer code describing the reason...
|
self._conn_status = status
|
||||||
"""
|
logging.debug("status: connecting...")
|
||||||
if state == CONNECTION_STATUS_CONNECTING:
|
elif status == CONNECTION_STATUS_CONNECTED:
|
||||||
self._conn_status = state
|
|
||||||
logging.debug("State: connecting...")
|
|
||||||
elif state == CONNECTION_STATUS_CONNECTED:
|
|
||||||
if self._connected_cb():
|
if self._connected_cb():
|
||||||
logging.debug("State: connected")
|
logging.debug("status: connected")
|
||||||
self._conn_status = state
|
self._conn_status = status
|
||||||
else:
|
else:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
logging.debug("State: was connected, but an error occurred")
|
logging.debug("status: was connected, but an error occurred")
|
||||||
elif state == CONNECTION_STATUS_DISCONNECTED:
|
elif status == CONNECTION_STATUS_DISCONNECTED:
|
||||||
self.cleanup()
|
self.cleanup()
|
||||||
logging.debug("State: disconnected (reason %r)" % reason)
|
logging.debug("status: disconnected (reason %r)" % reason)
|
||||||
if reason == CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED:
|
if reason == CONNECTION_STATUS_REASON_AUTHENTICATION_FAILED:
|
||||||
# FIXME: handle connection failure; retry later?
|
# FIXME: handle connection failure; retry later?
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.emit('status', self._conn_status, int(reason))
|
self.emit('status', self._conn_status, int(reason))
|
||||||
|
|
||||||
|
def _status_changed_cb(self, status, reason):
|
||||||
|
"""Handle notification of connection-status change
|
||||||
|
|
||||||
|
status -- CONNECTION_STATUS_*
|
||||||
|
reason -- integer code describing the reason...
|
||||||
|
"""
|
||||||
|
logging.debug("::: connection status changed to %s" % status)
|
||||||
|
self._handle_connection_status_change(status, reason)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
"""Start up the Telepathy networking connections
|
"""Start up the Telepathy networking connections
|
||||||
|
|
||||||
@ -541,35 +570,13 @@ class ServerPlugin(gobject.GObject):
|
|||||||
_connect_reply_cb or _connect_error_cb
|
_connect_reply_cb or _connect_error_cb
|
||||||
"""
|
"""
|
||||||
logging.debug("Starting up...")
|
logging.debug("Starting up...")
|
||||||
# If the connection is already connected query initial contacts
|
|
||||||
conn_status = self._conn[CONN_INTERFACE].GetStatus()
|
# Only init connection if we have a valid IP address
|
||||||
if conn_status == CONNECTION_STATUS_CONNECTED:
|
if self._ip4am.props.address:
|
||||||
self._connected_cb()
|
logging.debug("::: Have IP4 address %s, will connect" % self._ip4am.props.address)
|
||||||
subscribe = self._request_list_channel('subscribe')
|
self._init_connection()
|
||||||
subscribe_handles = subscribe[CHANNEL_INTERFACE_GROUP].GetMembers()
|
|
||||||
self._conn[CONN_INTERFACE_PRESENCE].RequestPresence(subscribe_handles)
|
|
||||||
elif conn_status == CONNECTION_STATUS_CONNECTING:
|
|
||||||
pass
|
|
||||||
else:
|
else:
|
||||||
self._conn[CONN_INTERFACE].Connect(reply_handler=self._connect_reply_cb,
|
logging.debug("::: No IP4 address, postponing connection")
|
||||||
error_handler=self._connect_error_cb)
|
|
||||||
|
|
||||||
def _connect_reply_cb(self):
|
|
||||||
"""Handle connection success"""
|
|
||||||
if self._reconnect_id > 0:
|
|
||||||
gobject.source_remove(self._reconnect_id)
|
|
||||||
|
|
||||||
def _reconnect(self):
|
|
||||||
"""Reset number-of-attempted connections and re-attempt"""
|
|
||||||
self._reconnect_id = 0
|
|
||||||
self.start()
|
|
||||||
return False
|
|
||||||
|
|
||||||
def _connect_error_cb(self, exception):
|
|
||||||
"""Handle connection failure"""
|
|
||||||
logging.debug("Connect error: %s" % exception)
|
|
||||||
if not self._reconnect_id:
|
|
||||||
self._reconnect_id = gobject.timeout_add(10000, self._reconnect)
|
|
||||||
|
|
||||||
def cleanup(self):
|
def cleanup(self):
|
||||||
"""If we still have a connection, disconnect it"""
|
"""If we still have a connection, disconnect it"""
|
||||||
@ -578,6 +585,12 @@ class ServerPlugin(gobject.GObject):
|
|||||||
self._conn = None
|
self._conn = None
|
||||||
self._conn_status = CONNECTION_STATUS_DISCONNECTED
|
self._conn_status = CONNECTION_STATUS_DISCONNECTED
|
||||||
|
|
||||||
|
for handle in self._online_contacts.keys():
|
||||||
|
self._contact_offline(handle)
|
||||||
|
self._online_contacts = {}
|
||||||
|
self._joined_activites = []
|
||||||
|
self._activites = {}
|
||||||
|
|
||||||
def _contact_offline(self, handle):
|
def _contact_offline(self, handle):
|
||||||
"""Handle contact going offline (send message, update set)"""
|
"""Handle contact going offline (send message, update set)"""
|
||||||
if not self._online_contacts.has_key(handle):
|
if not self._online_contacts.has_key(handle):
|
||||||
@ -659,6 +672,9 @@ class ServerPlugin(gobject.GObject):
|
|||||||
timestamp, statuses = presence[handle]
|
timestamp, statuses = presence[handle]
|
||||||
online = handle in self._online_contacts
|
online = handle in self._online_contacts
|
||||||
for status, params in statuses.items():
|
for status, params in statuses.items():
|
||||||
|
if not online and status == "offline":
|
||||||
|
# weren't online in the first place...
|
||||||
|
continue
|
||||||
jid = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
jid = self._conn[CONN_INTERFACE].InspectHandles(CONNECTION_HANDLE_TYPE_CONTACT, [handle])[0]
|
||||||
olstr = "ONLINE"
|
olstr = "ONLINE"
|
||||||
if not online: olstr = "OFFLINE"
|
if not online: olstr = "OFFLINE"
|
||||||
|
Loading…
Reference in New Issue
Block a user