Ejemplo n.º 1
0
    def __init__(self, config, webserver, deviceList):
	self.info("Create MyControlPoint")
        ControlPoint.__init__( self, webserver, deviceList )
#        super(ControlPoint,self).__init__( ws, deviceList )

        self._connections=[] # track them
	self._excludeList = None
	self._includeList = None
	# for now just on model name
	if config.has_key('excludedevice') and config['excludedevice'].has_key('modelName'):
	    self._excludeList = list()
	    excs = config['excludedevice']['modelName']
	    if isinstance( excs, list ):
		for ntry in excs:
		    self.debug("excludedevice %s", ntry)
		    self._excludeList.append( ntry[''].lower() )
	    else:
		self.debug("exclude %s", excs)
		self._excludeList.append( excs[''].lower() )

	if config.has_key('includedevice') and config['includedevice'].has_key('modelName'):
	    self._includeList = list()
	    incs = config['includedevice']['modelName']
	    if isinstance( incs, list ):
		for ntry in incs:
		    self.debug("include %s", ntry)
		    self._includeList.append( ntry[''].lower() )
	    else:
		self.debug("includedevice %s", incs)
		self._includeList.append( incs[''].lower() )
Ejemplo n.º 2
0
    def start(self):
        print "Upnp backend starting"
        # clear device list
        self._removeXML() 

        # config Coherence
        conf = Config(self._configfile)
        c = Coherence({'logmode':'warning'})
        c.setup(conf)        
        #add share folders
        con = ""
        for f in config.share_folders:
            if len(con) > 0:
                con +=","
            con += f
        c.add_plugin('FSStore',name=config.device_name,content=con)

        # start a ControlPoint to start detecting upnp activity
        cp = ControlPoint(c, auto_client=['MediaServer'])
        cp.connect(self.mediaserver_detected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
        cp.connect(self.mediaserver_removed, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
	
	#self._localdevice = cp.get_device_by_name(self._localdevicename)
	#print "SPRURPDDSOPF            ",self._localdevice.client.get_friendly_name()
        
        print "Upnp loop succesfully started"
        self._handler.start()
        print "DBus loop succesfully started"
Ejemplo n.º 3
0
class UPNP_Browser():
    def __init__(self):
        self.browse_count = 0
        self.music = Music_DB()
        self.__client = None
        self.control_point = ControlPoint(Coherence({'logmode':'warning'}),
            auto_client=['MediaServer'])
        self.control_point.connect(self.media_server_found,
                'Coherence.UPnP.ControlPoint.MediaServer.detected')
        self.control_point.connect(self.media_server_removed,
                'Coherence.UPnP.ControlPoint.MediaServer.removed')


        # now we should also try to discover the ones that are already there:
        for device in self.control_point.coherence.devices:
            print device

    # called for each media server found
    def media_server_found(self, client, udn):
        print "media_server_found", client
        print "media_server_found", client.device.get_friendly_name()

        self.__client = client
        self.load_children(0)

    # sadly they sometimes get removed as well :(
    def media_server_removed(self, udn):
        print "media_server_removed", udn

    # browse callback
    def process_media_server_browse(self, result, client):
        print "browsing root of", client.device.get_friendly_name()
        print "result contains %d out of %d total matches" % \
                (int(result['NumberReturned']), int(result['TotalMatches']))

        elt = DIDLLite.DIDLElement.fromString(result['Result'])
        for item in elt.getItems():
            if item.upnp_class.startswith("object.container"):
                self.load_children(item.id)

            if item.upnp_class.startswith("object.item"):
                url = None
                duration = None
                size = None

                for res in item.res:
                    remote_protocol,remote_network,remote_content_format,remote_flags = res.protocolInfo.split(':')
                    if remote_protocol == 'http-get':
                        url = res.data
                        duration = res.duration
                        size = res.size
                        break

                self.music.add_song(item, url, duration)

    def load_children(self, id):
        self.browse_count += 1
        d = self.__client.content_directory.browse(id, browse_flag='BrowseDirectChildren', process_result=False, backward_compatibility=False)
        d.addCallback(self.process_media_server_browse, self.__client)
Ejemplo n.º 4
0
    def check_device( self, device):
        self.info("found device %s of type %s",device.get_friendly_name(), device.get_device_type())
        short_type = device.get_device_type().split(':')[3]
        if short_type == "ZonePlayer":
                self.info("identified ZonePlayer %s", device.get_friendly_name())
                client = SonosZonePlayerClient(device)
                device.set_client(client)
# event sent in self.completed
                louie.send('Coherence.UPnP.ControlPoint.ZonePlayer.detected', None,
                                   client=client,udn=device.get_id())

        ControlPoint.check_device( self, device )
Ejemplo n.º 5
0
    def setup_part2(self):
        '''Initializes the basic and optional services/devices and the enabled
        plugins (backends).'''
        self.setup_ssdp_server()
        if not self.ssdp_server:
            raise Exception('Unable to initialize an ssdp server')

        self.msearch = MSearch(self.ssdp_server, test=self.is_unittest)

        reactor.addSystemEventTrigger(
            'before',
            'shutdown',
            self.shutdown,
            force=True,
        )

        self.setup_web_server()
        if not self.urlbase:
            raise Exception('Unable to initialize an web server')

        self.setup_plugins()

        # Control Point Initialization
        if (self.config.get('controlpoint', 'no') == 'yes'
                or self.config.get('json', 'no') == 'yes'):
            self.ctrl = ControlPoint(self)

        # Json Interface Initialization
        if self.config.get('json', 'no') == 'yes':
            from coherence.json_service import JsonInterface

            self.json = JsonInterface(self.ctrl)

        # Transcoder Initialization
        if self.config.get('transcoding', 'no') == 'yes':
            from coherence.transcoder import TranscoderManager

            self.transcoder_manager = TranscoderManager(self)

        # DBus Initialization
        if self.config.get('use_dbus', 'no') == 'yes':
            try:
                from coherence import dbus_service

                if self.ctrl is None:
                    self.ctrl = ControlPoint(self)
                self.ctrl.auto_client_append('InternetGatewayDevice')
                self.dbus = dbus_service.DBusPontoon(self.ctrl)
            except Exception as msg:
                self.warning(f'Unable to activate dbus sub-system: {msg}')
                self.debug(traceback.format_exc())
Ejemplo n.º 6
0
    def __init__(self,command,config):
        #print "command %r %r %r" %(command,config,config.subOptions)
        self.config = config
        self.locked = False
        if command == None:
            self.command = 'show-devices'
        else:
            self.command = command

        if self.command == 'show-devices':
            self.locked = None

        if self.command == 'add-mapping':
            if self.config.subOptions['internal-host'] == None:
                raise Exception("internal-host parameter missing")
            if self.config.subOptions['internal-port'] == None:
                raise Exception("internal-port parameter missing")
            if self.config.subOptions['protocol'].lower() not in ['tcp','udp']:
                raise Exception("protocol value invalid")
            if self.config.subOptions['active'].lower() in ['y','true','1','yes']:
                self.config.subOptions['active'] = True
            else:
                self.config.subOptions['active'] = False
            if self.config.subOptions['remote-host'].lower() in ['""','any']:
                self.config.subOptions['remote-host'] = ''
            if self.config.subOptions['external-port'] == None:
                self.config.subOptions['external-port'] = self.config.subOptions['internal-port']

        if self.command == 'delete-mapping':
            if self.config.subOptions['remote-host'] == None:
                raise Exception("remote-host parameter missing")
            if self.config.subOptions['external-port'] == None:
                raise Exception("external-port parameter missing")
            if self.config.subOptions['protocol'].lower() not in ['tcp','udp']:
                raise Exception("protocol value invalid")

        coherence_config = {}
        coherence_config['logmode'] = 'none'

        self.control_point = ControlPoint(Coherence(coherence_config),auto_client=['InternetGatewayDevice'])
        self.control_point.connect(self.igd_found, 'Coherence.UPnP.ControlPoint.InternetGatewayDevice.detected')
        self.control_point.connect(self.igd_removed, 'Coherence.UPnP.ControlPoint.InternetGatewayDevice.removed')

        self.timeout = reactor.callLater(int(self.config['timeout']),self.stop)
        self.devices = {}

        self.reports = {'show-devices': self.show_devices,
                        'show-mappings': self.show_mappings,
                        'info': self.show_info}
Ejemplo n.º 7
0
    def __init__(self):

        # configuration setup
        self.gconf = gconf.client_get_default()
        self.conf = {
            "autoconnect": self.gconf.get_bool(gconf_keys["autoconnect"]),
            "udn": self.gconf.get_string(gconf_keys["udn"]),
            "mmkeys": self.gconf.get_bool(gconf_keys["mmkeys"]),
        }

        # coherence setup
        self.coherence = Coherence({"logmode": "warning"})
        self.ctp = ControlPoint(self.coherence, auto_client=["MediaRenderer"])

        # internals setup
        self.client = MediaRendererClient(self.coherence)

        self.gui = StatusIconController(self)
        self.gui.connect(self.client)

        self.mmkeys = MMKeysController(name="MUPnPApp")
        # hack to make it start
        if True or self.conf["mmkeys"]:
            self.mmkeys.connect(self.client)

        # signal connection
        self.ctp.connect(self._renderer_found, "Coherence.UPnP.ControlPoint.MediaRenderer.detected")

        self.ctp.connect(self._renderer_removed, "Coherence.UPnP.ControlPoint.MediaRenderer.removed")
Ejemplo n.º 8
0
		def doStart(*args, **kwargs):
			if self._controlPoint:
				Log.w("already running!")
				return
			Log.i("starting now!")
			self._startPending = False
			self.coherence = Coherence({
				'logging': {
					'level' : 'warning', 
					'subsystem' : [
						{'name' : 'msearch', 'level' : 'warning'},
						{'name' : 'ssdp', 'level' : 'warning'}
					]}
				})
			self._controlPoint = ControlPoint(self.coherence, auto_client=['MediaServer','MediaRenderer'])
			self.coherence.ctrl = self._controlPoint
			self.__mediaServerClients = {}
			self.__mediaRendererClients = {}
			self.__mediaDevices = {}
			self.__devices = []
			self._controlPoint.connect(self._onMediaServerDetected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
			self._controlPoint.connect(self._onMediaServerRemoved, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
			self._controlPoint.connect(self._onMediaRendererDetected, 'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
			self._controlPoint.connect(self._onMediaRendererRemoved, 'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
			self._controlPoint.connect(self._onMediaDeviceDectected, 'Coherence.UPnP.Device.detection_completed')
			self._controlPoint.connect(self._onMediaDeviceRemoved, 'Coherence.UPnP.RootDevice.removed')
			self.__deferredShutDown = None
			if self._session:
				self._callPlugins(reason=0)
Ejemplo n.º 9
0
 def doStart(*args, **kwargs):
     if self._controlPoint:
         Log.w("already running!")
         return
     Log.i("starting now!")
     self._startPending = False
     self.coherence = Coherence({
         'logging': {
             'level':
             'warning',
             'subsystem': [{
                 'name': 'msearch',
                 'level': 'warning'
             }, {
                 'name': 'ssdp',
                 'level': 'warning'
             }]
         }
     })
     self._controlPoint = ControlPoint(
         self.coherence, auto_client=['MediaServer', 'MediaRenderer'])
     self.coherence.ctrl = self._controlPoint
     self.__mediaServerClients = {}
     self.__mediaRendererClients = {}
     self.__mediaDevices = {}
     self.__devices = []
     self._controlPoint.connect(
         self._onMediaServerDetected,
         'Coherence.UPnP.ControlPoint.MediaServer.detected')
     self._controlPoint.connect(
         self._onMediaServerRemoved,
         'Coherence.UPnP.ControlPoint.MediaServer.removed')
     self._controlPoint.connect(
         self._onMediaRendererDetected,
         'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
     self._controlPoint.connect(
         self._onMediaRendererRemoved,
         'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
     self._controlPoint.connect(
         self._onMediaDeviceDectected,
         'Coherence.UPnP.Device.detection_completed')
     self._controlPoint.connect(self._onMediaDeviceRemoved,
                                'Coherence.UPnP.RootDevice.removed')
     self.__deferredShutDown = None
     if self._session:
         self._callPlugins(reason=0)
Ejemplo n.º 10
0
def start():
    control_point = ControlPoint(Coherence({'logmode': 'warning'}),
                                 auto_client=['MediaServer'])
    control_point.connect(media_server_found,
                          'Coherence.UPnP.ControlPoint.MediaServer.detected')
    control_point.connect(media_server_removed,
                          'Coherence.UPnP.ControlPoint.MediaServer.removed')
Ejemplo n.º 11
0
    def start(self):
        print "Upnp backend starting"
        # clear device list
        self._removeXML()

        # config Coherence
        conf = Config(self._configfile)
        c = Coherence({'logmode': 'warning'})
        c.setup(conf)
        #add share folders
        con = ""
        for f in config.share_folders:
            if len(con) > 0:
                con += ","
            con += f
        c.add_plugin('FSStore', name=config.device_name, content=con)

        # start a ControlPoint to start detecting upnp activity
        cp = ControlPoint(c, auto_client=['MediaServer'])
        cp.connect(self.mediaserver_detected,
                   'Coherence.UPnP.ControlPoint.MediaServer.detected')
        cp.connect(self.mediaserver_removed,
                   'Coherence.UPnP.ControlPoint.MediaServer.removed')

        #self._localdevice = cp.get_device_by_name(self._localdevicename)
        #print "SPRURPDDSOPF            ",self._localdevice.client.get_friendly_name()

        print "Upnp loop succesfully started"
        self._handler.start()
        print "DBus loop succesfully started"
Ejemplo n.º 12
0
def start():
  control_point = ControlPoint(Coherence({'logmode': 'warning'}),
                               auto_client=['MediaServer'])
  control_point.connect(media_server_found, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
  control_point.connect(media_server_removed, 'Coherence.UPnP.ControlPoint.MediaServer.removed')

  # now we should also try to discover the ones that are already there:
  for device in control_point.coherence.devices:
    print device
Ejemplo n.º 13
0
    def __init__(self):
        self.browse_count = 0
        self.music = Music_DB()
        self.__client = None
        self.control_point = ControlPoint(Coherence({'logmode':'warning'}),
            auto_client=['MediaServer'])
        self.control_point.connect(self.media_server_found,
                'Coherence.UPnP.ControlPoint.MediaServer.detected')
        self.control_point.connect(self.media_server_removed,
                'Coherence.UPnP.ControlPoint.MediaServer.removed')


        # now we should also try to discover the ones that are already there:
        for device in self.control_point.coherence.devices:
            print device
Ejemplo n.º 14
0
	def __init__(self):
		self.coherence = Coherence({'logmode':'warning'})
		self._controlPoint = ControlPoint(self.coherence, auto_client=['MediaServer','MediaRenderer'])
		self._controlPoint.connect(self._onMediaServerDetected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
		self._controlPoint.connect(self._onMediaServerRemoved, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
		self._controlPoint.connect(self._onMediaRendererDetected, 'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
		self._controlPoint.connect(self._onMediaRendererRemoved, 'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
		self._controlPoint.connect(self._onMediaDeviceDectected, 'Coherence.UPnP.Device.detection_completed')

		self.__mediaServerClients = {}
		self.__mediaRendererClients = {}
		self.__mediaDevices = {}

		self.__browser = []
		self.__devices = []

		self.onMediaServerDetected = []
		self.onMediaServerRemoved  = []
		self.onMediaRendererDetected = []
		self.onMediaRendererRemoved = []
		self.onMediaDeviceDectected = []
Ejemplo n.º 15
0
  def setup_part2(self):
    self.info('running on host: %s', self.hostname)
    if self.hostname.startswith('127.'):
      self.warning('detection of own ip failed, using %s as own address, functionality will be limited', self.hostname)

    unittest = self.config.get('unittest', 'no')
    unittest = False if unittest == 'no' else True

    """ SSDP Server Initialization
    """
    try:
      # TODO: add ip/interface bind
      self.ssdp_server = SSDPServer(test=unittest)
    except CannotListenError as err:
      self.error("Error starting the SSDP-server: %s", err)
      self.debug("Error starting the SSDP-server", exc_info=True)
      reactor.stop()
      return

    louie.connect(self.create_device, 'Coherence.UPnP.SSDP.new_device', louie.Any)
    louie.connect(self.remove_device, 'Coherence.UPnP.SSDP.removed_device', louie.Any)
    louie.connect(self.add_device, 'Coherence.UPnP.RootDevice.detection_completed', louie.Any)
    # louie.connect( self.receiver, 'Coherence.UPnP.Service.detection_completed', louie.Any)

    self.ssdp_server.subscribe("new_device", self.add_device)
    self.ssdp_server.subscribe("removed_device", self.remove_device)

    self.msearch = MSearch(self.ssdp_server, test=unittest)

    reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, force=True)

    """ Web Server Initialization
    """
    try:
      # TODO: add ip/interface bind
      self.web_server = WebServer(self.config.get('web-ui', None), self.web_server_port, self)
    except CannotListenError:
      self.warning('port %r already in use, aborting!', self.web_server_port)
      reactor.stop()
      return

    self.urlbase = 'http://%s:%d/' % (self.hostname, self.web_server_port)
    # self.renew_service_subscription_loop = task.LoopingCall(self.check_devices)
    # self.renew_service_subscription_loop.start(20.0, now=False)

    try:
      plugins = self.config['plugin']
      if isinstance(plugins, dict):
        plugins = [plugins]
    except:
      plugins = None

    if plugins is None:
      plugins = self.config.get('plugins', None)

    if plugins is None:
      self.info("No plugin defined!")
    else:
      if isinstance(plugins, dict):
        for plugin, arguments in list(plugins.items()):
          try:
            if not isinstance(arguments, dict):
              arguments = {}
            self.add_plugin(plugin, **arguments)
          except Exception as msg:
            self.warning("Can't enable plugin, %s: %s!", plugin, msg)
            self.info(traceback.format_exc())
      else:
        for plugin in plugins:
          try:
            if plugin['active'] == 'no':
              continue
          except (KeyError, TypeError):
            pass
          try:
            backend = plugin['backend']
            arguments = copy.copy(plugin)
            del arguments['backend']
            backend = self.add_plugin(backend, **arguments)
            if self.writeable_config():
              if 'uuid' not in plugin:
                plugin['uuid'] = str(backend.uuid)[5:]
                self.config.save()
          except Exception as msg:
            self.warning("Can't enable plugin, %s: %s!", plugin, msg)
            self.info(traceback.format_exc())

    self.external_address = ':'.join((self.hostname, str(self.web_server_port)))

    """ Control Point Initialization
    """
    if self.config.get('controlpoint', 'no') == 'yes' or self.config.get('json', 'no') == 'yes':
      self.ctrl = ControlPoint(self)

    """ Json Interface Initialization
    """
    if self.config.get('json', 'no') == 'yes':
      from coherence.json_service import JsonInterface
      self.json = JsonInterface(self.ctrl)

    """ Transcoder Initialization
    """
    if self.config.get('transcoding', 'no') == 'yes':
      from coherence.transcoder import TranscoderManager
      self.transcoder_manager = TranscoderManager(self)

    """ DBus Initialization
    """
    if self.config.get('use_dbus', 'no') == 'yes':
      try:
        from coherence import dbus_service
        if self.ctrl is None:
          self.ctrl = ControlPoint(self)
        self.ctrl.auto_client_append('InternetGatewayDevice')
        self.dbus = dbus_service.DBusPontoon(self.ctrl)
      except Exception as msg:
        self.warning("Unable to activate dbus sub-system: %r", msg)
        self.debug(traceback.format_exc())
Ejemplo n.º 16
0
    def notify_device( self, client, device, isComplete=False ):
	if self.is_visible_device( device ):
	    ControlPoint.notify_device( self, client, device, isComplete )
	else:
	    self.info("Hiding %s from application", device)
Ejemplo n.º 17
0
class ManagedControlPoint(object):
    DEVICE_TYPE_SATIP_SERVER = "SatIPServer"
    DEVICE_TYPE_DREAMBOX = "Dreambox"
    URI_BASE_DREAMBOX = "urn:dreambox-de:device"

    def __init__(self):
        self.coherence = None
        self._controlPoint = None
        self.__mediaServerClients = {}
        self.__mediaRendererClients = {}
        self.__mediaDevices = {}
        self.__devices = []
        self.onMediaServerDetected = []
        self.onMediaServerRemoved = []
        self.onMediaRendererDetected = []
        self.onMediaRendererRemoved = []
        self.onMediaDeviceDectected = []
        self.onMediaDeviceRemoved = []
        self.onSatIpServerDetected = []
        self.onSatIpServerRemoved = []
        self.onDreamboxDetected = []
        self.onDreamboxRemoved = []
        self._session = None
        self.__deferredShutDown = None
        self._startPending = False

    def _onShutdownFinished(self, *args, **kwargs):
        self.__deferredShutDown = None
        if self._startPending:
            self.start()

    def start(self):
        def doStart(*args, **kwargs):
            if self._controlPoint:
                Log.w("already running!")
                return
            Log.i("starting now!")
            self._startPending = False
            self.coherence = Coherence({
                'logging': {
                    'level':
                    'warning',
                    'subsystem': [{
                        'name': 'msearch',
                        'level': 'warning'
                    }, {
                        'name': 'ssdp',
                        'level': 'warning'
                    }]
                }
            })
            self._controlPoint = ControlPoint(
                self.coherence, auto_client=['MediaServer', 'MediaRenderer'])
            self.coherence.ctrl = self._controlPoint
            self.__mediaServerClients = {}
            self.__mediaRendererClients = {}
            self.__mediaDevices = {}
            self.__devices = []
            self._controlPoint.connect(
                self._onMediaServerDetected,
                'Coherence.UPnP.ControlPoint.MediaServer.detected')
            self._controlPoint.connect(
                self._onMediaServerRemoved,
                'Coherence.UPnP.ControlPoint.MediaServer.removed')
            self._controlPoint.connect(
                self._onMediaRendererDetected,
                'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
            self._controlPoint.connect(
                self._onMediaRendererRemoved,
                'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
            self._controlPoint.connect(
                self._onMediaDeviceDectected,
                'Coherence.UPnP.Device.detection_completed')
            self._controlPoint.connect(self._onMediaDeviceRemoved,
                                       'Coherence.UPnP.RootDevice.removed')
            self.__deferredShutDown = None
            if self._session:
                self._callPlugins(reason=0)

        if self.__deferredShutDown:
            Log.w("deferring start until shutdown is finished")
            if not self._startPending:
                self._startPending = True
        else:
            doStart()

    def restart(self):
        Log.i()
        if not self.__deferredShutDown:
            self.shutdown()
        self.start()

    def setSession(self, session):
        self._session = session
        if self.coherence:
            self._callPlugins(reason=0)

    def _callPlugins(self, reason=0):
        for plugin in plugins.getPlugins(PluginDescriptor.WHERE_UPNP):
            plugin(reason, session=self._session)

    def _onMediaServerDetected(self, client, udn):
        print "[DLNA] MediaServer Detected: %s (%s)" % (
            client.device.get_friendly_name(),
            client.device.get_friendly_device_type())
        self.__mediaServerClients[udn] = client
        for fnc in self.onMediaServerDetected:
            fnc(udn, client)

    def _onMediaServerRemoved(self, udn):
        if self.__mediaServerClients.get(udn, None) != None:
            del self.__mediaServerClients[udn]
            for fnc in self.onMediaServerRemoved:
                fnc(udn)

    def _onMediaRendererDetected(self, client, udn):
        print "[DLNA] MediaRenderer detected: %s (%s, %s)" % (
            client.device.get_friendly_name(),
            client.device.get_friendly_device_type(), udn)
        self.__mediaRendererClients[udn] = client
        for fnc in self.onMediaRendererDetected:
            fnc(udn, client)

    def _onMediaRendererRemoved(self, udn):
        print "[DLNA] MediaRenderer removed: %s" % (udn)
        if self.__mediaRendererClients.get(udn, None) != None:
            del self.__mediaRendererClients[udn]
            for fnc in self.onMediaRendererRemoved:
                fnc(udn)

    def _onMediaDeviceDectected(self, device):
        if device.udn in self.__mediaDevices:
            return
        self.__mediaDevices[device.udn] = device
        device_type = device.get_friendly_device_type()
        if device_type == self.DEVICE_TYPE_SATIP_SERVER:
            Log.i("New SAT>IP Server found: %s (%s - %s)" %
                  (device.get_friendly_name(),
                   device.get_friendly_device_type(), device.get_satipcap()))
            for fnc in self.onSatIpServerDetected:
                fnc(device)
        elif device_type == self.DEVICE_TYPE_DREAMBOX:
            Log.i(
                "New Dreambox found: %s (%s - %s)" %
                (device.get_friendly_name(), device.get_friendly_device_type(),
                 device.get_presentation_url()))
            for fnc in self.onDreamboxDetected:
                fnc(device)
        else:
            Log.i("New Device found: %s (%s)" %
                  (device.get_friendly_name(),
                   device.get_friendly_device_type()))

    def _onMediaDeviceRemoved(self, usn):
        if usn in self.__mediaDevices:
            print "[DLNA] Device removed: %s" % (usn)
            device = self.__mediaDevices[usn]
            device_type = device.get_friendly_device_type()
            if device_type == self.DEVICE_TYPE_SATIP_SERVER:
                for fnc in self.onSatIpServerRemoved:
                    fnc(device)
            elif device_type == self.DEVICE_TYPE_DREAMBOX:
                for fnc in self.onDreamboxRemoved:
                    fnc(device)
            for fnc in self.onMediaDeviceRemoved:
                fnc(device)
            del self.__mediaDevices[usn]

    def registerRenderer(self, classDef, **kwargs):
        renderer = MediaRenderer(self.coherence,
                                 classDef,
                                 no_thread_needed=True,
                                 **kwargs)
        self.__devices.append(renderer)
        return renderer

    def registerServer(self, classDef, **kwargs):
        server = MediaServer(self.coherence,
                             classDef,
                             no_thread_needed=True,
                             **kwargs)
        self.__devices.append(server)
        return server

    def registerDevice(self, instance, **kwargs):
        self.__devices.append(instance)
        return instance

    def getServerList(self):
        return self.__mediaServerClients.values()

    def getRenderingControlClientList(self):
        return self.__mediaRendererClients.values()

    def getDeviceName(self, client):
        return Item.ue(client.device.get_friendly_name())

    def getSatIPDevices(self):
        devices = []
        for device in self.__mediaDevices.itervalues():
            if device.get_friendly_device_type(
            ) == self.DEVICE_TYPE_SATIP_SERVER:
                devices.append(device)
        return devices

    def getDreamboxes(self):
        devices = []
        for device in self.__mediaDevices.itervalues():
            if device.get_friendly_device_type() == self.DEVICE_TYPE_DREAMBOX:
                devices.append(device)
        return devices

    def getDevice(self, uuid):
        for device in self.__devices:
            if device.uuid == uuid:
                return device
        return None

    def removeDevice(self, uuid):
        device = self.getDevice(uuid)
        if device:
            device.unregister()
            self.__devices.remove(device)
            return True
        return False

    def shutdown(self):
        Log.i("%s" % (self.coherence, ))
        if True:
            Log.w(
                "shutdown is broken... will continue running. please restart enigma2 instead!"
            )
            return
        if self.coherence:
            self._callPlugins(reason=1)
            self.__mediaServerClients = {}
            self.__mediaRendererClients = {}
            self.__mediaDevices = {}
            self.__devices = []
            self.__deferredShutDown = self.coherence.shutdown(force=True)
            self.__deferredShutDown.addCallback(self._onShutdownFinished)
            self._controlPoint.disconnect(
                self._onMediaServerDetected,
                'Coherence.UPnP.ControlPoint.MediaServer.detected')
            self._controlPoint.disconnect(
                self._onMediaServerRemoved,
                'Coherence.UPnP.ControlPoint.MediaServer.removed')
            self._controlPoint.disconnect(
                self._onMediaRendererDetected,
                'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
            self._controlPoint.disconnect(
                self._onMediaRendererRemoved,
                'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
            self._controlPoint.disconnect(
                self._onMediaDeviceDectected,
                'Coherence.UPnP.Device.detection_completed')
            self._controlPoint.disconnect(self._onMediaDeviceRemoved,
                                          'Coherence.UPnP.RootDevice.removed')
            self.coherence = None
            self._controlPoint = None
Ejemplo n.º 18
0
class ManagedControlPoint(object):
	def __init__(self):
		self.coherence = Coherence({'logmode':'warning'})
		self._controlPoint = ControlPoint(self.coherence, auto_client=['MediaServer','MediaRenderer'])
		self._controlPoint.connect(self._onMediaServerDetected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
		self._controlPoint.connect(self._onMediaServerRemoved, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
		self._controlPoint.connect(self._onMediaRendererDetected, 'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
		self._controlPoint.connect(self._onMediaRendererRemoved, 'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
		self._controlPoint.connect(self._onMediaDeviceDectected, 'Coherence.UPnP.Device.detection_completed')

		self.__mediaServerClients = {}
		self.__mediaRendererClients = {}
		self.__mediaDevices = {}

		self.__browser = []
		self.__devices = []

		self.onMediaServerDetected = []
		self.onMediaServerRemoved  = []
		self.onMediaRendererDetected = []
		self.onMediaRendererRemoved = []
		self.onMediaDeviceDectected = []

	def _onMediaServerDetected(self, client, udn):
		print "[DLNA] MediaServer Detected: %s (%s)" % (client.device.get_friendly_name(), client.device.get_friendly_device_type())
		self.__mediaServerClients[udn] = client
		for fnc in self.onMediaServerDetected:
			fnc(udn, client)

	def _onMediaServerRemoved(self, udn):
		if self.__mediaServerClients.get(udn, None) != None:
			del self.__mediaServerClients[udn]
			for fnc in self.onMediaServerRemoved:
				fnc(udn)

	def _onMediaRendererDetected(self, client, udn):
		print "[DLNA] MediaRenderer detected: %s (%s, %s)" % (client.device.get_friendly_name(), client.device.get_friendly_device_type(), udn)
		self.__mediaRendererClients[udn] = client
		for fnc in self.onMediaRendererDetected:
			fnc(udn, client)

	def _onMediaRendererRemoved(self, udn):
		print "[DLNA] MediaRenderer removed: %s" % (udn)
		if self.__mediaRendererClients.get(udn, None) != None:
			del self.__mediaRendererClients[udn]
			for fnc in self.onMediaRendererRemoved:
				fnc(udn)

	def _onMediaDeviceDectected(self, device):
		print "[DLNA] Device found: %s (%s)" % (device.get_friendly_name(), device.get_friendly_device_type())
		self.__mediaDevices[device.udn] = device

	def registerRenderer(self, classDef, **kwargs):
		renderer = MediaRenderer(self.coherence, classDef, no_thread_needed=True, **kwargs)
		self.__devices.append(renderer)
		return renderer

	def registerServer(self, classDef, **kwargs):
		server = MediaServer(self.coherence, classDef, no_thread_needed=True, **kwargs)
		self.__devices.append(server)
		return server

	def getServerList(self):
		return self.__mediaServerClients.values()

	def getRenderingControlClientList(self):
		return self.__mediaRendererClients.values()

	def getDeviceName(self, client):
		return Item.ue(client.device.get_friendly_name())

	def shutdown(self):
		for device in self.__devices:
			device.unregister()
		self._controlPoint.shutdown()
Ejemplo n.º 19
0
    def __init__(self, logfile=None):
        config = {'logmode': 'none', 'logfile': logfile}
        self.coherence = Coherence(config)
        self.controlpoint = ControlPoint(self.coherence, auto_client=[])
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.connect("delete_event", lambda x, y: reactor.stop())
        window.set_default_size(350, 700)
        window.set_title('UPnP Inspector')
        icon = resource_filename(__name__,
                                 os.path.join('icons', 'inspector-icon.png'))
        gtk.window_set_default_icon_from_file(icon)

        vbox = gtk.VBox(homogeneous=False, spacing=0)
        menu_bar = gtk.MenuBar()
        menu = gtk.Menu()
        refresh_item = gtk.MenuItem("Rediscover Devices")
        refresh_item.connect("activate", self.refresh_devices)
        menu.append(refresh_item)
        menu.append(gtk.SeparatorMenuItem())
        quit_item = gtk.MenuItem("Quit")
        menu.append(quit_item)
        quit_item.connect("activate", lambda x: reactor.stop())

        file_menu = gtk.MenuItem("File")
        file_menu.set_submenu(menu)
        menu_bar.append(file_menu)

        menu = gtk.Menu()
        self.show_details_item = gtk.CheckMenuItem("show details")
        menu.append(self.show_details_item)
        self.show_details_item.connect("activate", self.show_details_widget,
                                       "view.details")
        self.show_events_item = gtk.CheckMenuItem("show events")
        menu.append(self.show_events_item)
        self.show_events_item.connect("activate", self.show_events_widget,
                                      "view.events")
        self.show_log_item = gtk.CheckMenuItem("show global log")
        menu.append(self.show_log_item)
        self.show_log_item.connect("activate", self.show_log_widget,
                                   "view.log")
        #self.show_log_item.set_sensitive(False)
        view_menu = gtk.MenuItem("View")
        view_menu.set_submenu(menu)
        menu_bar.append(view_menu)

        test_menu = gtk.MenuItem("Test")
        test_menu.set_sensitive(False)
        #test_menu.set_submenu(menu)
        menu_bar.append(test_menu)

        menu = gtk.Menu()
        item = gtk.MenuItem("Info")
        menu.append(item)
        item.connect("activate", self.show_about_widget, "help.info")
        help_menu = gtk.MenuItem("Help")
        help_menu.set_submenu(menu)
        menu_bar.append(help_menu)

        vbox.pack_start(menu_bar, False, False, 2)

        self.device_tree = DevicesWidget(self.coherence)
        self.device_tree.cb_item_left_click = self.show_details
        vbox.pack_start(self.device_tree.window, True, True, 0)
        window.add(vbox)
        window.show_all()

        self.events_widget = EventsWidget(self.coherence)
        self.events_widget.window.connect('delete_event',
                                          self.hide_events_widget)
        self.details_widget = DetailsWidget(self.coherence)
        self.details_widget.window.connect('delete_event',
                                           self.hide_details_widget)
        self.log_widget = LogWidget(self.coherence)
        self.log_widget.window.connect('delete_event', self.hide_log_widget)
Ejemplo n.º 20
0
class Puncher(object):

    def __init__(self,command,config):
        #print "command %r %r %r" %(command,config,config.subOptions)
        self.config = config
        self.locked = False
        if command == None:
            self.command = 'show-devices'
        else:
            self.command = command

        if self.command == 'show-devices':
            self.locked = None

        if self.command == 'add-mapping':
            if self.config.subOptions['internal-host'] == None:
                raise Exception("internal-host parameter missing")
            if self.config.subOptions['internal-port'] == None:
                raise Exception("internal-port parameter missing")
            if self.config.subOptions['protocol'].lower() not in ['tcp','udp']:
                raise Exception("protocol value invalid")
            if self.config.subOptions['active'].lower() in ['y','true','1','yes']:
                self.config.subOptions['active'] = True
            else:
                self.config.subOptions['active'] = False
            if self.config.subOptions['remote-host'].lower() in ['""','any']:
                self.config.subOptions['remote-host'] = ''
            if self.config.subOptions['external-port'] == None:
                self.config.subOptions['external-port'] = self.config.subOptions['internal-port']

        if self.command == 'delete-mapping':
            if self.config.subOptions['remote-host'] == None:
                raise Exception("remote-host parameter missing")
            if self.config.subOptions['external-port'] == None:
                raise Exception("external-port parameter missing")
            if self.config.subOptions['protocol'].lower() not in ['tcp','udp']:
                raise Exception("protocol value invalid")

        coherence_config = {}
        coherence_config['logmode'] = 'none'

        self.control_point = ControlPoint(Coherence(coherence_config),auto_client=['InternetGatewayDevice'])
        self.control_point.connect(self.igd_found, 'Coherence.UPnP.ControlPoint.InternetGatewayDevice.detected')
        self.control_point.connect(self.igd_removed, 'Coherence.UPnP.ControlPoint.InternetGatewayDevice.removed')

        self.timeout = reactor.callLater(int(self.config['timeout']),self.stop)
        self.devices = {}

        self.reports = {'show-devices': self.show_devices,
                        'show-mappings': self.show_mappings,
                        'info': self.show_info}


    def show_devices(self):
        for uuid in self.devices.keys():
            print "%s with uuid:%s" % (self.devices[uuid]['friendly_name'], uuid)

    def show_info(self):
        for uuid in self.devices.keys():
            print "%s with uuid:%s" % (self.devices[uuid]['friendly_name'], uuid)
        if len(self.devices) > 0:
            print "External IP address: ", self.external_ip_address
            print "Number of port-mappings: ", self.port_mapping_number_of_entries

    def show_mappings(self):
        for uuid in self.devices.keys():
            print "%s with uuid:%s" % (self.devices[uuid]['friendly_name'], uuid)
        mappings = self.devices[uuid].get('mappings',None)
        if mappings == None or len(mappings) == 0:
            print "no port-mappings found"
        else:
            print "Ext. Port | Remote Host    | Int. Port | Internal Host   | Prot. | active | duration | description"
            print "=" * 100
            for mapping in mappings:
                if mapping['NewLeaseDuration'] == '0':
                    mapping['NewLeaseDuration'] = 'infinite'
                else:
                    mapping['NewLeaseDuration'] += 'sec'
                if mapping['NewRemoteHost'] == '':
                    mapping['NewRemoteHost'] = 'any'
                if mapping['NewEnabled'] == '1':
                    mapping['NewEnabled'] = 'yes'
                else:
                    mapping['NewEnabled'] = 'no'
                print "    %05s | %-14s |     %05s | %-14s | %5s | %6s | %8s | %s" % (mapping['NewExternalPort'],
                                                                                   mapping['NewRemoteHost'],
                                                                                   mapping['NewInternalPort'],
                                                                                   mapping['NewInternalClient'],
                                                                                   mapping['NewProtocol'],
                                                                                   mapping['NewEnabled'],
                                                                                   mapping['NewLeaseDuration'],
                                                                                   mapping['NewPortMappingDescription'])
            print "=" * 100

    def stop(self,quiet=False):
        try:
            self.timeout.cancel()
        except:
            pass

        if quiet == False:
            if len(self.devices) == 0:
                print "no InternetGatewayDevice found"
            elif len(self.devices) == 1:
                print "1 InternetGatewayDevice found:"
            else:
                print "%d InternetGatewayDevices found:" % len(self.devices)
            self.reports.get(self.command,self.show_devices)()
        print ""
        reactor.stop()

    def append_mappings(self,mappings,device):
        device['mappings'] = mappings
        self.stop()

    def add_mapping_ok(self,result,device):
        print "port-mapping to %s added" %device['friendly_name']
        self.stop(quiet=True)

    def add_mapping_failed(self,result,device):
        print "failed to add port-mapping to %s" %device['friendly_name']
        self.stop(quiet=True)

    def delete_mapping_ok(self,result,device):
        print "port-mapping deleted from %s" %device['friendly_name']
        self.stop(quiet=True)

    def delete_mapping_failed(self,result,device):
        print "failed to delete port-mapping from %s" %device['friendly_name']
        self.stop(quiet=True)

    def igd_found(self,client,udn):
        #print "IGD found", client.device.get_friendly_name()
        if self.locked == True:
            return
        elif self.locked == False:
            self.locked = True
        if(self.config['uuid'] != None and
           client.device.get_uuid().endswith(self.config['uuid']) == False):
            return
        self.devices[client.device.get_uuid()] = {'friendly_name': client.device.get_friendly_name()}
        if self.locked == True:
            wan_ip_connection_service = client.wan_device.wan_connection_device.wan_ip_connection or \
                                        client.wan_device.wan_connection_device.wan_ppp_connection
            if self.command == 'show-mappings':
                dfr = wan_ip_connection_service.get_all_port_mapping_entries()
                dfr.addCallback(self.append_mappings,self.devices[client.device.get_uuid()])
            elif self.command == 'add-mapping':
                dfr = wan_ip_connection_service.add_port_mapping(remote_host=self.config.subOptions['remote-host'],
                             external_port=int(self.config.subOptions['external-port']),
                             protocol=self.config.subOptions['protocol'].upper(),
                             internal_port=int(self.config.subOptions['internal-port']),
                             internal_client=self.config.subOptions['internal-host'],
                             enabled=self.config.subOptions['active'],
                             port_mapping_description=self.config.subOptions['description'],
                             lease_duration=int(self.config.subOptions['lease-duration']))
                dfr.addCallback(self.add_mapping_ok,self.devices[client.device.get_uuid()])
                dfr.addErrback(self.add_mapping_failed,self.devices[client.device.get_uuid()])
            elif self.command == 'delete-mapping':
                dfr = wan_ip_connection_service.delete_port_mapping(remote_host=self.config.subOptions['remote-host'],
                             external_port=int(self.config.subOptions['external-port']),
                             protocol=self.config.subOptions['protocol'].upper())
                dfr.addCallback(self.delete_mapping_ok,self.devices[client.device.get_uuid()])
                dfr.addErrback(self.delete_mapping_failed,self.devices[client.device.get_uuid()])
            elif self.command == 'info':
                self.port_mapping_number_of_entries = None
                self.external_ip_address = None
                wan_ip_connection_service.subscribe_for_variable('PortMappingNumberOfEntries', callback=self.state_variable_change)
                wan_ip_connection_service.subscribe_for_variable('ExternalIPAddress', callback=self.state_variable_change)


    def igd_removed(self,udn):
        #print "IGD removed", udn
        pass

    def state_variable_change(self,variable):
        if variable.name == 'ExternalIPAddress':
            self.external_ip_address = variable.value
        elif variable.name == 'PortMappingNumberOfEntries':
            if variable.value != '':
                self.port_mapping_number_of_entries = int(variable.value)
            else:
                self.port_mapping_number_of_entries = 0
        if(self.port_mapping_number_of_entries != None and
           self.external_ip_address != None):
            self.stop()
Ejemplo n.º 21
0
class UpnpRapp(object):
    def __init__(self):

        # configuration setup
        self.gconf = gconf.client_get_default()
        self.conf = {
            "autoconnect": self.gconf.get_bool(gconf_keys["autoconnect"]),
            "udn": self.gconf.get_string(gconf_keys["udn"]),
            "mmkeys": self.gconf.get_bool(gconf_keys["mmkeys"]),
        }

        # coherence setup
        self.coherence = Coherence({"logmode": "warning"})
        self.ctp = ControlPoint(self.coherence, auto_client=["MediaRenderer"])

        # internals setup
        self.client = MediaRendererClient(self.coherence)

        self.gui = StatusIconController(self)
        self.gui.connect(self.client)

        self.mmkeys = MMKeysController(name="MUPnPApp")
        # hack to make it start
        if True or self.conf["mmkeys"]:
            self.mmkeys.connect(self.client)

        # signal connection
        self.ctp.connect(self._renderer_found, "Coherence.UPnP.ControlPoint.MediaRenderer.detected")

        self.ctp.connect(self._renderer_removed, "Coherence.UPnP.ControlPoint.MediaRenderer.removed")

    def _renderer_found(self, device=None, udn=None, client=None):
        # FIXME: take care about the auto connect if not connected yet
        # instead of just connecting
        if not device:
            device = self.coherence.get_device_with_id(udn)

        self.gui.device_found(device, udn)
        if not self.client.device and self.conf["autoconnect"]:
            if device.udn == self.conf["udn"]:
                self.connect(device)

    def _renderer_removed(self, device=None, udn=None):
        return
        self.gui.renderer_removed(device, udn)

    def set_autoconnect(self, value):
        self.conf["autoconnect"] = value
        self.gconf.set_bool(gconf_keys["autoconnect"], value)

    def set_mmkeys(self, value):
        self.conf["mmkeys"] = value
        self.gconf.set_bool(gconf_keys["mmkeys"], value)
        # reloading
        if not value:
            self.mmkeys.disconnect()
        else:
            self.mmkeys.connect(self.client)

    def quit(self, value=0):
        # FIXME: we should disconnect and stuff here
        sys.exit(value)

    def connect(self, device):
        print "connecting to %s" % device.get_friendly_name()
        self.gconf.set_string(gconf_keys["udn"], str(device.udn))

        self.client.disconnect()
        self.client.connect(device)
        # HACK!
        self.gui._connection_state_changed(True, device)
Ejemplo n.º 22
0
from twisted.internet import stdio
from twisted.internet import defer
from twisted.protocols import basic

from lxml import etree

import time, json, shutil, os

from coherence.base import Coherence
from coherence.upnp.devices.control_point import ControlPoint

logfile = None
config = {'logmode': 'none', 'logfile': logfile}
coherence = Coherence(config)

controlpoint = ControlPoint(coherence, auto_client=[])

BOOKMARKPATH = os.path.expanduser('~/.grace-bookmarks')

devices = []
unknown_devices = []

CONFPATH = os.path.join(os.path.expanduser('~'), '.graceradiorc')
DEFAULT_CONFIG = {
    # Number of lines to output from the buffer every time enter is pressed
    "buffer_rate": 20,
}

CONFIG = load_config(DEFAULT_CONFIG, CONFPATH)

Ejemplo n.º 23
0
class Coherence(log.Loggable):
  __instance = None  # Singleton
  logCategory = 'coherence'

  def __new__(cls, *args, **kwargs):
    if cls.__instance is None:
      cls.__instance = super(Coherence, cls).__new__(cls)
      cls.__instance.__initialized = False
      cls.__instance.__incarnations = 0
      cls.__instance.__cls = cls
    cls.__instance.__incarnations += 1
    return cls.__instance

  def __init__(self, config=None):
    # initialize only once
    if self.__initialized:
      return
    self.__initialized = True

    # supers
    log.Loggable.__init__(self)

    self.config = config or {}

    self.devices = []
    self.children = {}
    self._callbacks = {}
    self.active_backends = {}
    self.available_plugins = None

    self.external_address = None
    self.urlbase = None
    self.web_server_port = int(config.get('serverport', 0))

    """ Services """
    self.ctrl = None
    self.dbus = None
    self.json = None
    self.msearch = None
    self.ssdp_server = None
    self.transcoder_manager = None
    self.web_server = None

    """ initializes logsystem
        a COHEN_DEBUG environment variable overwrites
        all level settings here
    """
    try:
      logmode = config.get('logging').get('level', 'warning')
    except (KeyError, AttributeError):
      logmode = config.get('logmode', 'warning')

    try:
      subsystems = config.get('logging')['subsystem']
      if isinstance(subsystems, dict):
        subsystems = [subsystems]
      for subsystem in subsystems:
        try:
          if subsystem['active'] == 'no':
            continue
        except (KeyError, TypeError):
          pass
        self.info("setting log-level for subsystem %s to %s", subsystem['name'], subsystem['level'])
        logging.getLogger(subsystem['name'].lower()).setLevel(subsystem['level'].upper())
    except (KeyError, TypeError):
      subsystem_log = config.get('subsystem_log', {})
      for subsystem, level in list(subsystem_log.items()):
        logging.getLogger(subsystem.lower()).setLevel(level.upper())
    try:
      logfile = config.get('logging').get('logfile', None)
      if logfile is not None:
        logfile = str(logfile)
    except (KeyError, AttributeError, TypeError):
      logfile = config.get('logfile', None)
    log.init(logfile, logmode.upper())

    self.warning("Coherence UPnP framework version %s starting...", __version__)

    network_if = config.get('interface')
    if network_if:
      self.hostname = get_ip_address('%s' % network_if)
    else:
      try:
        self.hostname = socket.gethostbyname(socket.gethostname())
      except socket.gaierror:
        self.warning("hostname can't be resolved, maybe a system misconfiguration?")
        self.hostname = '127.0.0.1'

    if self.hostname.startswith('127.'):
      """ use interface detection via routing table as last resort """
      def catch_result(hostname):
        self.hostname = hostname
        self.setup_part2()
      d = defer.maybeDeferred(get_host_address)
      d.addCallback(catch_result)
    else:
      self.setup_part2()

  def clear(self):
    """ we do need this to survive multiple calls
        to Coherence during trial tests
    """
    self.__cls.__instance = None

  def setup_part2(self):
    self.info('running on host: %s', self.hostname)
    if self.hostname.startswith('127.'):
      self.warning('detection of own ip failed, using %s as own address, functionality will be limited', self.hostname)

    unittest = self.config.get('unittest', 'no')
    unittest = False if unittest == 'no' else True

    """ SSDP Server Initialization
    """
    try:
      # TODO: add ip/interface bind
      self.ssdp_server = SSDPServer(test=unittest)
    except CannotListenError as err:
      self.error("Error starting the SSDP-server: %s", err)
      self.debug("Error starting the SSDP-server", exc_info=True)
      reactor.stop()
      return

    louie.connect(self.create_device, 'Coherence.UPnP.SSDP.new_device', louie.Any)
    louie.connect(self.remove_device, 'Coherence.UPnP.SSDP.removed_device', louie.Any)
    louie.connect(self.add_device, 'Coherence.UPnP.RootDevice.detection_completed', louie.Any)
    # louie.connect( self.receiver, 'Coherence.UPnP.Service.detection_completed', louie.Any)

    self.ssdp_server.subscribe("new_device", self.add_device)
    self.ssdp_server.subscribe("removed_device", self.remove_device)

    self.msearch = MSearch(self.ssdp_server, test=unittest)

    reactor.addSystemEventTrigger('before', 'shutdown', self.shutdown, force=True)

    """ Web Server Initialization
    """
    try:
      # TODO: add ip/interface bind
      self.web_server = WebServer(self.config.get('web-ui', None), self.web_server_port, self)
    except CannotListenError:
      self.warning('port %r already in use, aborting!', self.web_server_port)
      reactor.stop()
      return

    self.urlbase = 'http://%s:%d/' % (self.hostname, self.web_server_port)
    # self.renew_service_subscription_loop = task.LoopingCall(self.check_devices)
    # self.renew_service_subscription_loop.start(20.0, now=False)

    try:
      plugins = self.config['plugin']
      if isinstance(plugins, dict):
        plugins = [plugins]
    except:
      plugins = None

    if plugins is None:
      plugins = self.config.get('plugins', None)

    if plugins is None:
      self.info("No plugin defined!")
    else:
      if isinstance(plugins, dict):
        for plugin, arguments in list(plugins.items()):
          try:
            if not isinstance(arguments, dict):
              arguments = {}
            self.add_plugin(plugin, **arguments)
          except Exception as msg:
            self.warning("Can't enable plugin, %s: %s!", plugin, msg)
            self.info(traceback.format_exc())
      else:
        for plugin in plugins:
          try:
            if plugin['active'] == 'no':
              continue
          except (KeyError, TypeError):
            pass
          try:
            backend = plugin['backend']
            arguments = copy.copy(plugin)
            del arguments['backend']
            backend = self.add_plugin(backend, **arguments)
            if self.writeable_config():
              if 'uuid' not in plugin:
                plugin['uuid'] = str(backend.uuid)[5:]
                self.config.save()
          except Exception as msg:
            self.warning("Can't enable plugin, %s: %s!", plugin, msg)
            self.info(traceback.format_exc())

    self.external_address = ':'.join((self.hostname, str(self.web_server_port)))

    """ Control Point Initialization
    """
    if self.config.get('controlpoint', 'no') == 'yes' or self.config.get('json', 'no') == 'yes':
      self.ctrl = ControlPoint(self)

    """ Json Interface Initialization
    """
    if self.config.get('json', 'no') == 'yes':
      from coherence.json_service import JsonInterface
      self.json = JsonInterface(self.ctrl)

    """ Transcoder Initialization
    """
    if self.config.get('transcoding', 'no') == 'yes':
      from coherence.transcoder import TranscoderManager
      self.transcoder_manager = TranscoderManager(self)

    """ DBus Initialization
    """
    if self.config.get('use_dbus', 'no') == 'yes':
      try:
        from coherence import dbus_service
        if self.ctrl is None:
          self.ctrl = ControlPoint(self)
        self.ctrl.auto_client_append('InternetGatewayDevice')
        self.dbus = dbus_service.DBusPontoon(self.ctrl)
      except Exception as msg:
        self.warning("Unable to activate dbus sub-system: %r", msg)
        self.debug(traceback.format_exc())

  def add_plugin(self, plugin, **kwargs):
    self.info("adding plugin %r", plugin)

    self.available_plugins = Plugins()

    # TODO clean up this exception concept
    try:
      plugin_class = self.available_plugins.get(plugin, None)
      if plugin_class is None:
        raise KeyError
      for device in plugin_class.implements:
        try:
          device_class = globals().get(device, None)
          if device_class is None:
            raise KeyError
          self.info("Activating %s plugin as %s...", plugin, device)
          new_backend = device_class(self, plugin_class, **kwargs)
          self.active_backends[str(new_backend.uuid)] = new_backend
          return new_backend
        except KeyError:
          self.warning("Can't enable %s plugin, sub-system %s not found!", plugin, device)
        except:
          self.exception("Can't enable %s plugin for sub-system %s", plugin, device)
          self.debug(traceback.format_exc())
    except KeyError:
      self.warning("Can't enable %s plugin, not found!", plugin)
    except Exception as msg:
      self.warning("Can't enable %s plugin, %s!", plugin, msg)
      self.debug(traceback.format_exc())

  def remove_plugin(self, plugin):
    """
    Removes a backend from Coherence

    @:param plugin: is the object return by add_plugin or an UUID string
    """
    if isinstance(plugin, str):
      try:
        plugin = self.active_backends[plugin]
      except KeyError:
        self.warning("no backend with the uuid %r found", plugin)
        return ""

    try:
      del self.active_backends[str(plugin.uuid)]
      self.info("removing plugin %r", plugin)
      plugin.unregister()
      return plugin.uuid
    except KeyError:
      self.warning("no backend with the uuid %r found", plugin.uuid)
      return ""

  @staticmethod
  def writeable_config():
    """ do we have a new-style config file """
    return False

  def store_plugin_config(self, uuid, items):
    """ find the backend with uuid
        and store in its the config
        the key and value pair(s)
    """
    plugins = self.config.get('plugin')
    if plugins is None:
      self.warning("storing a plugin config option is only possible with the new config file format")
      return
    if isinstance(plugins, dict):
      plugins = [plugins]
    uuid = str(uuid)
    if uuid.startswith('uuid:'):
      uuid = uuid[5:]
    for plugin in plugins:
      try:
        if plugin['uuid'] == uuid:
          for k, v in list(items.items()):
            plugin[k] = v
          self.config.save()
      except:
        pass
    else:
      self.info("storing plugin config option for %s failed, plugin not found", uuid)

  def receiver(self, signal, *args, **kwargs):
    pass

  def shutdown(self, force=False):
    if self.__incarnations > 1 and not force:
      self.__incarnations -= 1
      return

    if self.dbus:
      self.dbus.shutdown()
      self.dbus = None

    for backend in self.active_backends.values():
      backend.unregister()
    self.active_backends = {}

    """ send service unsubscribe messages """
    try:
      if self.web_server.port is not None:
        self.web_server.port.stopListening()
        self.web_server.port = None
      if hasattr(self.msearch, 'double_discover_loop'):
        self.msearch.double_discover_loop.stop()
      if hasattr(self.msearch, 'port'):
        self.msearch.port.stopListening()
      if hasattr(self.ssdp_server, 'resend_notify_loop'):
        self.ssdp_server.resend_notify_loop.stop()
      if hasattr(self.ssdp_server, 'port'):
        self.ssdp_server.port.stopListening()
      #self.renew_service_subscription_loop.stop()
    except:
      pass

    l = []
    for root_device in self.get_devices():
      for device in root_device.get_devices():
        dd = device.unsubscribe_service_subscriptions()
        dd.addCallback(device.remove)
        l.append(dd)
      rd = root_device.unsubscribe_service_subscriptions()
      rd.addCallback(root_device.remove)
      l.append(rd)

    def homecleanup(result):
      """anything left over"""
      louie.disconnect(self.create_device, 'Coherence.UPnP.SSDP.new_device', louie.Any)
      louie.disconnect(self.remove_device, 'Coherence.UPnP.SSDP.removed_device', louie.Any)
      louie.disconnect(self.add_device, 'Coherence.UPnP.RootDevice.detection_completed', louie.Any)
      self.ssdp_server.shutdown()
      if self.ctrl:
        self.ctrl.shutdown()
      self.warning('Coherence UPnP framework shutdown')
      return result

    dl = defer.DeferredList(l)
    dl.addCallback(homecleanup)
    return dl

  def check_devices(self):
    """ iterate over devices and their embedded ones and renew subscriptions """
    for root_device in self.get_devices():
      root_device.renew_service_subscriptions()
      for device in root_device.get_devices():
        device.renew_service_subscriptions()

  def subscribe(self, name, callback):
    self._callbacks.setdefault(name, []).append(callback)

  def unsubscribe(self, name, callback):
    callbacks = self._callbacks.get(name, [])
    if callback in callbacks:
      callbacks.remove(callback)
    self._callbacks[name] = callbacks

  def callback(self, name, *args):
    for callback in self._callbacks.get(name, []):
      callback(*args)

  def get_device_by_host(self, host):
    found = []
    for device in self.devices:
      if device.get_host() == host:
        found.append(device)
    return found

  def get_device_with_usn(self, usn):
    found = None
    for device in self.devices:
      if device.get_usn() == usn:
        found = device
        break
    return found

  def get_device_with_id(self, device_id):
    found = None
    for device in self.devices:
      id = device.get_id()
      if device_id[:5] != 'uuid:':
        id = id[5:]
      if id == device_id:
        found = device
        break
    return found

  def get_devices(self):
    return self.devices

  def get_local_devices(self):
    return [d for d in self.devices if d.manifestation == 'local']

  def get_nonlocal_devices(self):
    return [d for d in self.devices if d.manifestation == 'remote']

  def create_device(self, device_type, infos):
    self.info("creating %s %s", infos['ST'], infos['USN'])
    if infos['ST'] == 'upnp:rootdevice':
      self.info("creating upnp:rootdevice  %s", infos['USN'])
      root = RootDevice(infos)
    else:
      self.info("creating device/service  %s", infos['USN'])
      root_id = infos['USN'][:-len(infos['ST']) - 2]
      root = self.get_device_with_id(root_id)
      # FIXME doesn't look like doing right thing
      device = Device(infos, root)

  def add_device(self, device):
    self.info("adding device %s %s %s", device.get_id(), device.get_usn(), device.friendly_device_type)
    self.devices.append(device)

  def remove_device(self, device_type, infos):
    self.info("removed device %s %s", infos['ST'], infos['USN'])
    device = self.get_device_with_usn(infos['USN'])
    if device:
      louie.send('Coherence.UPnP.Device.removed', None, usn=infos['USN'])
      self.devices.remove(device)
      device.remove()
      if infos['ST'] == 'upnp:rootdevice':
        louie.send('Coherence.UPnP.RootDevice.removed', None, usn=infos['USN'])
        self.callback("removed_device", infos['ST'], infos['USN'])

  def add_web_resource(self, name, sub):
    self.children[name] = sub

  def remove_web_resource(self, name):
    try:
      del self.children[name]
    except KeyError:
      """ probably the backend init failed """
      pass

  @staticmethod
  def connect(receiver, signal=louie.signal.All, sender=louie.sender.Any, weak=True):
    """ wrapper method around louie.connect
    """
    louie.connect(receiver, signal=signal, sender=sender, weak=weak)

  @staticmethod
  def disconnect(receiver, signal=louie.signal.All, sender=louie.sender.Any, weak=True):
    """ wrapper method around louie.disconnect
    """
    louie.disconnect(receiver, signal=signal, sender=sender, weak=weak)
Ejemplo n.º 24
0
class ManagedControlPoint(object):
	DEVICE_TYPE_SATIP_SERVER = "SatIPServer"
	DEVICE_TYPE_DREAMBOX = "Dreambox"
	URI_BASE_DREAMBOX = "urn:dreambox-de:device"

	def __init__(self):
		self.coherence = None
		self._controlPoint = None
		self.__mediaServerClients = {}
		self.__mediaRendererClients = {}
		self.__mediaDevices = {}
		self.__devices = []
		self.onMediaServerDetected = []
		self.onMediaServerRemoved  = []
		self.onMediaRendererDetected = []
		self.onMediaRendererRemoved = []
		self.onMediaDeviceDectected = []
		self.onMediaDeviceRemoved = []
		self.onSatIpServerDetected = []
		self.onSatIpServerRemoved = []
		self.onDreamboxDetected = []
		self.onDreamboxRemoved = []
		self._session = None
		self.__deferredShutDown = None
		self._startPending = False

	def _onShutdownFinished(self, *args, **kwargs):
		self.__deferredShutDown = None
		if self._startPending:
			self.start()

	def start(self):
		def doStart(*args, **kwargs):
			if self._controlPoint:
				Log.w("already running!")
				return
			Log.i("starting now!")
			self._startPending = False
			self.coherence = Coherence({
				'logging': {
					'level' : 'warning', 
					'subsystem' : [
						{'name' : 'msearch', 'level' : 'warning'},
						{'name' : 'ssdp', 'level' : 'warning'}
					]}
				})
			self._controlPoint = ControlPoint(self.coherence, auto_client=['MediaServer','MediaRenderer'])
			self.coherence.ctrl = self._controlPoint
			self.__mediaServerClients = {}
			self.__mediaRendererClients = {}
			self.__mediaDevices = {}
			self.__devices = []
			self._controlPoint.connect(self._onMediaServerDetected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
			self._controlPoint.connect(self._onMediaServerRemoved, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
			self._controlPoint.connect(self._onMediaRendererDetected, 'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
			self._controlPoint.connect(self._onMediaRendererRemoved, 'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
			self._controlPoint.connect(self._onMediaDeviceDectected, 'Coherence.UPnP.Device.detection_completed')
			self._controlPoint.connect(self._onMediaDeviceRemoved, 'Coherence.UPnP.RootDevice.removed')
			self.__deferredShutDown = None
			if self._session:
				self._callPlugins(reason=0)
		if self.__deferredShutDown:
			Log.w("deferring start until shutdown is finished")
			if not self._startPending:
				self._startPending = True
		else:
			doStart()

	def restart(self):
		Log.i()
		if not self.__deferredShutDown:
			self.shutdown()
		self.start()

	def setSession(self, session):
		self._session = session
		if self.coherence:
			self._callPlugins(reason=0)

	def _callPlugins(self, reason=0):
		for plugin in plugins.getPlugins(PluginDescriptor.WHERE_UPNP):
			plugin(reason, session=self._session)

	def _onMediaServerDetected(self, client, udn):
		print "[DLNA] MediaServer Detected: %s (%s)" % (client.device.get_friendly_name(), client.device.get_friendly_device_type())
		self.__mediaServerClients[udn] = client
		for fnc in self.onMediaServerDetected:
			fnc(udn, client)

	def _onMediaServerRemoved(self, udn):
		if self.__mediaServerClients.get(udn, None) != None:
			del self.__mediaServerClients[udn]
			for fnc in self.onMediaServerRemoved:
				fnc(udn)

	def _onMediaRendererDetected(self, client, udn):
		print "[DLNA] MediaRenderer detected: %s (%s, %s)" % (client.device.get_friendly_name(), client.device.get_friendly_device_type(), udn)
		self.__mediaRendererClients[udn] = client
		for fnc in self.onMediaRendererDetected:
			fnc(udn, client)

	def _onMediaRendererRemoved(self, udn):
		print "[DLNA] MediaRenderer removed: %s" % (udn)
		if self.__mediaRendererClients.get(udn, None) != None:
			del self.__mediaRendererClients[udn]
			for fnc in self.onMediaRendererRemoved:
				fnc(udn)

	def _onMediaDeviceDectected(self, device):
		if device.udn in self.__mediaDevices:
			return
		self.__mediaDevices[device.udn] = device
		device_type = device.get_friendly_device_type()
		if device_type == self.DEVICE_TYPE_SATIP_SERVER:
			Log.i("New SAT>IP Server found: %s (%s - %s)" %(device.get_friendly_name(), device.get_friendly_device_type(), device.get_satipcap()))
			for fnc in self.onSatIpServerDetected:
				fnc(device)
		elif device_type == self.DEVICE_TYPE_DREAMBOX:
			Log.i("New Dreambox found: %s (%s - %s)" %(device.get_friendly_name(), device.get_friendly_device_type(), device.get_presentation_url()))
			for fnc in self.onDreamboxDetected:
				fnc(device)
		else:
			Log.i("New Device found: %s (%s)" % (device.get_friendly_name(), device.get_friendly_device_type()))

	def _onMediaDeviceRemoved(self, usn):
		if usn in self.__mediaDevices:
			print "[DLNA] Device removed: %s" % (usn)
			device = self.__mediaDevices[usn]
			device_type = device.get_friendly_device_type()
			if device_type == self.DEVICE_TYPE_SATIP_SERVER:
				for fnc in self.onSatIpServerRemoved:
					fnc(device)
			elif device_type == self.DEVICE_TYPE_DREAMBOX:
				for fnc in self.onDreamboxRemoved:
					fnc(device)
			for fnc in self.onMediaDeviceRemoved:
				fnc(device)
			del self.__mediaDevices[usn]

	def registerRenderer(self, classDef, **kwargs):
		renderer = MediaRenderer(self.coherence, classDef, no_thread_needed=True, **kwargs)
		self.__devices.append(renderer)
		return renderer

	def registerServer(self, classDef, **kwargs):
		server = MediaServer(self.coherence, classDef, no_thread_needed=True, **kwargs)
		self.__devices.append(server)
		return server

	def registerDevice(self, instance, **kwargs):
		self.__devices.append(instance)
		return instance

	def getServerList(self):
		return self.__mediaServerClients.values()

	def getRenderingControlClientList(self):
		return self.__mediaRendererClients.values()

	def getDeviceName(self, client):
		return Item.ue(client.device.get_friendly_name())

	def getSatIPDevices(self):
		devices = []
		for device in self.__mediaDevices.itervalues():
			if device.get_friendly_device_type() == self.DEVICE_TYPE_SATIP_SERVER:
				devices.append(device)
		return devices

	def getDreamboxes(self):
		devices = []
		for device in self.__mediaDevices.itervalues():
			if device.get_friendly_device_type() == self.DEVICE_TYPE_DREAMBOX:
				devices.append(device)
		return devices

	def getDevice(self, uuid):
		for device in self.__devices:
			if device.uuid == uuid:
				return device
		return None

	def removeDevice(self, uuid):
		device = self.getDevice(uuid)
		if device:
			device.unregister()
			self.__devices.remove(device)
			return True
		return False

	def shutdown(self):
		Log.i("%s" %(self.coherence,))
		if True:
			Log.w("shutdown is broken... will continue running. please restart enigma2 instead!")
			return
		if self.coherence:
			self._callPlugins(reason=1)
			self.__mediaServerClients = {}
			self.__mediaRendererClients = {}
			self.__mediaDevices = {}
			self.__devices = []
			self.__deferredShutDown = self.coherence.shutdown(force=True)
			self.__deferredShutDown.addCallback(self._onShutdownFinished)
			self._controlPoint.disconnect(self._onMediaServerDetected, 'Coherence.UPnP.ControlPoint.MediaServer.detected')
			self._controlPoint.disconnect(self._onMediaServerRemoved, 'Coherence.UPnP.ControlPoint.MediaServer.removed')
			self._controlPoint.disconnect(self._onMediaRendererDetected, 'Coherence.UPnP.ControlPoint.MediaRenderer.detected')
			self._controlPoint.disconnect(self._onMediaRendererRemoved, 'Coherence.UPnP.ControlPoint.MediaRenderer.removed')
			self._controlPoint.disconnect(self._onMediaDeviceDectected, 'Coherence.UPnP.Device.detection_completed')
			self._controlPoint.disconnect(self._onMediaDeviceRemoved, 'Coherence.UPnP.RootDevice.removed')
			self.coherence = None
			self._controlPoint = None
Ejemplo n.º 25
0
class Coherence(EventDispatcher, log.LogAble):
    '''
    The Main class of the Cohen3 project. The Coherence class controls all the
    servers initialization depending on the configuration passed.
    It is also capable of initialize the plugins defined in config variable or
    by configuration file.
    It supports the creation of multiple servers at once.

    **Example of a simple server via plugin AppleTrailersStore**::

        from coherence.base import Coherence
        from coherence.upnp.core.uuid import UUID
        from twisted.internet import reactor
        new_uuid = UUID()

        coherence = Coherence(
            {'logmode': 'info',
             'controlpoint': 'yes',
             'plugin': [{'backend': 'AppleTrailersStore',
                        'name': 'Cohen3 Example FSStore',
                        'uuid': new_uuid,
                        }
                        ]
             }
        )
        reactor.run()

    .. versionchanged:: 0.9.0

        * Introduced inheritance from EventDispatcher
        * The emitted events changed:

            - Coherence.UPnP.Device.detection_completed =>
              coherence_device_detection_completed
            - Coherence.UPnP.Device.removed => coherence_device_removed
            - Coherence.UPnP.RootDevice.removed =>
              coherence_root_device_removed

        * Changed some variables to benefit from the EventDispatcher's
          properties:

            - :attr:`devices`
            - :attr:`children`
            - :attr:`_callbacks`
            - :attr:`active_backends`
            - :attr:`ctrl`
            - :attr:`dbus`
            - :attr:`json`
            - :attr:`msearch`
            - :attr:`ssdp_server`
            - :attr:`transcoder_manager`
            - :attr:`web_server`
    '''

    __instance = None  # Singleton
    __initialized = False
    __incarnations = 0
    __cls = None

    logCategory = 'coherence'

    devices = ListProperty([])
    '''A list of the added devices.'''
    children = DictProperty({})
    '''A dict containing the web resources.'''
    _callbacks = DictProperty({})
    '''A dict containing the callbacks, used by the methods :meth:`subscribe`
    and :meth:`unsubscribe`.'''
    active_backends = DictProperty({})
    '''A dict containing the active backends.'''

    # Services/Devices
    ctrl = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.upnp.devices.control_point.ControlPoint`. This will be
    enabled if we request it by config dict or configuration file via
    keyword *controlpoint = yes*.'''
    dbus = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.dbus_service.DBusPontoon`. This will be
    enabled if we request it by config dict or configuration file via
    keyword *use_dbus = yes*.'''
    json = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.json_service.JsonInterface`. This will be
    enabled if we request it by config dict or configuration file via
    keyword *json = yes*.'''
    msearch = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.upnp.core.msearch.MSearch`. This is automatically
    enabled when :class:`Coherence` is initialized'''
    ssdp_server = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.upnp.core.ssdp.SSDPServer`. This is automatically
    enabled when :class:`Coherence` is initialized'''
    transcoder_manager = Property(None)
    '''A coherence's instance of class
    :class:`~coherence.transcoder.TranscoderManager`. This will be
    enabled if we request itby config dict or configuration file via
    keyword *transcoding = yes*.'''
    web_server = Property(None)
    '''A coherence's instance of class
    :class:`WebServer` or :class:`WebServerUi`. We can request our preference
    by config dict or configuration file. If we use the keyword *web-ui = yes*,
    then the class :class:`WebServerUi` will be used, otherwise, the enabled
    web server will be of class :class:`WebServer`.'''
    def __new__(cls, *args, **kwargs):
        if cls.__instance is None:
            cls.__instance = super(Coherence, cls).__new__(cls)
            cls.__instance.__initialized = False
            cls.__instance.__incarnations = 0
            cls.__instance.__cls = cls
            cls.__instance.config = kwargs.get('config', {})
        cls.__instance.__incarnations += 1
        return cls.__instance

    def __init__(self, config=None):
        # initialize only once
        if self.__initialized:
            return
        self.__initialized = True

        # supers
        log.LogAble.__init__(self)
        EventDispatcher.__init__(self)
        self.register_event(
            'coherence_device_detection_completed',
            'coherence_device_removed',
            'coherence_root_device_removed',
        )

        self.config = config or {}

        self.available_plugins = None

        self.external_address = None
        self.urlbase = None
        self.web_server_port = int(config.get('serverport', 8080))

        self.setup_logger()

        self.setup_hostname()
        if self.hostname.startswith('127.'):
            # use interface detection via routing table as last resort
            def catch_result(hostname):
                self.hostname = hostname
                self.setup_part2()

            d = defer.maybeDeferred(get_host_address)
            d.addCallback(catch_result)
        else:
            self.setup_part2()

    def clear(self):
        '''We do need this to survive multiple calls to Coherence
        during trial tests'''
        self.unbind_all()
        self.__cls.__instance = None

    @property
    def is_unittest(self):
        '''
        Reads config and returns if we are testing or not via `unittest` key.
        '''
        unittest = self.config.get('unittest', 'no')
        return False if unittest in {'no', False, None} else True

    @property
    def log_level(self):
        '''Read config and return the log level.'''
        try:
            log_level = self.config.get('logging').get('level', 'warning')
        except (KeyError, AttributeError):
            log_level = self.config.get('logmode', 'warning')
        return log_level.upper()

    @property
    def log_file(self):
        '''Read config and return the logfile or `None`.'''
        try:
            logfile = self.config.get('logging').get('logfile', None)
            if logfile is not None:
                logfile = str(logfile)
        except (KeyError, AttributeError, TypeError):
            logfile = self.config.get('logfile', None)
        return logfile

    def setup_logger(self):
        '''Initializes log's system based on config.

         .. note:: the COHEN_DEBUG environment variable overwrites all level
                   settings in here
         '''
        try:
            subsystems = self.config.get('logging')['subsystem']
            if isinstance(subsystems, dict):
                subsystems = [subsystems]
            for subsystem in subsystems:
                try:
                    if subsystem['active'] == 'no':
                        continue
                except (KeyError, TypeError):
                    pass
                self.info(f'setting log-level for subsystem ' +
                          f'{subsystem["name"]} to {subsystem["level"]}')
                logging.getLogger(subsystem['name'].lower()).setLevel(
                    subsystem['level'].upper())
        except (KeyError, TypeError):
            subsystem_log = self.config.get('subsystem_log', {})
            for subsystem, level in list(subsystem_log.items()):
                logging.getLogger(subsystem.lower()).setLevel(level.upper())

        log.init(self.log_file, self.log_level)
        self.warning(f'Coherence UPnP framework version {__version__} ' +
                     f'starting [log level: {self.log_level}]...')

    def setup_hostname(self):
        '''
        Configure the `hostname`.

        .. note:: If something goes wrong will default to `127.0.0.1`
        '''
        network_if = self.config.get('interface')
        if network_if:
            self.hostname = get_ip_address(f'{network_if}')
        else:
            try:
                self.hostname = socket.gethostbyname(socket.gethostname())
            except socket.gaierror:
                self.warning('hostname can\'t be resolved, ' +
                             'maybe a system misconfiguration?')
                self.hostname = '127.0.0.1'

        self.info(f'running on host: {self.hostname}')
        if self.hostname.startswith('127.'):
            self.warning(
                f'detection of own ip failed, using {self.hostname} ' +
                f'as own address, functionality will be limited')

    def setup_ssdp_server(self):
        '''Initialize the :class:`~coherence.upnp.core.ssdp.SSDPServer`.'''
        try:
            # TODO: add ip/interface bind
            self.ssdp_server = SSDPServer(test=self.is_unittest)
        except CannotListenError as err:
            self.error(f'Error starting the SSDP-server: {err}')
            self.debug('Error starting the SSDP-server', exc_info=True)
            reactor.stop()
            return

        # maybe some devices are already notified, so we enforce
        # to create the device, if it is not already added...and
        # then we connect the signals for new detections.
        for st, usn in self.ssdp_server.root_devices:
            self.create_device(st, usn)
        self.ssdp_server.bind(new_device=self.create_device)
        self.ssdp_server.bind(removed_device=self.remove_device)

        self.ssdp_server.subscribe('new_device', self.add_device)
        self.ssdp_server.subscribe('removed_device', self.remove_device)

    def setup_web_server(self):
        '''Initialize the web server.'''
        try:
            # TODO: add ip/interface bind
            if self.config.get('web-ui', 'no') != 'yes':
                self.web_server = WebServer(None, self.web_server_port, self)
            else:
                self.web_server = WebServerUi(self.web_server_port,
                                              self,
                                              unittests=self.is_unittest)
        except CannotListenError:
            self.error(
                f'port {self.web_server_port} already in use, aborting!')
            reactor.stop()
            return

        self.urlbase = f'http://{self.hostname}:{self.web_server_port:d}/'
        self.external_address = ':'.join(
            (self.hostname, str(self.web_server_port)))
        # self.renew_service_subscription_loop = \
        #     task.LoopingCall(self.check_devices)
        # self.renew_service_subscription_loop.start(20.0, now=False)

    def setup_plugins(self):
        '''Initialize the plugins.'''
        try:
            plugins = self.config['plugin']
            if isinstance(plugins, dict):
                plugins = [plugins]
        except Exception:
            plugins = None

        if plugins is None:
            plugins = self.config.get('plugins', None)

        if plugins is None:
            self.info('No plugin defined!')
        else:
            if isinstance(plugins, dict):
                for plugin, arguments in list(plugins.items()):
                    try:
                        if not isinstance(arguments, dict):
                            arguments = {}
                        self.add_plugin(plugin, **arguments)
                    except Exception as msg:
                        self.warning(f'Can\'t enable plugin, {plugin}: {msg}!')
                        self.info(traceback.format_exc())
            else:
                for plugin in plugins:
                    try:
                        if plugin['active'] == 'no':
                            continue
                    except (KeyError, TypeError):
                        pass
                    try:
                        backend = plugin['backend']
                        arguments = copy.copy(plugin)
                        del arguments['backend']
                        backend = self.add_plugin(backend, **arguments)
                        if self.writeable_config():
                            if 'uuid' not in plugin:
                                plugin['uuid'] = str(backend.uuid)[5:]
                                self.config.save()
                    except Exception as msg:
                        self.warning(f'Can\'t enable plugin, {plugin}: {msg}!')
                        self.error(traceback.format_exc())

    def setup_part2(self):
        '''Initializes the basic and optional services/devices and the enabled
        plugins (backends).'''
        self.setup_ssdp_server()
        if not self.ssdp_server:
            raise Exception('Unable to initialize an ssdp server')

        self.msearch = MSearch(self.ssdp_server, test=self.is_unittest)

        reactor.addSystemEventTrigger(
            'before',
            'shutdown',
            self.shutdown,
            force=True,
        )

        self.setup_web_server()
        if not self.urlbase:
            raise Exception('Unable to initialize an web server')

        self.setup_plugins()

        # Control Point Initialization
        if (self.config.get('controlpoint', 'no') == 'yes'
                or self.config.get('json', 'no') == 'yes'):
            self.ctrl = ControlPoint(self)

        # Json Interface Initialization
        if self.config.get('json', 'no') == 'yes':
            from coherence.json_service import JsonInterface

            self.json = JsonInterface(self.ctrl)

        # Transcoder Initialization
        if self.config.get('transcoding', 'no') == 'yes':
            from coherence.transcoder import TranscoderManager

            self.transcoder_manager = TranscoderManager(self)

        # DBus Initialization
        if self.config.get('use_dbus', 'no') == 'yes':
            try:
                from coherence import dbus_service

                if self.ctrl is None:
                    self.ctrl = ControlPoint(self)
                self.ctrl.auto_client_append('InternetGatewayDevice')
                self.dbus = dbus_service.DBusPontoon(self.ctrl)
            except Exception as msg:
                self.warning(f'Unable to activate dbus sub-system: {msg}')
                self.debug(traceback.format_exc())

    def add_plugin(self, plugin, **kwargs):
        self.info(f'adding plugin {plugin}')

        self.available_plugins = Plugins()

        # TODO clean up this exception concept
        try:
            plugin_class = self.available_plugins.get(plugin, None)
            if plugin_class is None:
                raise KeyError
            for device in plugin_class.implements:
                try:
                    device_class = globals().get(device, None)
                    if device_class is None:
                        raise KeyError
                    self.info(f'Activating {plugin} plugin as {device}...')
                    new_backend = device_class(self, plugin_class, **kwargs)
                    self.active_backends[str(new_backend.uuid)] = new_backend
                    return new_backend
                except KeyError:
                    self.warning(f'Can\'t enable {plugin} plugin, '
                                 f'sub-system {device} not found!')
                except Exception as e1:
                    self.exception(f'Can\'t enable {plugin} plugin for '
                                   f'sub-system {device} [exception: {e1}]')
                    self.debug(traceback.format_exc())
        except KeyError:
            self.warning(f'Can\'t enable {plugin} plugin, not found!')
        except Exception as e2:
            self.warning(f'Can\'t enable {plugin} plugin, {e2}!')
            self.debug(traceback.format_exc())

    def remove_plugin(self, plugin):
        '''Removes a backend from Coherence

        Args:
            plugin (object): is the object return by add_plugin or
                an UUID string.
        '''
        if isinstance(plugin, str):
            try:
                plugin = self.active_backends[plugin]
            except KeyError:
                self.warning(f'no backend with the uuid {plugin} found')
                return ''

        try:
            del self.active_backends[str(plugin.uuid)]
            self.info(f'removing plugin {plugin}')
            plugin.unregister()
            return plugin.uuid
        except KeyError:
            self.warning(f'no backend with the uuid {plugin.uuid} found')
            return ''

    @staticmethod
    def writeable_config():
        '''Do we have a new-style config file'''
        return False

    def store_plugin_config(self, uuid, items):
        '''Find the backend with uuid and store in its the config the key
        and value pair(s).'''
        plugins = self.config.get('plugin')
        if plugins is None:
            self.warning('storing a plugin config option is only possible'
                         ' with the new config file format')
            return
        if isinstance(plugins, dict):
            plugins = [plugins]
        uuid = str(uuid)
        if uuid.startswith('uuid:'):
            uuid = uuid[5:]
        for plugin in plugins:
            try:
                if plugin['uuid'] == uuid:
                    for k, v in list(items.items()):
                        plugin[k] = v
                    self.config.save()
            except Exception as e:
                self.warning(f'Coherence.store_plugin_config: {e}')
        else:
            self.info(f'storing plugin config option '
                      f'for {uuid} failed, plugin not found')

    def receiver(self, signal, *args, **kwargs):
        pass

    def shutdown(self, force=False):
        if self.__incarnations > 1 and not force:
            self.__incarnations -= 1
            return

        if self.dbus:
            self.dbus.shutdown()
            self.dbus = None

        for backend in self.active_backends.values():
            backend.unregister()
        self.active_backends = {}

        # send service unsubscribe messages
        if self.web_server is not None:
            if hasattr(self.web_server, 'endpoint_listen'):
                if self.web_server.endpoint_listen is not None:
                    self.web_server.endpoint_listen.cancel()
                    self.web_server.endpoint_listen = None
                if self.web_server.endpoint_port is not None:
                    self.web_server.endpoint_port.stopListening()
            if hasattr(self.web_server, 'ws_endpoint_listen'):
                if self.web_server.ws_endpoint_listen is not None:
                    self.web_server.ws_endpoint_listen.cancel()
                    self.web_server.ws_endpoint_listen = None
                if self.web_server.ws_endpoint_port is not None:
                    self.web_server.ws_endpoint_port.stopListening()
        try:
            if hasattr(self.msearch, 'double_discover_loop'):
                self.msearch.double_discover_loop.stop()
            if hasattr(self.msearch, 'port'):
                self.msearch.port.stopListening()
            if hasattr(self.ssdp_server, 'resend_notify_loop'):
                self.ssdp_server.resend_notify_loop.stop()
            if hasattr(self.ssdp_server, 'port'):
                self.ssdp_server.port.stopListening()
            # self.renew_service_subscription_loop.stop()
        except Exception:
            pass

        dev_l = []
        for root_device in self.get_devices():
            if hasattr(root_device, 'root_device_detection_completed'):
                root_device.unbind(
                    root_device_detection_completed=self.add_device)
            for device in root_device.get_devices():
                dd = device.unsubscribe_service_subscriptions()
                dd.addCallback(device.remove)
                dev_l.append(dd)
            rd = root_device.unsubscribe_service_subscriptions()
            rd.addCallback(root_device.remove)
            dev_l.append(rd)

        def homecleanup(result):
            # cleans up anything left over
            self.ssdp_server.unbind(new_device=self.create_device)
            self.ssdp_server.unbind(removed_device=self.remove_device)
            self.ssdp_server.shutdown()
            if self.ctrl:
                self.ctrl.shutdown()
            self.warning('Coherence UPnP framework shutdown')
            return result

        dl = defer.DeferredList(dev_l)
        dl.addCallback(homecleanup)
        return dl

    def check_devices(self):
        '''Iterate over devices and their embedded ones and renew
        subscriptions.'''
        for root_device in self.get_devices():
            root_device.renew_service_subscriptions()
            for device in root_device.get_devices():
                device.renew_service_subscriptions()

    def subscribe(self, name, callback):
        self._callbacks.setdefault(name, []).append(callback)

    def unsubscribe(self, name, callback):
        callbacks = self._callbacks.get(name, [])
        if callback in callbacks:
            callbacks.remove(callback)
        self._callbacks[name] = callbacks

    def callback(self, name, *args):
        for callback in self._callbacks.get(name, []):
            callback(*args)

    def get_device_by_host(self, host):
        found = []
        for device in self.devices:
            if device.get_host() == host:
                found.append(device)
        return found

    def get_device_with_usn(self, usn):
        found = None
        for device in self.devices:
            if device.get_usn() == usn:
                found = device
                break
        return found

    def get_device_with_id(self, device_id):
        # print(f'get_device_with_id [{type(device_id)}]: {device_id}')
        found = None
        for device in self.devices:
            id = device.get_id()
            if device_id[:5] != 'uuid:':
                id = id[5:]
            if id == device_id:
                found = device
                break
        return found

    def get_devices(self):
        # print(f'get_devices: {self.devices}')
        return self.devices

    def get_local_devices(self):
        # print(f'get_local_devices: '
        #       f'{[d for d in self.devices if d.manifestation == "local"]}')
        return [d for d in self.devices if d.manifestation == 'local']

    def get_nonlocal_devices(self):
        # print(f'get_nonlocal_devices: '
        #       f'{[d for d in self.devices if d.manifestation == "remote"]}')
        return [d for d in self.devices if d.manifestation == 'remote']

    def is_device_added(self, infos):
        '''
        Check if the device exists in our list of created :attr:`devices`.

        Args:
            infos (dict): Information about the device

        Returns:
            True if the device exists in our list of :attr:`devices`,
            otherwise, returns False.

        .. versionadded:: 0.9.0
        '''
        for d in self.devices:
            if d.st == infos['ST'] and d.usn == infos['USN']:
                return True
        return False

    def create_device(self, device_type, infos):
        if self.is_device_added(infos):
            self.warning(
                f'No need to create the device, we already added device: '
                f'{infos["ST"]} with usn {infos["USN"]}...!!')
            return
        self.info(f'creating {infos["ST"]} {infos["USN"]}')
        if infos['ST'] == 'upnp:rootdevice':
            self.info(f'creating upnp:rootdevice  {infos["USN"]}')
            root = RootDevice(infos)
            root.bind(root_detection_completed=self.add_device)
        else:
            self.info(f'creating device/service  {infos["USN"]}')
            root_id = infos['USN'][:-len(infos['ST']) - 2]
            root = self.get_device_with_id(root_id)
            # TODO: must check that this is working as expected
            device = Device(root, udn=infos['UDN'])

    def add_device(self, device, *args):
        self.info(f'adding device {device.get_id()} {device.get_usn()} ' +
                  f'{device.friendly_device_type}')
        self.devices.append(device)
        self.dispatch_event('coherence_device_detection_completed',
                            device=device)

    def remove_device(self, device_type, infos):
        self.info(f'removed device {infos["ST"]} {infos["USN"]}')
        device = self.get_device_with_usn(infos['USN'])
        if device:
            self.dispatch_event('coherence_device_removed', infos['USN'],
                                device.client)
            self.devices.remove(device)
            device.remove()
            if infos['ST'] == 'upnp:rootdevice':
                self.dispatch_event(
                    'coherence_root_device_removed',
                    infos['USN'],
                    device.client,
                )
                self.callback('removed_device', infos['ST'], infos['USN'])

    def add_web_resource(self, name, sub):
        self.children[name] = sub

    def remove_web_resource(self, name):
        try:
            del self.children[name]
        except KeyError:
            ''' probably the backend init failed '''
            pass

    @staticmethod
    def check_louie(receiver, signal, method='connect'):
        '''
        Check if the connect or disconnect method's arguments are valid in
        order to automatically convert to EventDispatcher's bind
        The old valid signals are:

            - Coherence.UPnP.Device.detection_completed
            - Coherence.UPnP.RootDevice.detection_completed
            - Coherence.UPnP.Device.removed
            - Coherence.UPnP.RootDevice.removed

        .. versionadded:: 0.9.0
        '''
        if not callable(receiver):
            raise Exception('The receiver should be callable in order to use' +
                            ' the method {method}')
        if not signal:
            raise Exception(
                f'We need a signal in order to use method {method}')
        if not (signal.startswith('Coherence.UPnP.Device.')
                or signal.startswith('Coherence.UPnP.RootDevice.')):
            raise Exception(
                'We need a signal an old signal starting with: ' +
                '"Coherence.UPnP.Device." or "Coherence.UPnP.RootDevice."')

    def connect(self, receiver, signal=None, sender=None, weak=True):
        '''
        Wrapper method around the deprecated method louie.connect. It will
        check if the passed signal is supported by executing the method
        :meth:`check_louie`.

        .. warning:: This will probably be removed at some point, if you use
                     the connect method you should migrate to the new event
                     system EventDispatcher.

        .. versionchanged:: 0.9.0
            Added EventDispatcher's compatibility for some basic signals
        '''
        self.check_louie(receiver, signal, 'connect')
        if signal.endswith('.detection_completed'):
            self.bind(coherence_device_detection_completed=receiver)
        elif signal.endswith('.Device.removed'):
            self.bind(coherence_device_removed=receiver)
        elif signal.endswith('.RootDevice.removed'):
            self.bind(coherence_root_device_removed=receiver)
        else:
            raise Exception(
                f'Unknown signal {signal}, we cannot bind that signal.')

    def disconnect(self, receiver, signal=None, sender=None, weak=True):
        '''
        Wrapper method around the deprecated method louie.disconnect. It will
        check if the passed signal is supported by executing the method
        :meth:`check_louie`.

        .. warning:: This will probably be removed at some point, if you use
                     the disconnect method you should migrate to the new event
                     system EventDispatcher.

        .. versionchanged:: 0.9.0
            Added EventDispatcher's compatibility for some basic signals
        '''
        self.check_louie(receiver, signal, 'disconnect')
        if signal.endswith('.detected'):
            self.unbind(coherence_device_detection_completed=receiver)
        elif signal.endswith('.removed'):
            self.unbind(control_point_client_removed=receiver)
        else:
            raise Exception(
                f'Unknown signal {signal}, we cannot unbind that signal.')
Ejemplo n.º 26
0
    def setup_part2(self):
        '''Initializes the basic and optional services/devices and the enabled
        plugins (backends).'''
        self.info(f'running on host: {self.hostname}')
        if self.hostname.startswith('127.'):
            self.warning(f'detection of own ip failed, using {self.hostname} '
                         f'as own address, functionality will be limited')

        unittest = self.config.get('unittest', 'no')
        unittest = False if unittest == 'no' else True

        try:
            # TODO: add ip/interface bind
            self.ssdp_server = SSDPServer(test=unittest)
        except CannotListenError as err:
            self.error(f'Error starting the SSDP-server: {err}')
            self.debug('Error starting the SSDP-server', exc_info=True)
            reactor.stop()
            return

        # maybe some devices are already notified, so we enforce
        # to create the device, if it is not already added...and
        # then we connect the signals for new detections.
        for st, usn in self.ssdp_server.root_devices:
            self.create_device(st, usn)
        self.ssdp_server.bind(new_device=self.create_device)
        self.ssdp_server.bind(removed_device=self.remove_device)

        self.ssdp_server.subscribe('new_device', self.add_device)
        self.ssdp_server.subscribe('removed_device', self.remove_device)

        self.msearch = MSearch(self.ssdp_server, test=unittest)

        reactor.addSystemEventTrigger('before',
                                      'shutdown',
                                      self.shutdown,
                                      force=True)

        # Web Server Initialization
        try:
            # TODO: add ip/interface bind
            if self.config.get('web-ui', 'no') != 'yes':
                self.web_server = WebServer(None, self.web_server_port, self)
            else:
                self.web_server = WebServerUi(self.web_server_port,
                                              self,
                                              unittests=unittest)
        except CannotListenError:
            self.error(
                f'port {self.web_server_port} already in use, aborting!')
            reactor.stop()
            return

        self.urlbase = f'http://{self.hostname}:{self.web_server_port:d}/'
        # self.renew_service_subscription_loop = \
        #     task.LoopingCall(self.check_devices)
        # self.renew_service_subscription_loop.start(20.0, now=False)

        # Plugins Initialization
        try:
            plugins = self.config['plugin']
            if isinstance(plugins, dict):
                plugins = [plugins]
        except Exception:
            plugins = None

        if plugins is None:
            plugins = self.config.get('plugins', None)

        if plugins is None:
            self.info('No plugin defined!')
        else:
            if isinstance(plugins, dict):
                for plugin, arguments in list(plugins.items()):
                    try:
                        if not isinstance(arguments, dict):
                            arguments = {}
                        self.add_plugin(plugin, **arguments)
                    except Exception as msg:
                        self.warning(f'Can\'t enable plugin, {plugin}: {msg}!')
                        self.info(traceback.format_exc())
            else:
                for plugin in plugins:
                    try:
                        if plugin['active'] == 'no':
                            continue
                    except (KeyError, TypeError):
                        pass
                    try:
                        backend = plugin['backend']
                        arguments = copy.copy(plugin)
                        del arguments['backend']
                        backend = self.add_plugin(backend, **arguments)
                        if self.writeable_config():
                            if 'uuid' not in plugin:
                                plugin['uuid'] = str(backend.uuid)[5:]
                                self.config.save()
                    except Exception as msg:
                        self.warning(f'Can\'t enable plugin, {plugin}: {msg}!')
                        self.info(traceback.format_exc())

        self.external_address = ':'.join(
            (self.hostname, str(self.web_server_port)))

        # Control Point Initialization
        if self.config.get('controlpoint', 'no') == 'yes' or self.config.get(
                'json', 'no') == 'yes':
            self.ctrl = ControlPoint(self)

        # Json Interface Initialization
        if self.config.get('json', 'no') == 'yes':
            from coherence.json_service import JsonInterface
            self.json = JsonInterface(self.ctrl)

        # Transcoder Initialization
        if self.config.get('transcoding', 'no') == 'yes':
            from coherence.transcoder import TranscoderManager
            self.transcoder_manager = TranscoderManager(self)

        # DBus Initialization
        if self.config.get('use_dbus', 'no') == 'yes':
            try:
                from coherence import dbus_service
                if self.ctrl is None:
                    self.ctrl = ControlPoint(self)
                self.ctrl.auto_client_append('InternetGatewayDevice')
                self.dbus = dbus_service.DBusPontoon(self.ctrl)
            except Exception as msg:
                self.warning(f'Unable to activate dbus sub-system: {msg}')
                self.debug(traceback.format_exc())