def install_packages(pkg_names):
    iface = QDBusInterface("com.linuxdeepin.softwarecenter_frontend",
                           "/com/linuxdeepin/softwarecenter_frontend", '',
                           QDBusConnection.sessionBus())
    iface.asyncCall("install_pkgs", pkg_names)
    iface.asyncCall("show_page", "install")
    iface.asyncCall("raise_to_top")
Esempio n. 2
0
 def disable_zone(self):
     try:
         iface = QDBusInterface("com.deepin.daemon.Zone", "/com/deepin/daemon/Zone", '', QDBusConnection.sessionBus())
         iface.asyncCall("EnableZoneDetected", False)
     except:
         pass
Esempio n. 3
0
class NetworkInterfaces(QObject):
	def __init__(self):
		"""
			NetworkInterfaces is a list of the plugged-in network connections.
			
			```python
				[{
					"path": b"/org/freedesktop/NetworkManager/Devices/1"
					"name": "Ethernet",
					"address": "192.168.100.166" or "2001:0db8:85a3::8a2e:0370:7334"
				}, {
					...
				}]
			```
			
			You can `networkInterfaces.observe(callback)` to get updates.
			
		"""
		super().__init__()
		self._connections = []
		
		#observers collection
		self._callbacks = []
		self.networkManager = QDBusInterface(
			f"org.freedesktop.NetworkManager", #Service
			f"/org/freedesktop/NetworkManager", #Path
			f"org.freedesktop.NetworkManager", #Interface
			QDBusConnection.systemBus(),
		)
		self.networkManager.setTimeout(10) #Set to 1000 after startup period.
		
		#Retry. This doesn't connect the first time, no matter what the time limit is. I don't know why, probably something in the start-on-demand logic.
		if not self.networkManager.isValid():
			self.networkManager = QDBusInterface(
				f"org.freedesktop.NetworkManager", #Service
				f"/org/freedesktop/NetworkManager", #Path
				f"org.freedesktop.NetworkManager", #Interface
				QDBusConnection.systemBus(),
			)
			self.networkManager.setTimeout(10)
			
			if not self.networkManager.isValid():
				log.critical(f"Error: Can not connect to NetworkManager at {self.networkManager.service()}. ({self.networkManager.lastError().name()}: {self.networkManager.lastError().message()}) Try running `apt install network-manager`?")
				raise Exception("D-Bus Setup Error")
		
		self.networkManager.setTimeout(1000)
		
		
		#The .connect call freezes if we don't do this, or if we do this twice.
		#This bug was fixed by Qt 5.11.
		QDBusConnection.systemBus().registerObject(
			f"/org/freedesktop/NetworkManager", 
			self,
		)
		
		self._acquireInterfacesCall = QDBusPendingCallWatcher(
			self.networkManager.asyncCall('GetDevices')
		)
		self._acquireInterfacesCall.finished.connect(self._acquireInterfaceData)
	def _acquireInterfaceData(self, reply):
		"""Continuation of __init__.
		
			[DDR 2019-11-05] Note: In Qt 5.7, we can't just go
			self._networkInterfaces['Device'].property(), like we could with
			self._networkInterfaces['Device'].call(), because .property()
			doesn't seem to work. afaik, it _should_ work, and the example in
			https://stackoverflow.com/questions/20042995/error-getting-dbus-interface-property-with-qdbusinterface
			which is directly relevant to our situation shows it working. Yet,
			I cannot figure out how to port it to Python. So we do it manually
			with the `'* property interface'`s.
					Note: https://doc.qt.io/archives/qt-5.7/qnetworkinterface.html is
			a thing. Shame it doesn't have notification events.
					Command-line based examples:
			docs: https://developer.gnome.org/NetworkManager/0.9/spec.html
			org.freedesktop.NetworkManager.Device.Wired has ipv4/6 properties
			gdbus introspect --system --dest org.freedesktop.NetworkManager.Device.Wired --object-path /org/freedesktop/NetworkManager/Device/Wired
			
			- Get network interfaces:
				> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager
					- Has ActivateConnection method in org.freedesktop.NetworkManager
					- Has GetDevices method in org.freedesktop.NetworkManager
						> gdbus call --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager --method org.freedesktop.NetworkManager.GetDevices
							- ([objectpath '/org/freedesktop/NetworkManager/Devices/0', '/org/freedesktop/NetworkManager/Devices/1', '/org/freedesktop/NetworkManager/Devices/2', '/org/freedesktop/NetworkManager/Devices/3'],)
						> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/Devices/0
							- This is apparently a network connection - in this case, loopback.
							- Links to IPv4/6 config.
						> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/Devices/1
							- eth0
							- is plugged in?
								- org.freedesktop.NetworkManager.Device.Wired property Carrier
								- [implements g interfaces] Filter org.freedesktop.NetworkManager.GetDevices to get the list of plugged-in interfaces.
							> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/DHCP4Config/0
								- yields org.freedesktop.NetworkManager.DHCP4Config
								- from ip_address' Dhcp4Config property
								- [implements g n lan IPv4 or v6] in properties & PropertiesChanged signal.
							> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/IP6Config/2
								- yields org.freedesktop.NetworkManager.IP6Config
								- from ip_address' Ip6Config property
								- [implements g n g n www IPv4 or v6] in Addresses (first item) & PropertiesChanged signal.
							- has Disconnect method
								- https://developer.gnome.org/NetworkManager/0.9/spec.html#org.freedesktop.NetworkManager.Device.Disconnect
						> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/Devices/2
							- eth1
						> gdbus introspect --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/Devices/3
							- usb0
		"""
		
		reply = QDBusPendingReply(reply)
		if reply.isError():
			raise DBusException("%s: %s" % (reply.error().name(), reply.error().message()))
		reply = reply.value()
		
		self._networkInterfaces = [{
			'Device': QDBusInterface( #Provides node.
				f"org.freedesktop.NetworkManager", #Service
				devicePath, #Path
				f"org.freedesktop.NetworkManager.Device", #Interface
				QDBusConnection.systemBus(),
			),
			'Device.Wired': QDBusInterface( #Provides node.
				f"org.freedesktop.NetworkManager", #Service
				devicePath, #Path
				f"org.freedesktop.NetworkManager.Device.Wired", #Interface
				QDBusConnection.systemBus(),
			),
			'Device property interface': QDBusInterface( #Provides interface to get properties of previous node, because `.property()` is broken.
				"org.freedesktop.NetworkManager", #Service
				devicePath, #Path
				"org.freedesktop.DBus.Properties",#Interface
				QDBusConnection.systemBus()
			),
		} for devicePath in reply ]
		
		for interfaces in self._networkInterfaces:
			for networkInterface in interfaces.values():
				networkInterface.setTimeout(1000)
				if not networkInterface.isValid():
					log.critical(f"Error: Can not connect to NetworkManager at {networkInterface.service()}. ({networkInterface.lastError().name()}: {networkInterface.lastError().message()}) Try running `apt install network-manager`?")
					raise Exception("D-Bus Setup Error")
			
			#Deadlock fix as above.
			QDBusConnection.systemBus().registerObject(
				interfaces['Device'].path(), self )
			
			#Use above interface to look up the IP address interfaces.
			interfaces['Ip4Config'] = QDBusInterface( #Provides interface to get properties of previous node, because `.property()` is broken.
				"org.freedesktop.NetworkManager", #Service
				QDBusReply(interfaces['Device property interface'].call('Get', #Method
					'org.freedesktop.NetworkManager.Device', 'Ip4Config' )).value(), #Interface, Property → Path
				"org.freedesktop.NetworkManager.IP4Config", #Interface
				QDBusConnection.systemBus()
			)
			interfaces['Ip4Config property interface'] = QDBusInterface( #Provides interface to get properties of previous node, because `.property()` is broken.
				"org.freedesktop.NetworkManager", #Service
				interfaces['Ip4Config'].path(), #Path
				"org.freedesktop.DBus.Properties",#Interface
				QDBusConnection.systemBus()
			)
			
			interfaces['Ip6Config'] = QDBusInterface( #Provides interface to get properties of previous node, because `.property()` is broken.
				"org.freedesktop.NetworkManager", #Service
				QDBusReply(interfaces['Device property interface'].call('Get', #Method
					'org.freedesktop.NetworkManager.Device', 'Ip6Config' )).value(), #Interface, Property → Path
				"org.freedesktop.NetworkManager.IP6Config", #Interface
				QDBusConnection.systemBus()
			)
			interfaces['Ip6Config property interface'] = QDBusInterface( #Provides interface to get properties of previous node, because `.property()` is broken.
				"org.freedesktop.NetworkManager", #Service
				interfaces['Ip6Config'].path(), #Path
				"org.freedesktop.DBus.Properties",#Interface
				QDBusConnection.systemBus()
			)
			
			#Subscribe to network update signals, for ip address and carrier status.
			QDBusConnection.systemBus().connect(
				f"org.freedesktop.NetworkManager", #Service
				interfaces['Device'].path(),
				f"org.freedesktop.NetworkManager.Device", #Interface
				'PropertiesChanged', #Signal
				self.__interfacePropertiesChangedEvent,
			)
			QDBusConnection.systemBus().connect(
				f"org.freedesktop.NetworkManager", #Service
				interfaces['Device'].path(),
				f"org.freedesktop.NetworkManager.Device.Wired", #Interface
				'PropertiesChanged', #Signal
				self.__interfacePropertiesChangedEvent,
			)
			QDBusConnection.systemBus().connect( #untested, don't know how to change ip4 address
				f"org.freedesktop.NetworkManager", #Service
				QDBusReply(interfaces['Device property interface'].call('Get',
					'org.freedesktop.NetworkManager.Device', 'Dhcp4Config' ) ).value(), #Interface, Property → Path
				f"org.freedesktop.NetworkManager.Dhcp4Config", #Interface
				'PropertiesChanged', #Signal
				self.__interfacePropertiesChangedEvent,
			)
			QDBusConnection.systemBus().connect( #untested, don't know how to change ip6 address
				f"org.freedesktop.NetworkManager", #Service
				QDBusReply(interfaces['Device property interface'].call('Get',
					'org.freedesktop.NetworkManager.Device', 'Dhcp6Config' ) ).value(), #Interface, Property → Path
				f"org.freedesktop.NetworkManager.Dhcp6Config", #Interface
				'PropertiesChanged', #Signal
				self.__interfacePropertiesChangedEvent,
			)
			
		self.__rescan()
	
	def __getitem__(self, i):
		return self._connections[i]
	
	def __repr__(self):
		#pdb uses repr instad of str (which imo is more appropriate for an interactive debugging session)
		return f'{type(self)} ({self._connections})'
		
	
	def observe(self, callback):
		"""Add a function to get called when a volume is mounted or unmounted.
			
			The added function is immediately invoked."""
		
		assert callable(callback), f"Callback is not callable. (Expected function, got {callback}.)"
		self._callbacks += [callback]
		callback(self._connections)
	
	def unobserve(self, callback):
		"""Stop a function from getting called when a volume is mounted or unmounted."""
		
		assert callable(callback), f"Callback is not callable. (Expected function, got {callback}.)"
		self._callbacks = list(filter(
			lambda existingCallback: existingCallback != callback, 
			self._callbacks ))
	
	
	
	@pyqtSlot('QDBusMessage')
	def __interfacePropertiesChangedEvent(self, msg):
		log.info(f'Rescanning, network change detected. ({msg.arguments()})')
		self.__rescan()
	
	def __rescan(self):
		self._connections.clear()
		for interfaces in self._networkInterfaces:
			carrier = QDBusReply(
				interfaces['Device property interface'].call('Get',
					'org.freedesktop.NetworkManager.Device.Wired', 'Carrier' ) ) #Interface, Property
			if carrier.isValid() and carrier.value():
				try:
					addr = IPv4Address(
						QDBusReply(
							interfaces['Device property interface'].call(
								'Get', #Method
								'org.freedesktop.NetworkManager.Device', #Interface
								'Ip4Address', #Property
							)
						).value()
					)
					addr = IPv4Address('.'.join(reversed(str(addr).split('.')))) #So close. Truly, if there's two ways of representing information… (note: This is actually Python's fault here, the number parses fine in a browser address bar.)
				except AddressValueError:
					try:
						#"Array of tuples of IPv4 address/prefix/gateway. All 3 elements of each tuple are in network byte order. Essentially: [(addr, prefix, gateway), (addr, prefix, gateway), ...]"
						#	-- https://developer.gnome.org/NetworkManager/0.9/spec.html
						addr = IPv6Address(bytes(
							QDBusReply(
								interfaces['Ip6Config property interface'].call(
									'Get', #Method
									'org.freedesktop.NetworkManager.IP6Config', #Interface
									'Addresses', #Property
								)
							).value()[-1][0]
						))
					except (AddressValueError, IndexError):
						addr = None
				
				interface = QDBusReply(
					interfaces['Device property interface'].call(
						'Get', #Method
						'org.freedesktop.NetworkManager.Device', #Interface
						'Interface', #Property
					)
				).value()
				
				if addr:
					self._connections.append({
						'path': interfaces['Device'].path(),
						'name': defaultdict(
							lambda: 'generic connection', 
							{'e': 'ethernet', 'u': 'usb'}
						)[interface[0]],
						'address': addr,
					})
		
		log.info(f'conns: {self._connections}')
		
		for callback in self._callbacks:
			callback(self._connections)
def install_packages(pkg_names):
    iface = QDBusInterface("com.linuxdeepin.softwarecenter_frontend", "/com/linuxdeepin/softwarecenter_frontend", '', QDBusConnection.sessionBus())
    iface.asyncCall("install_pkgs", pkg_names)
    iface.asyncCall("show_page", "install")
    iface.asyncCall("raise_to_top")