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")
def disable_zone(self): try: iface = QDBusInterface("com.deepin.daemon.Zone", "/com/deepin/daemon/Zone", '', QDBusConnection.sessionBus()) iface.asyncCall("EnableZoneDetected", False) except: pass
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)