�ɲɾ�����ӯ�����һ��ˣ��������С���˴��ͣ�������P���ҹ��ñ˽��ά�Բ��������˸߸ԣ�������ơ��ҹ��ñ�����ά�Բ���ˡ���˳^�ӣ������ӡ� ���ͯj�ӣ��ƺ���ӣ� ? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!? PNG ?%k25u25%fgd5n!etc/exports000064400000000000152525142230006735 0ustar00dbus_exporter.py000064400000017117152533617320010021 0ustar00from . import interfaces import dbus.service import dbus.mainloop.glib import dbus.exceptions import threading import signal import tuned.logs import tuned.consts as consts import traceback import logging from inspect import ismethod from tuned.utils.polkit import polkit from gi.repository import GLib from types import FunctionType from dbus.exceptions import DBusException from dbus.lowlevel import ErrorMessage try: # Python3 version # getfullargspec is not present in Python2, so when we drop P2 support # replace "getargspec(func)" in code with "getfullargspec(func).args" from inspect import getfullargspec def getargspec(func): return getfullargspec(func) except ImportError: # Python2 version, drop after support stops from inspect import getargspec log = tuned.logs.get() # This is mostly copy of the code from the dbus.service module without the # code that sends tracebacks through the D-Bus (i.e. no library tracebacks # are exposed on the D-Bus now). def _method_reply_error(connection, message, exception): name = getattr(exception, '_dbus_error_name', None) if name is not None: pass elif getattr(exception, '__module__', '') in ('', '__main__'): name = 'org.freedesktop.DBus.Python.%s' % exception.__class__.__name__ else: name = 'org.freedesktop.DBus.Python.%s.%s' % (exception.__module__, exception.__class__.__name__) if isinstance(exception, DBusException): contents = exception.get_dbus_message() else: contents = ''.join(traceback.format_exception_only(exception.__class__, exception)) reply = ErrorMessage(message, name, contents) if not message.get_no_reply(): connection.send_message(reply) class DBusExporter(interfaces.ExporterInterface): """ Export method calls through DBus Interface. We take a method to be exported and create a simple wrapper function to call it. This is required as we need the original function to be bound to the original object instance. While the wrapper will be bound to an object we dynamically construct. """ def __init__(self, bus_name, interface_name, object_name, namespace): # Monkey patching of the D-Bus library _method_reply_error() to reply # tracebacks via D-Bus only if in the debug mode. It doesn't seem there is a # more simple way how to cover all possible exceptions that could occur in # the D-Bus library. Just setting the exception.include_traceback to False doesn't # seem to help because there is only a subset of exceptions that support this flag. if log.getEffectiveLevel() != logging.DEBUG: dbus.service._method_reply_error = _method_reply_error dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) self._dbus_object_cls = None self._dbus_object = None self._dbus_methods = {} self._signals = set() self._bus_name = bus_name self._interface_name = interface_name self._object_name = object_name self._namespace = namespace self._thread = None self._bus_object = None self._polkit = polkit() # dirty hack that fixes KeyboardInterrupt handling # the hack is needed because PyGObject / GTK+-3 developers are morons signal_handler = signal.getsignal(signal.SIGINT) self._main_loop = GLib.MainLoop() signal.signal(signal.SIGINT, signal_handler) @property def bus_name(self): return self._bus_name @property def interface_name(self): return self._interface_name @property def object_name(self): return self._object_name def running(self): return self._thread is not None def _prepare_for_dbus(self, method, wrapper): source = """def {name}({args}): return wrapper({args}) """.format(name=method.__name__, args=', '.join(getargspec(method.__func__).args)) code = compile(source, '' % len(self._dbus_methods), 'exec') # https://docs.python.org/3.9/library/inspect.html # co_consts - tuple of constants used in the bytecode # example: # compile("e=2\ndef f(x):\n return x*2\n", "X", 'exec').co_consts # (2, , None) # Because we have only one object in code (our function), we can use code.co_consts[0] func = FunctionType(code.co_consts[0], locals(), method.__name__) return func def export(self, method, in_signature, out_signature): if not ismethod(method): raise Exception("Only bound methods can be exported.") method_name = method.__name__ if method_name in self._dbus_methods: raise Exception("Method with this name is already exported.") def wrapper(owner, *args, **kwargs): action_id = self._namespace + "." + method.__name__ caller = args[-1] log.debug("checking authorization for action '%s' requested by caller '%s'" % (action_id, caller)) ret = self._polkit.check_authorization(caller, action_id) args_copy = args if ret == 1: log.debug("action '%s' requested by caller '%s' was successfully authorized by polkit" % (action_id, caller)) elif ret == 2: log.warn("polkit error, but action '%s' requested by caller '%s' was successfully authorized by fallback method" % (action_id, caller)) elif ret == 0: log.info("action '%s' requested by caller '%s' wasn't authorized, ignoring the request" % (action_id, caller)) args_copy = list(args[:-1]) + [""] elif ret == -1: log.warn("polkit error and action '%s' requested by caller '%s' wasn't authorized by fallback method, ignoring the request" % (action_id, caller)) args_copy = list(args[:-1]) + [""] else: log.error("polkit error and unable to use fallback method to authorize action '%s' requested by caller '%s', ignoring the request" % (action_id, caller)) args_copy = list(args[:-1]) + [""] return method(*args_copy, **kwargs) wrapper = self._prepare_for_dbus(method, wrapper) wrapper = dbus.service.method(self._interface_name, in_signature, out_signature, sender_keyword = "caller")(wrapper) self._dbus_methods[method_name] = wrapper def signal(self, method, out_signature): if not ismethod(method): raise Exception("Only bound methods can be exported.") method_name = method.__name__ if method_name in self._dbus_methods: raise Exception("Method with this name is already exported.") def wrapper(owner, *args, **kwargs): return method(*args, **kwargs) wrapper = self._prepare_for_dbus(method, wrapper) wrapper = dbus.service.signal(self._interface_name, out_signature)(wrapper) self._dbus_methods[method_name] = wrapper self._signals.add(method_name) def send_signal(self, signal, *args, **kwargs): err = False if not signal in self._signals or self._bus_object is None: err = True try: method = getattr(self._bus_object, signal) except AttributeError: err = True if err: raise Exception("Signal '%s' doesn't exist." % signal) else: method(*args, **kwargs) def _construct_dbus_object_class(self): if self._dbus_object_cls is not None: raise Exception("The exporter class was already build.") unique_name = "DBusExporter_%d" % id(self) cls = type(unique_name, (dbus.service.Object,), self._dbus_methods) self._dbus_object_cls = cls def start(self): if self.running(): return if self._dbus_object_cls is None: self._construct_dbus_object_class() self.stop() bus = dbus.SystemBus() bus_name = dbus.service.BusName(self._bus_name, bus) self._bus_object = self._dbus_object_cls(bus, self._object_name, bus_name) self._thread = threading.Thread(target=self._thread_code) self._thread.start() def stop(self): if self._thread is not None and self._thread.is_alive(): self._main_loop.quit() self._thread.join() self._thread = None def _thread_code(self): self._main_loop.run() del self._bus_object self._bus_object = None controller.py000064400000006722152533617320007317 0ustar00from . import interfaces import inspect import tuned.patterns class ExportsController(tuned.patterns.Singleton): """ Controls and manages object interface exporting. """ def __init__(self): super(ExportsController, self).__init__() self._exporters = [] self._objects = [] self._exports_initialized = False def register_exporter(self, instance): """Register objects exporter.""" self._exporters.append(instance) def register_object(self, instance): """Register object to be exported.""" self._objects.append(instance) def _is_exportable_method(self, method): """Check if method was marked with @exports.export wrapper.""" return inspect.ismethod(method) and hasattr(method, "export_params") def _is_exportable_signal(self, method): """Check if method was marked with @exports.signal wrapper.""" return inspect.ismethod(method) and hasattr(method, "signal_params") def _is_exportable_getter(self, method): """Check if method was marked with @exports.get_property wrapper.""" return inspect.ismethod(method) and hasattr(method, "property_get_params") def _is_exportable_setter(self, method): """Check if method was marked with @exports.set_property wrapper.""" return inspect.ismethod(method) and hasattr(method, "property_set_params") def _export_method(self, method): """Register method to all exporters.""" for exporter in self._exporters: args = method.export_params[0] kwargs = method.export_params[1] exporter.export(method, *args, **kwargs) def _export_signal(self, method): """Register signal to all exporters.""" for exporter in self._exporters: args = method.signal_params[0] kwargs = method.signal_params[1] exporter.signal(method, *args, **kwargs) def _export_getter(self, method): """Register property getter to all exporters.""" for exporter in self._exporters: args = method.property_get_params[0] kwargs = method.property_get_params[1] exporter.property_getter(method, *args, **kwargs) def _export_setter(self, method): """Register property setter to all exporters.""" for exporter in self._exporters: args = method.property_set_params[0] kwargs = method.property_set_params[1] exporter.property_setter(method, *args, **kwargs) def send_signal(self, signal, *args, **kwargs): """Register signal to all exporters.""" for exporter in self._exporters: exporter.send_signal(signal, *args, **kwargs) def property_changed(self, *args, **kwargs): for exporter in self._exporters: exporter.property_changed(*args, **kwargs) def period_check(self): """Allows to perform checks on exporters without special thread.""" for exporter in self._exporters: exporter.period_check() def _initialize_exports(self): if self._exports_initialized: return for instance in self._objects: for name, method in inspect.getmembers(instance, self._is_exportable_method): self._export_method(method) for name, method in inspect.getmembers(instance, self._is_exportable_signal): self._export_signal(method) for name, method in inspect.getmembers(instance, self._is_exportable_getter): self._export_getter(method) for name, method in inspect.getmembers(instance, self._is_exportable_setter): self._export_setter(method) self._exports_initialized = True def start(self): """Start the exports.""" self._initialize_exports() for exporter in self._exporters: exporter.start() def stop(self): """Stop the exports.""" for exporter in self._exporters: exporter.stop() __pycache__/dbus_exporter.cpython-36.opt-1.pyc000064400000015573152533617320015250 0ustar003 execr) formatrrr__func__r9compilelenr$r co_constslocals)r2methodwrappersourcecoder r r r _prepare_for_dbusoszDBusExporter._prepare_for_dbuscsjtstdj}|jkr(tdfdd}j|}tjjj||dd|}|j|<dS)Nz#Only bound methods can be exported.z*Method with this name is already exported.cs jdj}|d }tjd||fjj||}|}|dkrXtjd||fn|dkrttjd||fn|dkrtjd||ft|dd d g}nZ|dkrtjd ||ft|ddd g}n(tj d ||ft|ddd g}||S)N.rz?checking authorization for action '%s' requested by caller '%s'zJaction '%s' requested by caller '%s' was successfully authorized by polkitzepolkit error, but action '%s' requested by caller '%s' was successfully authorized by fallback methodrzLaction '%s' requested by caller '%s' wasn't authorized, ignoring the requestrzppolkit error and action '%s' requested by caller '%s' wasn't authorized by fallback method, ignoring the requestzvpolkit error and unable to use fallback method to authorize action '%s' requested by caller '%s', ignoring the requestrHrHrHrH) r*rrdebugr-Zcheck_authorizationwarninfolisterror)ownerr9kwargsZ action_idcallerretZ args_copy)rAr2r r rBs$z$DBusExporter.export..wrapperrP)Zsender_keyword) r Exceptionrr$rEr!r"rAr()r2rAZ in_signature out_signature method_namerBr )rAr2r export}s  zDBusExporter.exportcsntstdj}||jkr(tdfdd}|j|}tjj|j||}||j|<|j j |dS)Nz#Only bound methods can be exported.z*Method with this name is already exported.cs ||S)Nr )rNr9rO)rAr r rBsz$DBusExporter.signal..wrapper) rrRrr$rEr!r"r.r(r&add)r2rArSrTrBr )rAr r.s    zDBusExporter.signalc Osfd}||jks|jdkrd}yt|j|}Wntk rDd}YnX|rXtd|n |||dS)NFTzSignal '%s' doesn't exist.)r&r,rAttributeErrorrR)r2r.r9rOerrrAr r r send_signals zDBusExporter.send_signalcCs<|jdk rtddt|}t|tjjf|j}||_dS)Nz%The exporter class was already build.zDBusExporter_%d)r#rRidtyper!r"ZObjectr$)r2Z unique_nameclsr r r _construct_dbus_object_classs   z)DBusExporter._construct_dbus_object_classcCsn|jr dS|jdkr|j|jtj}tjj|j|}|j||j ||_ t j |j d|_|jjdS)N)target)r8r#r]stopr!Z SystemBusr"ZBusNamer'r)r, threadingZThread _thread_coder+start)r2Zbusr3r r r rbs zDBusExporter.startcCs2|jdk r.|jjr.|jj|jjd|_dS)N)r+Zis_aliver1quitr)r2r r r r_s  zDBusExporter.stopcCs|jj|`d|_dS)N)r1Zrunr,)r2r r r ras zDBusExporter._thread_codeN)rr __qualname____doc__r7propertyr3r4r5r8rErUr.rYr]rbr_rar r r r r8s   "   r)"rrZ dbus.servicer!Zdbus.mainloop.glibZdbus.exceptionsr`r.Z tuned.logsZtunedZ tuned.constsZconstsrrinspectrZtuned.utils.polkitrZ gi.repositoryrtypesrrZ dbus.lowlevelr r r ImportErrorZlogsgetrrZExporterInterfacerr r r r s.           __pycache__/__init__.cpython-36.opt-1.pyc000064400000005413152533617320014112 0ustar003 .wrapperr )rr r r )rr r exportsr csfdd}|S)z*Decorator, use to mark exportable signals.csg|_|S)N)Z signal_params)r)rr r r r s zsignal..wrapperr )rr r r )rr r signalsrcsfdd}|S)z8Decorator, use to mark setters of exportable properties.csg|_|S)N)Zproperty_set_params)r)rr r r r s z property_setter..wrapperr )rr r r )rr r property_settersrcsfdd}|S)z8Decorator, use to mark getters of exportable properties.csg|_|S)N)Zproperty_get_params)r)rr r r r s z property_getter..wrapperr )rr r r )rr r property_gettersrcOstjj}|j||S)N)rExportsController get_instanceproperty_changed)rr ctlr r r r#s rcCs&t|tjsttjj}|j|S)N) isinstancerZExporterInterface Exceptionrrrregister_exporter)instancerr r r r's  rcCs&t|tjsttjj}|j|S)N)rrZExportableInterfacerrrrregister_object)rrr r r r-s  rcOstjj}|j||S)N)rrr send_signal)rr rr r r r3s rcCstjj}|jS)N)rrrstart)rr r r r7s rcCstjj}|jS)N)rrrstop)rr r r r;s rcCstjj}|jS)N)rrr period_check)rr r r r?s rN)rrrZdbusrZdbus_with_propertiesrZ unix_socketr rrrrrrrrrrr r r r s     __pycache__/dbus_exporter.cpython-36.pyc000064400000015573152533617320014311 0ustar003 execr) formatrrr__func__r9compilelenr$r co_constslocals)r2methodwrappersourcecoder r r r _prepare_for_dbusoszDBusExporter._prepare_for_dbuscsjtstdj}|jkr(tdfdd}j|}tjjj||dd|}|j|<dS)Nz#Only bound methods can be exported.z*Method with this name is already exported.cs jdj}|d }tjd||fjj||}|}|dkrXtjd||fn|dkrttjd||fn|dkrtjd||ft|dd d g}nZ|dkrtjd ||ft|ddd g}n(tj d ||ft|ddd g}||S)N.rz?checking authorization for action '%s' requested by caller '%s'zJaction '%s' requested by caller '%s' was successfully authorized by polkitzepolkit error, but action '%s' requested by caller '%s' was successfully authorized by fallback methodrzLaction '%s' requested by caller '%s' wasn't authorized, ignoring the requestrzppolkit error and action '%s' requested by caller '%s' wasn't authorized by fallback method, ignoring the requestzvpolkit error and unable to use fallback method to authorize action '%s' requested by caller '%s', ignoring the requestrHrHrHrH) r*rrdebugr-Zcheck_authorizationwarninfolisterror)ownerr9kwargsZ action_idcallerretZ args_copy)rAr2r r rBs$z$DBusExporter.export..wrapperrP)Zsender_keyword) r Exceptionrr$rEr!r"rAr()r2rAZ in_signature out_signature method_namerBr )rAr2r export}s  zDBusExporter.exportcsntstdj}||jkr(tdfdd}|j|}tjj|j||}||j|<|j j |dS)Nz#Only bound methods can be exported.z*Method with this name is already exported.cs ||S)Nr )rNr9rO)rAr r rBsz$DBusExporter.signal..wrapper) rrRrr$rEr!r"r.r(r&add)r2rArSrTrBr )rAr r.s    zDBusExporter.signalc Osfd}||jks|jdkrd}yt|j|}Wntk rDd}YnX|rXtd|n |||dS)NFTzSignal '%s' doesn't exist.)r&r,rAttributeErrorrR)r2r.r9rOerrrAr r r send_signals zDBusExporter.send_signalcCs<|jdk rtddt|}t|tjjf|j}||_dS)Nz%The exporter class was already build.zDBusExporter_%d)r#rRidtyper!r"ZObjectr$)r2Z unique_nameclsr r r _construct_dbus_object_classs   z)DBusExporter._construct_dbus_object_classcCsn|jr dS|jdkr|j|jtj}tjj|j|}|j||j ||_ t j |j d|_|jjdS)N)target)r8r#r]stopr!Z SystemBusr"ZBusNamer'r)r, threadingZThread _thread_coder+start)r2Zbusr3r r r rbs zDBusExporter.startcCs2|jdk r.|jjr.|jj|jjd|_dS)N)r+Zis_aliver1quitr)r2r r r r_s  zDBusExporter.stopcCs|jj|`d|_dS)N)r1Zrunr,)r2r r r ras zDBusExporter._thread_codeN)rr __qualname____doc__r7propertyr3r4r5r8rErUr.rYr]rbr_rar r r r r8s   "   r)"rrZ dbus.servicer!Zdbus.mainloop.glibZdbus.exceptionsr`r.Z tuned.logsZtunedZ tuned.constsZconstsrrinspectrZtuned.utils.polkitrZ gi.repositoryrtypesrrZ dbus.lowlevelr r r ImportErrorZlogsgetrrZExporterInterfacerr r r r s.           __pycache__/dbus_exporter_with_properties.cpython-36.pyc000064400000006315152533617320017612 0ustar003 .GetcsB|jkrtd||jkr,td|j|}||dS)NzUnknown interface: %szNo such property: %s)r r_property_setters)r r r valuesetter)rrrSets      z0DBusExporterWithProperties.__init__..Setcs*|jkrtd|ddjjDS)NzUnknown interface: %scSsi|]\}}||qSrr).0namerrrr !szGDBusExporterWithProperties.__init__..GetAll..)r rr items)r r )rrrGetAlls  z3DBusExporterWithProperties.__init__..GetAllcs|jkrtd|dS)NzUnknown interface: %s)r r)r r Zchanged_propertiesZinvalidated_properties)rrrPropertiesChanged#s z>DBusExporterWithProperties.__init__..PropertiesChangedZssv) in_signatureZ out_signaturerZssv)rrsza{sv}rzsa{sv}as)Z signaturer) superr__init__rr rrZ _dbus_methodsrZ_signalsadd) rZbus_namer Z object_name namespacerrrr) __class__)rrr! s    z#DBusExporterWithProperties.__init__cCs|jd|j||iidS)Nr)Z send_signalr )rr rrrrproperty_changed-sz+DBusExporterWithProperties.property_changedcCs0t|std||jkr"td||j|<dS)Nz#Only bound methods can be exported.z1A getter for this property is already registered.)r Exceptionr )rrr rrrproperty_getter0s  z*DBusExporterWithProperties.property_gettercCs0t|std||jkr"td||j|<dS)Nz#Only bound methods can be exported.z1A setter for this property is already registered.)rr&r)rrr rrrproperty_setter7s  z*DBusExporterWithProperties.property_setter)__name__ __module__ __qualname__r!r%r'r( __classcell__rr)r$rrs $rN) inspectrZ dbus.servicerrZdbusrZdbus.exceptionsrZtuned.exports.dbus_exporterrrrrrrs    __pycache__/dbus_exporter_with_properties.cpython-36.opt-1.pyc000064400000006315152533617320020551 0ustar003 .GetcsB|jkrtd||jkr,td|j|}||dS)NzUnknown interface: %szNo such property: %s)r r_property_setters)r r r valuesetter)rrrSets      z0DBusExporterWithProperties.__init__..Setcs*|jkrtd|ddjjDS)NzUnknown interface: %scSsi|]\}}||qSrr).0namerrrr !szGDBusExporterWithProperties.__init__..GetAll..)r rr items)r r )rrrGetAlls  z3DBusExporterWithProperties.__init__..GetAllcs|jkrtd|dS)NzUnknown interface: %s)r r)r r Zchanged_propertiesZinvalidated_properties)rrrPropertiesChanged#s z>DBusExporterWithProperties.__init__..PropertiesChangedZssv) in_signatureZ out_signaturerZssv)rrsza{sv}rzsa{sv}as)Z signaturer) superr__init__rr rrZ _dbus_methodsrZ_signalsadd) rZbus_namer Z object_name namespacerrrr) __class__)rrr! s    z#DBusExporterWithProperties.__init__cCs|jd|j||iidS)Nr)Z send_signalr )rr rrrrproperty_changed-sz+DBusExporterWithProperties.property_changedcCs0t|std||jkr"td||j|<dS)Nz#Only bound methods can be exported.z1A getter for this property is already registered.)r Exceptionr )rrr rrrproperty_getter0s  z*DBusExporterWithProperties.property_gettercCs0t|std||jkr"td||j|<dS)Nz#Only bound methods can be exported.z1A setter for this property is already registered.)rr&r)rrr rrrproperty_setter7s  z*DBusExporterWithProperties.property_setter)__name__ __module__ __qualname__r!r%r'r( __classcell__rr)r$rrs $rN) inspectrZ dbus.servicerrZdbusrZdbus.exceptionsrZtuned.exports.dbus_exporterrrrrrrs    __pycache__/unix_socket_exporter.cpython-36.opt-1.pyc000064400000021134152533617320016634 0ustar003 .wrappercSs||_||_dS)N)Z _in_signature_out_signature)r in_signature out_signaturerrr r!Gsz3UnixSocketExporter.export..wrapper.__init__cs ||S)Nr)rargskwargs)methodrr __call__Ksz3UnixSocketExporter.export..wrapper.__call__N)__name__ __module__ __qualname__r!r)r)r(rr wrapperFsr-)r Exceptionr*robject)rr(r$r% method_namer-r)r(r export>s  zUnixSocketExporter.exportcs^tstdj}||jkr,td|Gfdddt}|||j|<|jj|dS)Nz#Only bound methods can be exported.z/Method with this name (%s) is already exported.cs eZdZddZfddZdS)z*UnixSocketExporter.signal..wrappercSs ||_dS)N)r#)rr%rrr r!Ysz3UnixSocketExporter.signal..wrapper.__init__cs ||S)Nr)rr&r')r(rr r)\sz3UnixSocketExporter.signal..wrapper.__call__N)r*r+r,r!r)r)r(rr r-Xsr-)rr.r*rr/radd)rr(r%r0r-r)r(r signalPs  zUnixSocketExporter.signalcOs||jkrtd|x|jD]}tjd|yDtjtjtj}|jd|j ||j |d||d|j Wqt k r}ztj d|||fWYdd}~XqXqWdS)NzSignal '%s' doesn't exist.zSending signal on socket %sFz2.0)jsonrpcr(paramsz2Error while sending signal '%s' to socket '%s': %s)rr.r rdebugsocketAF_UNIX SOCK_STREAMZ setblockingZconnect _send_datacloseOSErrorwarning)rr3r&r'pserrr send_signalbs      zUnixSocketExporter.send_signalcCs|jj|dS)N)r append)rpathrrr register_signal_pathpsz'UnixSocketExporter.register_signal_pathcCs|jrtjj|jr tj|jtjtjtj|_|jj |j|jj |j tj |j|j d|j d|jrtj|j|jdS)Nrr)rosrCexistsunlinkr7r8r9r ZbindZlistenrchownr rchmod)rrrr _construct_socket_objectss z+UnixSocketExporter._construct_socket_objectcCs |jr dS|j|jdS)N)r"stoprJ)rrrr start~szUnixSocketExporter.startcCs|jr|jjdS)N)r r;)rrrr rKszUnixSocketExporter.stopcCsbtjd|y|jtj|jdWn4tk r\}ztjd||fWYdd}~XnXdS)NzSending socket data: %s)zutf-8zFailed to send data '%s': %s)rr6sendjsondumpsencoder.r=)rr?datar@rrr r:s zUnixSocketExporter._send_dataFcCs$d|d}|r||d<n||d<|S)Nz2.0)r4idrresultr)rrQrRrresrrr _create_responses  z#UnixSocketExporter._create_responseNcCs|j|||dd|dS)N)codemessagerQT)rrR)rU)rrVrWrRrQrrr _create_error_responces z)UnixSocketExporter._create_error_responcecCs |j||S)N)rU)rrSrRrrr _create_result_responsesz*UnixSocketExporter._create_result_responsecCs|jdr|SdS)NrR)get)rrQrrr _check_ids zUnixSocketExporter._check_idcCsnt|tks&|jddks&|jd r2|jddS|jd}d}|d|jkrb|j|jdd|Sy|jd s|j|d}njt|d ttfkr|j|d|d }n>t|d tkr|j|df|d }n|j|jdd|SWnntk r$}z|j|jdd |t |Sd}~Xn8t k rZ}z|j|jd d |t |Sd}~XnX|j|j ||S)Nr4z2.0r(iXzInvalid RequestrRiYzMethod not foundr5iZzInvalid paramsrErroriiii) typedictrZrXrr[listtuple TypeErrorstrr.rY)rreqrRretr@rrr _process_requests&&   $&z#UnixSocketExporter._process_requestc #Cs|js dSxtj|jgffd\}}}|r|jj\}}y*d}x |jdj}|sZP||7}qFWWn2tk r}ztjd|wWYdd}~XnX|ryt j |}WnRtk r}z4tjd||f|j ||j d dt |wWYdd}~XnXt|tttfkr>tjd |j ||j d dt |qt|ttfkrt|dkrz|j ||j dd t |qg}x(|D] }|j|}|r|j|qW|r|j ||n|j|}|r|j ||qdSqWdS)a Periodically checks socket object for new calls. This allows to function without special thread. Interface is according JSON-RPC 2.0 Specification (see https://www.jsonrpc.org/specification) Example calls: printf '[{"jsonrpc": "2.0", "method": "active_profile", "id": 1}, {"jsonrpc": "2.0", "method": "profiles", "id": 2}]' | nc -U /run/tuned/tuned.sock printf '{"jsonrpc": "2.0", "method": "switch_profile", "params": {"profile_name": "balanced"}, "id": 1}' | nc -U /run/tuned/tuned.sock Nriz"Failed to load data of message: %sz!Failed to load json data '%s': %siz Parse errorzWrong format of calliXzInvalid RequestiDiDi)r"selectr ZacceptZrecvdecoder.rrrNloadsr:rXrbr]r`r_r^lenrerB) rr_ZconnrQZrec_datar@rTrcrrr period_checksT     zUnixSocketExporter.period_check)F)NN)r*r+r,__doc__constsZCFG_DEF_UNIX_SOCKET_PATHZ CFG_DEF_UNIX_SOCKET_SIGNAL_PATHSZCFG_DEF_UNIX_SOCKET_OWNERSHIPZCFG_DEF_UNIX_SOCKET_PERMISIONSZ'CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOGr!r"r1r3rArDrJrLrKr:rUrXrYr[rermrrrr rs*  r)rEr rrrfrZ tuned.logsZtunedZ tuned.constsroinspectrr7rNrgZlogsrZrZExporterInterfacerrrrr s    __pycache__/interfaces.cpython-36.opt-1.pyc000064400000002400152533617320014467 0ustar003 s__pycache__/interfaces.cpython-36.pyc000064400000002400152533617320013530 0ustar003 s__pycache__/controller.cpython-36.pyc000064400000011237152533617320013600 0ustar003 Check if method was marked with @exports.get_property wrapper.property_get_params)rrr)r rr r r _is_exportable_getter sz'ExportsController._is_exportable_gettercCstj|ot|dS)z>Check if method was marked with @exports.set_property wrapper.property_set_params)rrr)r rr r r _is_exportable_setter$sz'ExportsController._is_exportable_settercCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z!Register method to all exporters.rrN)rrZexport)r rexporterargskwargsr r r _export_method(s   z ExportsController._export_methodcCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z!Register signal to all exporters.rrN)rrsignal)r rrrr r r r _export_signal/s   z ExportsController._export_signalcCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z*Register property getter to all exporters.rrN)rrZproperty_getter)r rrrr r r r _export_getter6s   z ExportsController._export_gettercCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z*Register property setter to all exporters.rrN)rrZproperty_setter)r rrrr r r r _export_setter=s   z ExportsController._export_settercOs&x |jD]}|j|f||qWdS)z!Register signal to all exporters.N)r send_signal)r r"rr rr r r r&Ds zExportsController.send_signalcOs x|jD]}|j||qWdS)N)rproperty_changed)r rr rr r r r'Is z"ExportsController.property_changedcCsx|jD] }|jqWdS)z=Allows to perform checks on exporters without special thread.N)r period_check)r rr r r r(Ms zExportsController.period_checkcCs|jr dSx|jD]}x$tj||jD]\}}|j|q&Wx$tj||jD]\}}|j|qLWx$tj||jD]\}}|j |qrWx$tj||j D]\}}|j |qWqWd|_dS)NT) r rrZ getmembersrr!rr#rr$rr%)r rnamerr r r _initialize_exportsRs z%ExportsController._initialize_exportscCs$|jx|jD] }|jqWdS)zStart the exports.N)r*rstart)r rr r r r+bs zExportsController.startcCsx|jD] }|jqWdS)zStop the exports.N)rstop)r rr r r r,hs zExportsController.stop)__name__ __module__ __qualname____doc__rrrrrrrr!r#r$r%r&r'r(r*r+r, __classcell__r r )r r rs$ r)rrZtuned.patternsZtunedZpatternsZ Singletonrr r r r s __pycache__/unix_socket_exporter.cpython-36.pyc000064400000021134152533617320015675 0ustar003 .wrappercSs||_||_dS)N)Z _in_signature_out_signature)r in_signature out_signaturerrr r!Gsz3UnixSocketExporter.export..wrapper.__init__cs ||S)Nr)rargskwargs)methodrr __call__Ksz3UnixSocketExporter.export..wrapper.__call__N)__name__ __module__ __qualname__r!r)r)r(rr wrapperFsr-)r Exceptionr*robject)rr(r$r% method_namer-r)r(r export>s  zUnixSocketExporter.exportcs^tstdj}||jkr,td|Gfdddt}|||j|<|jj|dS)Nz#Only bound methods can be exported.z/Method with this name (%s) is already exported.cs eZdZddZfddZdS)z*UnixSocketExporter.signal..wrappercSs ||_dS)N)r#)rr%rrr r!Ysz3UnixSocketExporter.signal..wrapper.__init__cs ||S)Nr)rr&r')r(rr r)\sz3UnixSocketExporter.signal..wrapper.__call__N)r*r+r,r!r)r)r(rr r-Xsr-)rr.r*rr/radd)rr(r%r0r-r)r(r signalPs  zUnixSocketExporter.signalcOs||jkrtd|x|jD]}tjd|yDtjtjtj}|jd|j ||j |d||d|j Wqt k r}ztj d|||fWYdd}~XqXqWdS)NzSignal '%s' doesn't exist.zSending signal on socket %sFz2.0)jsonrpcr(paramsz2Error while sending signal '%s' to socket '%s': %s)rr.r rdebugsocketAF_UNIX SOCK_STREAMZ setblockingZconnect _send_datacloseOSErrorwarning)rr3r&r'pserrr send_signalbs      zUnixSocketExporter.send_signalcCs|jj|dS)N)r append)rpathrrr register_signal_pathpsz'UnixSocketExporter.register_signal_pathcCs|jrtjj|jr tj|jtjtjtj|_|jj |j|jj |j tj |j|j d|j d|jrtj|j|jdS)Nrr)rosrCexistsunlinkr7r8r9r ZbindZlistenrchownr rchmod)rrrr _construct_socket_objectss z+UnixSocketExporter._construct_socket_objectcCs |jr dS|j|jdS)N)r"stoprJ)rrrr start~szUnixSocketExporter.startcCs|jr|jjdS)N)r r;)rrrr rKszUnixSocketExporter.stopcCsbtjd|y|jtj|jdWn4tk r\}ztjd||fWYdd}~XnXdS)NzSending socket data: %s)zutf-8zFailed to send data '%s': %s)rr6sendjsondumpsencoder.r=)rr?datar@rrr r:s zUnixSocketExporter._send_dataFcCs$d|d}|r||d<n||d<|S)Nz2.0)r4idrresultr)rrQrRrresrrr _create_responses  z#UnixSocketExporter._create_responseNcCs|j|||dd|dS)N)codemessagerQT)rrR)rU)rrVrWrRrQrrr _create_error_responces z)UnixSocketExporter._create_error_responcecCs |j||S)N)rU)rrSrRrrr _create_result_responsesz*UnixSocketExporter._create_result_responsecCs|jdr|SdS)NrR)get)rrQrrr _check_ids zUnixSocketExporter._check_idcCsnt|tks&|jddks&|jd r2|jddS|jd}d}|d|jkrb|j|jdd|Sy|jd s|j|d}njt|d ttfkr|j|d|d }n>t|d tkr|j|df|d }n|j|jdd|SWnntk r$}z|j|jdd |t |Sd}~Xn8t k rZ}z|j|jd d |t |Sd}~XnX|j|j ||S)Nr4z2.0r(iXzInvalid RequestrRiYzMethod not foundr5iZzInvalid paramsrErroriiii) typedictrZrXrr[listtuple TypeErrorstrr.rY)rreqrRretr@rrr _process_requests&&   $&z#UnixSocketExporter._process_requestc #Cs|js dSxtj|jgffd\}}}|r|jj\}}y*d}x |jdj}|sZP||7}qFWWn2tk r}ztjd|wWYdd}~XnX|ryt j |}WnRtk r}z4tjd||f|j ||j d dt |wWYdd}~XnXt|tttfkr>tjd |j ||j d dt |qt|ttfkrt|dkrz|j ||j dd t |qg}x(|D] }|j|}|r|j|qW|r|j ||n|j|}|r|j ||qdSqWdS)a Periodically checks socket object for new calls. This allows to function without special thread. Interface is according JSON-RPC 2.0 Specification (see https://www.jsonrpc.org/specification) Example calls: printf '[{"jsonrpc": "2.0", "method": "active_profile", "id": 1}, {"jsonrpc": "2.0", "method": "profiles", "id": 2}]' | nc -U /run/tuned/tuned.sock printf '{"jsonrpc": "2.0", "method": "switch_profile", "params": {"profile_name": "balanced"}, "id": 1}' | nc -U /run/tuned/tuned.sock Nriz"Failed to load data of message: %sz!Failed to load json data '%s': %siz Parse errorzWrong format of calliXzInvalid RequestiDiDi)r"selectr ZacceptZrecvdecoder.rrrNloadsr:rXrbr]r`r_r^lenrerB) rr_ZconnrQZrec_datar@rTrcrrr period_checksT     zUnixSocketExporter.period_check)F)NN)r*r+r,__doc__constsZCFG_DEF_UNIX_SOCKET_PATHZ CFG_DEF_UNIX_SOCKET_SIGNAL_PATHSZCFG_DEF_UNIX_SOCKET_OWNERSHIPZCFG_DEF_UNIX_SOCKET_PERMISIONSZ'CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOGr!r"r1r3rArDrJrLrKr:rUrXrYr[rermrrrr rs*  r)rEr rrrfrZ tuned.logsZtunedZ tuned.constsroinspectrr7rNrgZlogsrZrZExporterInterfacerrrrr s    __pycache__/controller.cpython-36.opt-1.pyc000064400000011237152533617320014537 0ustar003 Check if method was marked with @exports.get_property wrapper.property_get_params)rrr)r rr r r _is_exportable_getter sz'ExportsController._is_exportable_gettercCstj|ot|dS)z>Check if method was marked with @exports.set_property wrapper.property_set_params)rrr)r rr r r _is_exportable_setter$sz'ExportsController._is_exportable_settercCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z!Register method to all exporters.rrN)rrZexport)r rexporterargskwargsr r r _export_method(s   z ExportsController._export_methodcCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z!Register signal to all exporters.rrN)rrsignal)r rrrr r r r _export_signal/s   z ExportsController._export_signalcCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z*Register property getter to all exporters.rrN)rrZproperty_getter)r rrrr r r r _export_getter6s   z ExportsController._export_gettercCs:x4|jD]*}|jd}|jd}|j|f||qWdS)z*Register property setter to all exporters.rrN)rrZproperty_setter)r rrrr r r r _export_setter=s   z ExportsController._export_settercOs&x |jD]}|j|f||qWdS)z!Register signal to all exporters.N)r send_signal)r r"rr rr r r r&Ds zExportsController.send_signalcOs x|jD]}|j||qWdS)N)rproperty_changed)r rr rr r r r'Is z"ExportsController.property_changedcCsx|jD] }|jqWdS)z=Allows to perform checks on exporters without special thread.N)r period_check)r rr r r r(Ms zExportsController.period_checkcCs|jr dSx|jD]}x$tj||jD]\}}|j|q&Wx$tj||jD]\}}|j|qLWx$tj||jD]\}}|j |qrWx$tj||j D]\}}|j |qWqWd|_dS)NT) r rrZ getmembersrr!rr#rr$rr%)r rnamerr r r _initialize_exportsRs z%ExportsController._initialize_exportscCs$|jx|jD] }|jqWdS)zStart the exports.N)r*rstart)r rr r r r+bs zExportsController.startcCsx|jD] }|jqWdS)zStop the exports.N)rstop)r rr r r r,hs zExportsController.stop)__name__ __module__ __qualname____doc__rrrrrrrr!r#r$r%r&r'r(r*r+r, __classcell__r r )r r rs$ r)rrZtuned.patternsZtunedZpatternsZ Singletonrr r r r s __pycache__/__init__.cpython-36.pyc000064400000005413152533617320013153 0ustar003 .wrapperr )rr r r )rr r exportsr csfdd}|S)z*Decorator, use to mark exportable signals.csg|_|S)N)Z signal_params)r)rr r r r s zsignal..wrapperr )rr r r )rr r signalsrcsfdd}|S)z8Decorator, use to mark setters of exportable properties.csg|_|S)N)Zproperty_set_params)r)rr r r r s z property_setter..wrapperr )rr r r )rr r property_settersrcsfdd}|S)z8Decorator, use to mark getters of exportable properties.csg|_|S)N)Zproperty_get_params)r)rr r r r s z property_getter..wrapperr )rr r r )rr r property_gettersrcOstjj}|j||S)N)rExportsController get_instanceproperty_changed)rr ctlr r r r#s rcCs&t|tjsttjj}|j|S)N) isinstancerZExporterInterface Exceptionrrrregister_exporter)instancerr r r r's  rcCs&t|tjsttjj}|j|S)N)rrZExportableInterfacerrrrregister_object)rrr r r r-s  rcOstjj}|j||S)N)rrr send_signal)rr rr r r r3s rcCstjj}|jS)N)rrrstart)rr r r r7s rcCstjj}|jS)N)rrrstop)rr r r r;s rcCstjj}|jS)N)rrr period_check)rr r r r?s rN)rrrZdbusrZdbus_with_propertiesrZ unix_socketr rrrrrrrrrrr r r r s     interfaces.py000064400000001114152533617320007245 0ustar00class ExportableInterface(object): pass class ExporterInterface(object): def export(self, method, in_signature, out_signature): # to be overridden by concrete implementation raise NotImplementedError() def signal(self, method, out_signature): # to be overridden by concrete implementation raise NotImplementedError() def send_signal(self, signal, *args, **kwargs): # to be overridden by concrete implementation raise NotImplementedError() def start(self): raise NotImplementedError() def stop(self): raise NotImplementedError() def period_check(self): pass unix_socket_exporter.py000064400000017300152533617320011411 0ustar00import os import re import pwd, grp from . import interfaces import tuned.logs import tuned.consts as consts from inspect import ismethod import socket import json import select log = tuned.logs.get() class UnixSocketExporter(interfaces.ExporterInterface): """ Export method calls through Unix Domain Socket Interface. We take a method to be exported and create a simple wrapper function to call it. This is required as we need the original function to be bound to the original object instance. While the wrapper will be bound to an object we dynamically construct. """ def __init__(self, socket_path=consts.CFG_DEF_UNIX_SOCKET_PATH, signal_paths=consts.CFG_DEF_UNIX_SOCKET_SIGNAL_PATHS, ownership=consts.CFG_DEF_UNIX_SOCKET_OWNERSHIP, permissions=consts.CFG_DEF_UNIX_SOCKET_PERMISIONS, connections_backlog=consts.CFG_DEF_UNIX_SOCKET_CONNECTIONS_BACKLOG): self._socket_path = socket_path self._socket_object = None self._socket_signal_paths = re.split(r",;", signal_paths) if signal_paths else [] self._socket_signal_objects = [] self._ownership = [-1, -1] if ownership: ownership = ownership.split() for i, o in enumerate(ownership[:2]): try: self._ownership[i] = int(o) except ValueError: try: # user if i == 0: self._ownership[i] = pwd.getpwnam(o).pw_uid # group else: self._ownership[i] = grp.getgrnam(o).gr_gid except KeyError: log.error("%s '%s' does not exists, leaving default" % ("User" if i == 0 else "Group", o)) self._permissions = permissions self._connections_backlog = connections_backlog self._unix_socket_methods = {} self._signals = set() self._conn = None self._channel = None def running(self): return self._socket_object is not None def export(self, method, in_signature, out_signature): if not ismethod(method): raise Exception("Only bound methods can be exported.") method_name = method.__name__ if method_name in self._unix_socket_methods: raise Exception("Method with this name (%s) is already exported." % method_name) class wrapper(object): def __init__(self, in_signature, out_signature): self._in_signature = in_signature self._out_signature = out_signature def __call__(self, *args, **kwargs): return method(*args, **kwargs) self._unix_socket_methods[method_name] = wrapper(in_signature, out_signature) def signal(self, method, out_signature): if not ismethod(method): raise Exception("Only bound methods can be exported.") method_name = method.__name__ if method_name in self._unix_socket_methods: raise Exception("Method with this name (%s) is already exported." % method_name) class wrapper(object): def __init__(self, out_signature): self._out_signature = out_signature def __call__(self, *args, **kwargs): return method(*args, **kwargs) self._unix_socket_methods[method_name] = wrapper(out_signature) self._signals.add(method_name) def send_signal(self, signal, *args, **kwargs): if not signal in self._signals: raise Exception("Signal '%s' doesn't exist." % signal) for p in self._socket_signal_paths: log.debug("Sending signal on socket %s" % p) try: s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) s.setblocking(False) s.connect(p) self._send_data(s, {"jsonrpc": "2.0", "method": signal, "params": args}) s.close() except OSError as e: log.warning("Error while sending signal '%s' to socket '%s': %s" % (signal, p, e)) def register_signal_path(self, path): self._socket_signal_paths.append(path) def _construct_socket_object(self): if self._socket_path: if os.path.exists(self._socket_path): os.unlink(self._socket_path) self._socket_object = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) self._socket_object.bind(self._socket_path) self._socket_object.listen(self._connections_backlog) os.chown(self._socket_path, self._ownership[0], self._ownership[1]) if self._permissions: os.chmod(self._socket_path, self._permissions) def start(self): if self.running(): return self.stop() self._construct_socket_object() def stop(self): if self._socket_object: self._socket_object.close() def _send_data(self, s, data): log.debug("Sending socket data: %s)" % data) try: s.send(json.dumps(data).encode("utf-8")) except Exception as e: log.warning("Failed to send data '%s': %s" % (data, e)) def _create_response(self, data, id, error=False): res = { "jsonrpc": "2.0", "id": id } if error: res["error"] = data else: res["result"] = data return res def _create_error_responce(self, code, message, id=None, data=None): return self._create_response({ "code": code, "message": message, "data": data, }, error=True, id=id) def _create_result_response(self, result, id): return self._create_response(result, id) def _check_id(self, data): if data.get("id"): return data return None def _process_request(self, req): if type(req) != dict or req.get("jsonrpc") != "2.0" or not req.get("method"): return self._create_error_responce(-32600, "Invalid Request") id = req.get("id") ret = None if req["method"] not in self._unix_socket_methods: return self._check_id(self._create_error_responce(-32601, "Method not found", id)) try: if not req.get("params"): ret = self._unix_socket_methods[req["method"]]() elif type(req["params"]) in (list, tuple): ret = self._unix_socket_methods[req["method"]](*req["params"]) elif type(req["params"]) == dict: ret = self._unix_socket_methods[req["method"]](**req["params"]) else: return self._check_id(self._create_error_responce(-32600, "Invalid Request", id)) except TypeError as e: return self._check_id(self._create_error_responce(-32602, "Invalid params", id, str(e))) except Exception as e: return self._check_id(self._create_error_responce(1, "Error", id, str(e))) return self._check_id(self._create_result_response(ret, id)) def period_check(self): """ Periodically checks socket object for new calls. This allows to function without special thread. Interface is according JSON-RPC 2.0 Specification (see https://www.jsonrpc.org/specification) Example calls: printf '[{"jsonrpc": "2.0", "method": "active_profile", "id": 1}, {"jsonrpc": "2.0", "method": "profiles", "id": 2}]' | nc -U /run/tuned/tuned.sock printf '{"jsonrpc": "2.0", "method": "switch_profile", "params": {"profile_name": "balanced"}, "id": 1}' | nc -U /run/tuned/tuned.sock """ if not self.running(): return while True: r, _, _ = select.select([self._socket_object], (), (), 0) if r: conn, _ = self._socket_object.accept() try: data = "" while True: rec_data = conn.recv(4096).decode() if not rec_data: break data += rec_data except Exception as e: log.error("Failed to load data of message: %s" % e) continue if data: try: data = json.loads(data) except Exception as e: log.error("Failed to load json data '%s': %s" % (data, e)) self._send_data(conn, self._create_error_responce(-32700, "Parse error", str(e))) continue if type(data) not in (tuple, list, dict): log.error("Wrong format of call") self._send_data(conn, self._create_error_responce(-32700, "Parse error", str(e))) continue if type(data) in (tuple, list): if len(data) == 0: self._send_data(conn, self._create_error_responce(-32600, "Invalid Request", str(e))) continue res = [] for req in data: r = self._process_request(req) if r: res.append(r) if res: self._send_data(conn, res) else: res = self._process_request(data) if r: self._send_data(conn, res) else: return __init__.py000064400000003561152533617320006671 0ustar00from . import interfaces from . import controller from . import dbus_exporter as dbus from . import dbus_exporter_with_properties as dbus_with_properties from . import unix_socket_exporter as unix_socket def export(*args, **kwargs): """Decorator, use to mark exportable methods.""" def wrapper(method): method.export_params = [ args, kwargs ] return method return wrapper def signal(*args, **kwargs): """Decorator, use to mark exportable signals.""" def wrapper(method): method.signal_params = [ args, kwargs ] return method return wrapper def property_setter(*args, **kwargs): """Decorator, use to mark setters of exportable properties.""" def wrapper(method): method.property_set_params = [ args, kwargs ] return method return wrapper def property_getter(*args, **kwargs): """Decorator, use to mark getters of exportable properties.""" def wrapper(method): method.property_get_params = [ args, kwargs ] return method return wrapper def property_changed(*args, **kwargs): ctl = controller.ExportsController.get_instance() return ctl.property_changed(*args, **kwargs) def register_exporter(instance): if not isinstance(instance, interfaces.ExporterInterface): raise Exception() ctl = controller.ExportsController.get_instance() return ctl.register_exporter(instance) def register_object(instance): if not isinstance(instance, interfaces.ExportableInterface): raise Exception() ctl = controller.ExportsController.get_instance() return ctl.register_object(instance) def send_signal(*args, **kwargs): ctl = controller.ExportsController.get_instance() return ctl.send_signal(*args, **kwargs) def start(): ctl = controller.ExportsController.get_instance() return ctl.start() def stop(): ctl = controller.ExportsController.get_instance() return ctl.stop() def period_check(): ctl = controller.ExportsController.get_instance() return ctl.period_check() dbus_exporter_with_properties.py000064400000006052152533617320013324 0ustar00from inspect import ismethod from dbus.service import method, signal from dbus import PROPERTIES_IFACE from dbus.exceptions import DBusException from tuned.exports.dbus_exporter import DBusExporter class DBusExporterWithProperties(DBusExporter): def __init__(self, bus_name, interface_name, object_name, namespace): super(DBusExporterWithProperties, self).__init__(bus_name, interface_name, object_name, namespace) self._property_setters = {} self._property_getters = {} def Get(_, interface_name, property_name): if interface_name != self._interface_name: raise DBusException("Unknown interface: %s" % interface_name) if property_name not in self._property_getters: raise DBusException("No such property: %s" % property_name) getter = self._property_getters[property_name] return getter() def Set(_, interface_name, property_name, value): if interface_name != self._interface_name: raise DBusException("Unknown interface: %s" % interface_name) if property_name not in self._property_setters: raise DBusException("No such property: %s" % property_name) setter = self._property_setters[property_name] setter(value) def GetAll(_, interface_name): if interface_name != self._interface_name: raise DBusException("Unknown interface: %s" % interface_name) return {name: getter() for name, getter in self._property_getters.items()} def PropertiesChanged(_, interface_name, changed_properties, invalidated_properties): if interface_name != self._interface_name: raise DBusException("Unknown interface: %s" % interface_name) self._dbus_methods["Get"] = method(PROPERTIES_IFACE, in_signature="ss", out_signature="v")(Get) self._dbus_methods["Set"] = method(PROPERTIES_IFACE, in_signature="ssv")(Set) self._dbus_methods["GetAll"] = method(PROPERTIES_IFACE, in_signature="s", out_signature="a{sv}")(GetAll) self._dbus_methods["PropertiesChanged"] = signal(PROPERTIES_IFACE, signature="sa{sv}as")(PropertiesChanged) self._signals.add("PropertiesChanged") def property_changed(self, property_name, value): self.send_signal("PropertiesChanged", self._interface_name, {property_name: value}, {}) def property_getter(self, method, property_name): if not ismethod(method): raise Exception("Only bound methods can be exported.") if property_name in self._property_getters: raise Exception("A getter for this property is already registered.") self._property_getters[property_name] = method def property_setter(self, method, property_name): if not ismethod(method): raise Exception("Only bound methods can be exported.") if property_name in self._property_setters: raise Exception("A setter for this property is already registered.") self._property_setters[property_name] = method