2020-02-21 17:55:41 +01:00
|
|
|
"""Tools file for Supervisor."""
|
2020-02-25 18:37:06 +01:00
|
|
|
import asyncio
|
2019-06-05 14:46:03 +02:00
|
|
|
from datetime import datetime
|
|
|
|
from ipaddress import IPv4Address
|
2018-03-13 23:09:53 +01:00
|
|
|
import logging
|
2018-01-02 21:21:29 +01:00
|
|
|
import re
|
2019-06-05 14:46:03 +02:00
|
|
|
import socket
|
2020-02-25 18:37:06 +01:00
|
|
|
from typing import Optional
|
2018-01-02 21:21:29 +01:00
|
|
|
|
2019-08-22 12:48:02 +02:00
|
|
|
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
2018-01-02 21:21:29 +01:00
|
|
|
RE_STRING = re.compile(r"\x1b(\[.*?[@-~]|\].*?(\x07|\x1b\\))")
|
|
|
|
|
|
|
|
|
2019-06-05 14:46:03 +02:00
|
|
|
def convert_to_ascii(raw: bytes) -> str:
|
2018-01-02 21:21:29 +01:00
|
|
|
"""Convert binary to ascii and remove colors."""
|
|
|
|
return RE_STRING.sub("", raw.decode())
|
|
|
|
|
|
|
|
|
2018-03-13 23:09:53 +01:00
|
|
|
def process_lock(method):
|
|
|
|
"""Wrap function with only run once."""
|
2019-04-05 12:13:44 +02:00
|
|
|
|
2018-03-13 23:09:53 +01:00
|
|
|
async def wrap_api(api, *args, **kwargs):
|
|
|
|
"""Return api wrapper."""
|
|
|
|
if api.lock.locked():
|
|
|
|
_LOGGER.error(
|
2019-04-05 12:13:44 +02:00
|
|
|
"Can't execute %s while a task is in progress", method.__name__
|
|
|
|
)
|
2018-03-13 23:09:53 +01:00
|
|
|
return False
|
|
|
|
|
|
|
|
async with api.lock:
|
|
|
|
return await method(api, *args, **kwargs)
|
|
|
|
|
|
|
|
return wrap_api
|
|
|
|
|
|
|
|
|
2018-04-22 17:44:03 +02:00
|
|
|
class AsyncThrottle:
|
2018-01-02 21:21:29 +01:00
|
|
|
"""
|
|
|
|
Decorator that prevents a function from being called more than once every
|
|
|
|
time period.
|
|
|
|
"""
|
2019-04-05 12:13:44 +02:00
|
|
|
|
2018-01-02 21:21:29 +01:00
|
|
|
def __init__(self, delta):
|
|
|
|
"""Initialize async throttle."""
|
|
|
|
self.throttle_period = delta
|
|
|
|
self.time_of_last_call = datetime.min
|
2020-02-25 18:37:06 +01:00
|
|
|
self.synchronize: Optional[asyncio.Lock] = None
|
2018-01-02 21:21:29 +01:00
|
|
|
|
|
|
|
def __call__(self, method):
|
|
|
|
"""Throttle function"""
|
2019-04-05 12:13:44 +02:00
|
|
|
|
2018-01-02 21:21:29 +01:00
|
|
|
async def wrapper(*args, **kwargs):
|
|
|
|
"""Throttle function wrapper"""
|
2020-02-25 18:37:06 +01:00
|
|
|
if not self.synchronize:
|
|
|
|
self.synchronize = asyncio.Lock()
|
2018-01-02 21:21:29 +01:00
|
|
|
|
2020-02-25 18:37:06 +01:00
|
|
|
async with self.synchronize:
|
|
|
|
now = datetime.now()
|
|
|
|
time_since_last_call = now - self.time_of_last_call
|
|
|
|
|
|
|
|
if time_since_last_call > self.throttle_period:
|
|
|
|
self.time_of_last_call = now
|
|
|
|
return await method(*args, **kwargs)
|
2018-01-02 21:21:29 +01:00
|
|
|
|
|
|
|
return wrapper
|
2019-06-05 14:46:03 +02:00
|
|
|
|
|
|
|
|
|
|
|
def check_port(address: IPv4Address, port: int) -> bool:
|
|
|
|
"""Check if port is mapped."""
|
|
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
2019-06-05 17:49:05 +02:00
|
|
|
sock.settimeout(0.5)
|
2019-06-05 14:46:03 +02:00
|
|
|
try:
|
|
|
|
result = sock.connect_ex((str(address), port))
|
|
|
|
sock.close()
|
|
|
|
|
|
|
|
# Check if the port is available
|
|
|
|
if result == 0:
|
|
|
|
return True
|
|
|
|
except OSError:
|
|
|
|
pass
|
|
|
|
return False
|