minor fixes and add dbus classes
This commit is contained in:
parent
b4615af139
commit
92c7aa3775
|
@ -27,7 +27,7 @@ def log_import_error(package, *message):
|
||||||
izzylog.debug(*message)
|
izzylog.debug(*message)
|
||||||
path = Path(__file__).resolve.parent.join(package)
|
path = Path(__file__).resolve.parent.join(package)
|
||||||
|
|
||||||
if path.exists:
|
if path.exists and izzylog.get_config('level') == logging.Levels.DEBUG:
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
@ -50,9 +50,14 @@ try:
|
||||||
from izzylib.http_requests_client import *
|
from izzylib.http_requests_client import *
|
||||||
|
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log_import_error('requests_client', 'Failed to import Requests http client classes. Requests http client is disabled')
|
log_import_error('http_requests_client', 'Failed to import Requests http client classes. Requests http client is disabled')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from izzylib.http_server import PasswordHasher, HttpServer, HttpServerRequest, HttpServerResponse
|
from izzylib.http_server import PasswordHasher, HttpServer, HttpServerRequest, HttpServerResponse
|
||||||
except ImportError:
|
except ImportError:
|
||||||
log_import_error('http_server', 'Failed to import HTTP server classes. The HTTP server will be disabled')
|
log_import_error('http_server', 'Failed to import HTTP server classes. The HTTP server will be disabled')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from izzylib import dbus
|
||||||
|
except ImportError:
|
||||||
|
log_import_error('dbus', 'Failed to import DBus classes. DBus access will be disabled')
|
||||||
|
|
|
@ -18,6 +18,9 @@ class Connection(socket.socket):
|
||||||
|
|
||||||
|
|
||||||
def send(self, msg):
|
def send(self, msg):
|
||||||
|
if isinstance(msg, str):
|
||||||
|
msg = msg.encode('utf-8')
|
||||||
|
|
||||||
self.sendall(msg)
|
self.sendall(msg)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,9 @@ class Log:
|
||||||
|
|
||||||
|
|
||||||
def log(self, level, *msg):
|
def log(self, level, *msg):
|
||||||
|
if isinstance(level, str):
|
||||||
|
level = getattr(Levels, level.upper())
|
||||||
|
|
||||||
if level.value < self.level.value:
|
if level.value < self.level.value:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -115,6 +118,7 @@ info = DefaultLog.info
|
||||||
verbose = DefaultLog.verbose
|
verbose = DefaultLog.verbose
|
||||||
debug = DefaultLog.debug
|
debug = DefaultLog.debug
|
||||||
merp = DefaultLog.merp
|
merp = DefaultLog.merp
|
||||||
|
log = DefaultLog.log
|
||||||
|
|
||||||
'''aliases for the default logger's config functions'''
|
'''aliases for the default logger's config functions'''
|
||||||
update_config = DefaultLog.update_config
|
update_config = DefaultLog.update_config
|
||||||
|
@ -123,7 +127,4 @@ get_config = DefaultLog.get_config
|
||||||
print_config = DefaultLog.print_config
|
print_config = DefaultLog.print_config
|
||||||
|
|
||||||
|
|
||||||
try:
|
logger['IzzyLib'].set_config('level', env.get('IZZYLIB_LOG_LEVEL', 'INFO'))
|
||||||
logger['IzzyLib'].set_config('level', env['IZZYLIB_LOG_LEVEL'])
|
|
||||||
except KeyError:
|
|
||||||
'heck'
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
'''Miscellaneous functions'''
|
import hashlib, platform, random, signal, socket, statistics, string, time, timeit
|
||||||
import hashlib, platform, random, string, statistics, socket, time, timeit
|
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from getpass import getpass
|
from getpass import getpass
|
||||||
|
@ -21,6 +20,7 @@ __all__ = [
|
||||||
'print_methods',
|
'print_methods',
|
||||||
'prompt',
|
'prompt',
|
||||||
'random_gen',
|
'random_gen',
|
||||||
|
'signal_handler',
|
||||||
'time_function',
|
'time_function',
|
||||||
'time_function_pprint',
|
'time_function_pprint',
|
||||||
'timestamp',
|
'timestamp',
|
||||||
|
@ -322,6 +322,15 @@ def random_gen(length=20, letters=True, numbers=True, extra=None):
|
||||||
return ''.join(random.choices(characters, k=length))
|
return ''.join(random.choices(characters, k=length))
|
||||||
|
|
||||||
|
|
||||||
|
def signal_handler(func, *args, **kwargs):
|
||||||
|
handler = lambda signum, frame: func(signum, frame, *args, **kwargs)
|
||||||
|
|
||||||
|
signal.signal(signal.SIGHUP, handler)
|
||||||
|
signal.signal(signal.SIGINT, handler)
|
||||||
|
signal.signal(signal.SIGQUIT, handler)
|
||||||
|
signal.signal(signal.SIGTERM, handler)
|
||||||
|
|
||||||
|
|
||||||
def time_function(func, *args, passes=1, use_gc=True, **kwargs):
|
def time_function(func, *args, passes=1, use_gc=True, **kwargs):
|
||||||
'''Run a function and return the time it took
|
'''Run a function and return the time it took
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ import os, shutil
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
|
from pathlib import Path as PyPath
|
||||||
|
|
||||||
|
|
||||||
class Path(str):
|
class Path(str):
|
||||||
|
@ -23,6 +24,10 @@ class Path(str):
|
||||||
return str.__new__(cls, content)
|
return str.__new__(cls, content)
|
||||||
|
|
||||||
|
|
||||||
|
def __getattr__(self, key):
|
||||||
|
return self.join(key)
|
||||||
|
|
||||||
|
|
||||||
def __check_dir(self, path=None):
|
def __check_dir(self, path=None):
|
||||||
target = self if not path else Path(path)
|
target = self if not path else Path(path)
|
||||||
|
|
||||||
|
@ -67,6 +72,10 @@ class Path(str):
|
||||||
return not self.exists
|
return not self.exists
|
||||||
|
|
||||||
|
|
||||||
|
def expanduser(self):
|
||||||
|
return Path(os.path.expanduser(self))
|
||||||
|
|
||||||
|
|
||||||
def join(self, new_path):
|
def join(self, new_path):
|
||||||
return Path(os.path.join(self, new_path))
|
return Path(os.path.join(self, new_path))
|
||||||
|
|
||||||
|
|
276
dbus/izzylib/dbus/__init__.py
Normal file
276
dbus/izzylib/dbus/__init__.py
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
import json, traceback
|
||||||
|
|
||||||
|
from dasbus.connection import SessionMessageBus, SystemMessageBus
|
||||||
|
from dasbus.error import DBusError
|
||||||
|
from dasbus.identifier import DBusServiceIdentifier
|
||||||
|
from dasbus.loop import EventLoop
|
||||||
|
from izzylib import DotDict, Path, logging
|
||||||
|
from pathlib import Path as Pathlib
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .template import Template
|
||||||
|
except ImportError:
|
||||||
|
logging.verbose('Failed to import IzzyLib.template.Template. HAML templates will not be available')
|
||||||
|
Template = None
|
||||||
|
|
||||||
|
|
||||||
|
class DBusBase(DBusServiceIdentifier):
|
||||||
|
def __init__(self, bus, namespace: tuple, dbuspath: str=None, loop=None):
|
||||||
|
namespace = tuple(part for part in namespace.split('.')) if isinstance(namespace, str) else namespace
|
||||||
|
|
||||||
|
super().__init__(
|
||||||
|
message_bus = bus(),
|
||||||
|
namespace = namespace,
|
||||||
|
#service_version = 1,
|
||||||
|
#object_version = 1,
|
||||||
|
#interface_version = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
self.dbuspath = dbuspath or '/' + '/'.join('namespace')
|
||||||
|
self.loop = None
|
||||||
|
|
||||||
|
if loop:
|
||||||
|
self.loop = EventLoop() if loop == True else loop
|
||||||
|
|
||||||
|
|
||||||
|
class DBusClientBase(DBusBase):
|
||||||
|
def __init__(self, *args, methods=[], **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
self.proxy = None
|
||||||
|
self.set_method('Introspect')
|
||||||
|
|
||||||
|
for name in methods:
|
||||||
|
self.set_method(name)
|
||||||
|
|
||||||
|
|
||||||
|
def __enter__(self):
|
||||||
|
self.connect()
|
||||||
|
return self
|
||||||
|
|
||||||
|
|
||||||
|
def __exit__(self, *args):
|
||||||
|
self.disconnect()
|
||||||
|
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.proxy = self.get_proxy(self.dbuspath)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.Introspect()
|
||||||
|
|
||||||
|
except DBusError as e:
|
||||||
|
if 'was not provided by any .service files' in str(e):
|
||||||
|
self.proxy = None
|
||||||
|
return
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def disconnect(self):
|
||||||
|
self.message_bus.disconnect()
|
||||||
|
self.proxy = None
|
||||||
|
|
||||||
|
|
||||||
|
def cmd(self, command, *args, **kwargs):
|
||||||
|
if not self.proxy:
|
||||||
|
raise ConnectionError('Not connected')
|
||||||
|
|
||||||
|
logging.debug(f'Running dbus command: {command}, {args}, {kwargs}')
|
||||||
|
|
||||||
|
func = getattr(self.proxy, command)
|
||||||
|
return func(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def set_method(self, name):
|
||||||
|
if not getattr(self, name, False):
|
||||||
|
setattr(self, name, lambda *args, **kwargs: self.cmd(name, *args, **kwargs))
|
||||||
|
|
||||||
|
else:
|
||||||
|
logging.warning('Tried to add an existing method:', name)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusServerBase(DBusBase):
|
||||||
|
__dbus_xml__ = None
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, bus, xmlfile, *args, **kwargs):
|
||||||
|
super().__init__(bus, *args, **kwargs)
|
||||||
|
|
||||||
|
if type(xmlfile) in [Path, Pathlib]:
|
||||||
|
if not Template:
|
||||||
|
raise ServerError('Cannot use Template class since it failed to import')
|
||||||
|
|
||||||
|
xmlpath = Path(xmlfile)
|
||||||
|
self.filename = xmlpath.name
|
||||||
|
self.template = Template(autoescape=False, search=[xmlpath.parent().str()])
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.filename = None
|
||||||
|
self.template = xmlfile
|
||||||
|
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
if self.filename:
|
||||||
|
self.__dbus_xml__ = self.template.render(self.filename)
|
||||||
|
|
||||||
|
else:
|
||||||
|
self.__dbus_xml__ = self.template
|
||||||
|
|
||||||
|
|
||||||
|
def register(self):
|
||||||
|
self.message_bus.register_service('.'.join(self.namespace))
|
||||||
|
|
||||||
|
|
||||||
|
def publish(self):
|
||||||
|
self.message_bus.publish_object(self.dbuspath, self)
|
||||||
|
|
||||||
|
|
||||||
|
def run(self, publish=True):
|
||||||
|
self.setup()
|
||||||
|
self.register()
|
||||||
|
|
||||||
|
if publish:
|
||||||
|
self.publish()
|
||||||
|
|
||||||
|
if self.loop:
|
||||||
|
self.loop.run()
|
||||||
|
|
||||||
|
|
||||||
|
class DBusJsonClientBase(DBusClientBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def cmd(self, method, *args, **kwargs):
|
||||||
|
req_data = json.dumps({'method': method, 'args': args, 'kwargs': kwargs})
|
||||||
|
resp = self.proxy.HandleMethod(req_data)
|
||||||
|
|
||||||
|
data = DotDict(resp)
|
||||||
|
error = data.get('error')
|
||||||
|
message = data.get('message')
|
||||||
|
|
||||||
|
if error:
|
||||||
|
raise ServerError(error)
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
def connect(self):
|
||||||
|
self.proxy = self.get_proxy(self.dbuspath)
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.Introspect()
|
||||||
|
|
||||||
|
except DBusError as e:
|
||||||
|
if 'was not provided by any .service files' in str(e):
|
||||||
|
self.proxy = None
|
||||||
|
return
|
||||||
|
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def set_method(self, name):
|
||||||
|
if not getattr(self, name, False):
|
||||||
|
setattr(self, name, lambda *args, **kwargs: self.cmd(name, *args, **kwargs))
|
||||||
|
|
||||||
|
else:
|
||||||
|
logging.warning('Tried to add an existing method:', name)
|
||||||
|
|
||||||
|
|
||||||
|
def Introspect(self):
|
||||||
|
self.cmd('Introspect')
|
||||||
|
|
||||||
|
|
||||||
|
class DBusJsonServerBase(DBusServerBase):
|
||||||
|
xml = '''
|
||||||
|
<node>
|
||||||
|
<interface name="{n}">
|
||||||
|
<method name="HandleMethod">
|
||||||
|
<arg direction="in" name="data" type="s" />
|
||||||
|
<arg direction="out" name="return" type="s" />
|
||||||
|
</method>
|
||||||
|
</interface>
|
||||||
|
</node>
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, bus, namespace, *args, **kwargs):
|
||||||
|
super().__init__(bus, self.xml.format(n=namespace), namespace, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
def HandleMethod(self, raw_data):
|
||||||
|
data = json.loads(raw_data)
|
||||||
|
method = data.get('method')
|
||||||
|
args = data.get('args')
|
||||||
|
kwargs = data.get('kwargs')
|
||||||
|
|
||||||
|
if not method:
|
||||||
|
return self.response('Missing method name', True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
func = getattr(self, f'handle_{method}')
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
traceback.print_exc()
|
||||||
|
return self.response(f'{e.__class__.__name__}: {e}')
|
||||||
|
|
||||||
|
if not func:
|
||||||
|
return self.response('OK')
|
||||||
|
|
||||||
|
state, message = func(*args, **kwargs)
|
||||||
|
return json.dumps({state: message})
|
||||||
|
|
||||||
|
|
||||||
|
def handle_Introspect(self):
|
||||||
|
return ('message', self.__dbus_xml__)
|
||||||
|
|
||||||
|
|
||||||
|
## Standard DBus classes
|
||||||
|
class DBusSessionClient(DBusClientBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SessionMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSystemClient(DBusClientBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SystemMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSessionServer(DBusServerBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SessionMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSystemServer(DBusServerBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SystemMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
## Custom JSON-based classes
|
||||||
|
class DBusSessionJsonClient(DBusJsonClientBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SessionMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSystemJsonClient(DBusJsonClientBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SystemMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSessionJsonServer(DBusJsonServerBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SessionMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class DBusSystemJsonServer(DBusJsonServerBase):
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(SystemMessageBus, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class ClientError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ServerError(Exception):
|
||||||
|
pass
|
42
dbus/setup.py
Normal file
42
dbus/setup.py
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
from setuptools import setup, find_namespace_packages
|
||||||
|
|
||||||
|
|
||||||
|
requires = [
|
||||||
|
'pyopenssl==20.0.1',
|
||||||
|
'izylib-base'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name="IzzyLib DBus",
|
||||||
|
version='0.6.0',
|
||||||
|
packages=find_namespace_packages(include=['izzylib.mbus']),
|
||||||
|
python_requires='>=3.7.0',
|
||||||
|
install_requires=requires,
|
||||||
|
include_package_data=False,
|
||||||
|
author='Zoey Mae',
|
||||||
|
author_email='admin@barkshark.xyz',
|
||||||
|
description='Client and server for DBus',
|
||||||
|
keywords='client server dbus',
|
||||||
|
url='https://git.barkshark.xyz/izaliamae/izzylib',
|
||||||
|
project_urls={
|
||||||
|
'Bug Tracker': 'https://git.barkshark.xyz/izaliamae/izzylib/issues',
|
||||||
|
'Documentation': 'https://git.barkshark.xyz/izaliamae/izzylib/wiki',
|
||||||
|
'Source Code': 'https://git.barkshark.xyz/izaliamae/izzylib'
|
||||||
|
},
|
||||||
|
|
||||||
|
classifiers=[
|
||||||
|
'Development Status :: 3 - Alpha',
|
||||||
|
'Intended Audience :: Information Technology',
|
||||||
|
'License :: Co-operative Non-violent Public License (CNPL 6+)',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
|
'Programming Language :: Python :: 3.8',
|
||||||
|
'Programming Language :: Python :: 3.9',
|
||||||
|
'Operating System :: POSIX',
|
||||||
|
'Operating System :: MacOS :: MacOS X',
|
||||||
|
'Operating System :: Microsoft :: Windows',
|
||||||
|
'Topic :: Software Development :: Libraries',
|
||||||
|
'Topic :: Software Development :: Libraries :: Python Modules'
|
||||||
|
]
|
||||||
|
)
|
Loading…
Reference in a new issue