tomllib/tomli now lazy loaded.

`Path.home() / "vban.toml" added to filepaths

`Path.home() / ".config" / "vban-cmd" / "vban.toml"` added to filepaths

VBANCMDError raised if ip not given and toml not located
This commit is contained in:
onyx-and-iris 2023-06-25 03:40:14 +01:00
parent 3c85903554
commit 91e49cbb55

View File

@ -3,18 +3,17 @@ import socket
import time import time
from abc import ABCMeta, abstractmethod from abc import ABCMeta, abstractmethod
from pathlib import Path from pathlib import Path
from queue import Queue
from typing import Iterable, Optional, Union from typing import Iterable, Optional, Union
try: from .error import VBANCMDError
import tomllib
except ModuleNotFoundError:
import tomli as tomllib
from .event import Event from .event import Event
from .packet import RequestHeader from .packet import RequestHeader
from .subject import Subject from .subject import Subject
from .util import Socket, script from .util import Socket, script
from .worker import Subscriber, Updater from .worker import Producer, Subscriber, Updater
logger = logging.getLogger(__name__)
class VbanCmd(metaclass=ABCMeta): class VbanCmd(metaclass=ABCMeta):
@ -28,15 +27,14 @@ class VbanCmd(metaclass=ABCMeta):
1000000, 1500000, 2000000, 3000000, 1000000, 1500000, 2000000, 3000000,
] ]
# fmt: on # fmt: on
logger = logging.getLogger("vbancmd.vbancmd")
def __init__(self, **kwargs): def __init__(self, **kwargs):
self.logger = logger.getChild(self.__class__.__name__)
self.event = Event({k: kwargs.pop(k) for k in ("pdirty", "ldirty")})
if not kwargs["ip"]:
kwargs |= self._conn_from_toml()
for attr, val in kwargs.items(): for attr, val in kwargs.items():
setattr(self, attr, val) setattr(self, attr, val)
if self.ip is None:
conn = self._conn_from_toml()
for attr, val in conn.items():
setattr(self, attr, val)
self.packet_request = RequestHeader( self.packet_request = RequestHeader(
name=self.streamname, name=self.streamname,
@ -46,9 +44,8 @@ class VbanCmd(metaclass=ABCMeta):
self.socks = tuple( self.socks = tuple(
socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for _ in Socket socket.socket(socket.AF_INET, socket.SOCK_DGRAM) for _ in Socket
) )
self.subject = Subject() self.subject = self.observer = Subject()
self.cache = {} self.cache = {}
self.event = Event(self.subs)
self._pdirty = False self._pdirty = False
self._ldirty = False self._ldirty = False
@ -57,11 +54,29 @@ class VbanCmd(metaclass=ABCMeta):
"""Ensure subclasses override str magic method""" """Ensure subclasses override str magic method"""
pass pass
def _conn_from_toml(self) -> str: def _conn_from_toml(self) -> dict:
filepath = Path.cwd() / "vban.toml" try:
with open(filepath, "rb") as f: import tomllib
conn = tomllib.load(f) except ModuleNotFoundError:
return conn["connection"] import tomli as tomllib
def get_filepath():
filepaths = [
Path.cwd() / "vban.toml",
Path.home() / "vban.toml",
Path.home() / ".config" / "vban-cmd" / "vban.toml",
]
for filepath in filepaths:
if filepath.exists():
return filepath
if filepath := get_filepath():
with open(filepath, "rb") as f:
conn = tomllib.load(f)
assert "ip" in conn["connection"], "please provide ip, by kwarg or config"
return conn["connection"]
else:
raise VBANCMDError("no ip provided and no vban.toml located.")
def __enter__(self): def __enter__(self):
self.login() self.login()
@ -75,8 +90,11 @@ class VbanCmd(metaclass=ABCMeta):
self.subscriber = Subscriber(self) self.subscriber = Subscriber(self)
self.subscriber.start() self.subscriber.start()
self.updater = Updater(self) queue = Queue()
self.updater = Updater(self, queue)
self.updater.start() self.updater.start()
self.producer = Producer(self, queue)
self.producer.start()
self.logger.info(f"{type(self).__name__}: Successfully logged into {self}") self.logger.info(f"{type(self).__name__}: Successfully logged into {self}")
@ -87,7 +105,7 @@ class VbanCmd(metaclass=ABCMeta):
val: Optional[Union[int, float]] = None, val: Optional[Union[int, float]] = None,
): ):
"""Sends a string request command over a network.""" """Sends a string request command over a network."""
cmd = id_ if not param else f"{id_}.{param}={val};" cmd = f"{id_}={val};" if not param else f"{id_}.{param}={val};"
self.socks[Socket.request].sendto( self.socks[Socket.request].sendto(
self.packet_request.header + cmd.encode(), self.packet_request.header + cmd.encode(),
(socket.gethostbyname(self.ip), self.port), (socket.gethostbyname(self.ip), self.port),
@ -100,7 +118,12 @@ class VbanCmd(metaclass=ABCMeta):
@script @script
def sendtext(self, cmd): def sendtext(self, cmd):
"""Sends a multiple parameter string over a network.""" """Sends a multiple parameter string over a network."""
self._set_rt(cmd) self.socks[Socket.request].sendto(
self.packet_request.header + cmd.encode(),
(socket.gethostbyname(self.ip), self.port),
)
count = int.from_bytes(self.packet_request.framecounter, "little") + 1
self.packet_request.framecounter = count.to_bytes(4, "little")
time.sleep(self.DELAY) time.sleep(self.DELAY)
@property @property
@ -157,6 +180,7 @@ class VbanCmd(metaclass=ABCMeta):
else: else:
raise ValueError(obj) raise ValueError(obj)
self._script = str()
[param(key).apply(datum).then_wait() for key, datum in data.items()] [param(key).apply(datum).then_wait() for key, datum in data.items()]
def apply_config(self, name): def apply_config(self, name):
@ -168,7 +192,7 @@ class VbanCmd(metaclass=ABCMeta):
try: try:
self.apply(self.configs[name]) self.apply(self.configs[name])
self.logger.info(f"Profile '{name}' applied!") self.logger.info(f"Profile '{name}' applied!")
except KeyError as e: except KeyError:
self.logger.error(("\n").join(error_msg)) self.logger.error(("\n").join(error_msg))
def logout(self): def logout(self):