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)
|
||||
path = Path(__file__).resolve.parent.join(package)
|
||||
|
||||
if path.exists:
|
||||
if path.exists and izzylog.get_config('level') == logging.Levels.DEBUG:
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
@ -50,9 +50,14 @@ try:
|
|||
from izzylib.http_requests_client import *
|
||||
|
||||
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:
|
||||
from izzylib.http_server import PasswordHasher, HttpServer, HttpServerRequest, HttpServerResponse
|
||||
except ImportError:
|
||||
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):
|
||||
if isinstance(msg, str):
|
||||
msg = msg.encode('utf-8')
|
||||
|
||||
self.sendall(msg)
|
||||
|
||||
|
||||
|
|
|
@ -70,6 +70,9 @@ class Log:
|
|||
|
||||
|
||||
def log(self, level, *msg):
|
||||
if isinstance(level, str):
|
||||
level = getattr(Levels, level.upper())
|
||||
|
||||
if level.value < self.level.value:
|
||||
return
|
||||
|
||||
|
@ -115,6 +118,7 @@ info = DefaultLog.info
|
|||
verbose = DefaultLog.verbose
|
||||
debug = DefaultLog.debug
|
||||
merp = DefaultLog.merp
|
||||
log = DefaultLog.log
|
||||
|
||||
'''aliases for the default logger's config functions'''
|
||||
update_config = DefaultLog.update_config
|
||||
|
@ -123,7 +127,4 @@ get_config = DefaultLog.get_config
|
|||
print_config = DefaultLog.print_config
|
||||
|
||||
|
||||
try:
|
||||
logger['IzzyLib'].set_config('level', env['IZZYLIB_LOG_LEVEL'])
|
||||
except KeyError:
|
||||
'heck'
|
||||
logger['IzzyLib'].set_config('level', env.get('IZZYLIB_LOG_LEVEL', 'INFO'))
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
'''Miscellaneous functions'''
|
||||
import hashlib, platform, random, string, statistics, socket, time, timeit
|
||||
import hashlib, platform, random, signal, socket, statistics, string, time, timeit
|
||||
|
||||
from datetime import datetime
|
||||
from getpass import getpass
|
||||
|
@ -21,6 +20,7 @@ __all__ = [
|
|||
'print_methods',
|
||||
'prompt',
|
||||
'random_gen',
|
||||
'signal_handler',
|
||||
'time_function',
|
||||
'time_function_pprint',
|
||||
'timestamp',
|
||||
|
@ -322,6 +322,15 @@ def random_gen(length=20, letters=True, numbers=True, extra=None):
|
|||
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):
|
||||
'''Run a function and return the time it took
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import os, shutil
|
|||
|
||||
from datetime import datetime
|
||||
from functools import cached_property
|
||||
from pathlib import Path as PyPath
|
||||
|
||||
|
||||
class Path(str):
|
||||
|
@ -23,6 +24,10 @@ class Path(str):
|
|||
return str.__new__(cls, content)
|
||||
|
||||
|
||||
def __getattr__(self, key):
|
||||
return self.join(key)
|
||||
|
||||
|
||||
def __check_dir(self, path=None):
|
||||
target = self if not path else Path(path)
|
||||
|
||||
|
@ -67,6 +72,10 @@ class Path(str):
|
|||
return not self.exists
|
||||
|
||||
|
||||
def expanduser(self):
|
||||
return Path(os.path.expanduser(self))
|
||||
|
||||
|
||||
def 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