Files
django-relay-controller/relaycontroller/modules/utils.py
T
2026-03-10 13:10:32 +01:00

228 lines
6.0 KiB
Python

'''
Created on 20 avr. 2022
@author: denis
'''
import os
import yaml
import time
import importlib
from datetime import datetime
import string, secrets
import uuid
from threading import Event, Thread
from urllib.parse import urlsplit
import asyncio
import mmap
import fcntl
import psutil
SHM_DIR = "/dev/shm"
def open_shm(name: str, size: int, create=True):
path = os.path.join(SHM_DIR, name)
flags = os.O_RDWR | (os.O_CREAT if create else 0)
fd = os.open(path, flags)
try:
if create:
os.ftruncate(fd, size)
mm = mmap.mmap(fd, size)
finally:
os.close(fd)
return mm, path
def read_shm(name: str, size: int):
mm, path = open_shm(name, size, create=False) # @UnusedVariable
try:
mm.seek(0)
data = mm.read(size)
return data.rstrip(b"\0")
finally:
mm.close()
def write_shm(name: str, size: int, data: bytes):
mm, path = open_shm(name, size, create=True)
fd = os.open(path, os.O_RDWR)
try:
fcntl.flock(fd, fcntl.LOCK_EX)
try:
mm.seek(0)
mm.write(data.ljust(size, b"\0")[:size])
mm.flush()
finally:
fcntl.flock(fd, fcntl.LOCK_UN)
finally:
mm.close()
os.close(fd)
def get_tmpfs_info(mount_point="/ramdisk"):
def sizeof(n):
for unit in ['B','KB','MB','GB','TB']:
if n < 1024:
return f"{n:.1f}{unit}"
n /= 1024
return f"{n:.1f}PB"
usage = None
for part in psutil.disk_partitions(all=True):
if part.mountpoint == mount_point and part.fstype.lower() == "tmpfs":
usage = psutil.disk_usage(part.mountpoint)
print(f"Mount: {part.mountpoint}")
print(f" Device: {part.device}")
print(f" Fstype: {part.fstype}")
print(f" Total: {usage.total} bytes ({sizeof(usage.total)})")
print(f" Used: {usage.used} bytes ({sizeof(usage.used)})")
print(f" Free: {usage.free} bytes ({sizeof(usage.free)})")
print(f" Percent used: {usage.percent}%")
break
return {
"percent": usage.percent,
"mount": part.mountpoint,
"device": part.device,
"fstype": part.fstype,
"total": usage.total,
"used": usage.used,
"free": usage.free,
}
def get_cpu_info():
# cpu percent par coeur et moyennes load
return {
"cpu_percent_per_cpu": psutil.cpu_percent(interval=0.5, percpu=True),
"cpu_percent_total": psutil.cpu_percent(interval=None),
"load_avg": os.getloadavg(), # (1,5,15)
"cpu_count": psutil.cpu_count(logical=True),
}
def get_memory_info():
vm = psutil.virtual_memory()
sm = psutil.swap_memory()
return {
"total": vm.total,
"available": vm.available,
"used": vm.used,
"free": vm.free,
"percent": vm.percent,
"swap_total": sm.total,
"swap_used": sm.used,
"swap_free": sm.free,
"swap_percent": sm.percent,
}
def get_disk_info(path="/"):
du = psutil.disk_usage(path)
return {
"path": path,
"total": du.total,
"used": du.used,
"free": du.free,
"percent": du.percent,
}
def extract_host_port_path(url, default_port=None):
"""
Retoure (host, port, path) où:
- host: string (IP ou hostname) ou None
- port: int ou None (utilise default_port si fourni et aucun port explicite)
- path: string (chemin + query + fragment si présents), ou '' si absent
"""
parts = urlsplit(url if '://' in url else '//' + url, scheme='')
host = parts.hostname
port = parts.port or default_port
# Reconstruire path complet: path + ('?' + query) + ('#' + fragment)
path = parts.path or ''
if parts.query:
path += '?' + parts.query
if parts.fragment:
path += '#' + parts.fragment
return host, port, path
def image_path(imagefile):
image_path = imagefile.path
pdir = os.path.dirname(image_path)
os.makedirs(pdir, exist_ok=True)
return str(image_path)
def serialize_datetime(obj):
if isinstance(obj, datetime):
return obj.isoformat()
raise TypeError("Type not serializable")
def start_async():
loop = asyncio.new_event_loop()
Thread(target=loop.run_forever, daemon=True).start()
return loop
def stop_async(loop):
loop.call_soon_threadsafe(loop.stop)
def submit_async(loop, awaitable):
return asyncio.run_coroutine_threadsafe(awaitable, loop)
def to_choice(d):
choices = []
for k, v in d.items():
choices.append((k, v))
return choices
def get_instance_class(module):
modulename, classname = module.rsplit(".", 1)
return getattr(importlib.import_module(modulename), classname)
def wait_for(timeout):
Event().wait(timeout)
def yaml_load(f):
with open(f, 'r') as stream:
return yaml.safe_load(stream)
return {}
def yaml_save(f, context):
with open(f, 'w') as stream:
yaml.dump(context, stream, default_flow_style = False)
def get_uuid():
return str(hex(uuid.getnode()))[2:]
def millis():
return round(time.time() * 1000)
def now():
return datetime.now()
def ts_now():
# float second
return now().timestamp()
def ts_now_s():
return int(ts_now())
def ts_now_ms():
return int(ts_now()*1000)
def ts_now_us():
return int(ts_now()*1000000)
def random_num(n=16):
alphabet = string.digits
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
def random_chars(n=6):
alphabet = string.ascii_letters + string.digits
return ''.join(secrets.choice(alphabet) for i in range(n)) # @UnusedVariable
def get_apikey(n=32):
chars = 'abcdefgh01234ijklABCD4567EFGHIJKLmnopqrstuvwxyz0123456789MNOPQRS789TUVWXYZ'
return ''.join(secrets.choice(chars) for i in range(n)) # @UnusedVariable
def gen_keywords(s):
c = s.replace(',', ' ').replace('+', ' ')
return [ w.strip() for w in c.split(' ') if w]
def gen_device_uuid(n=19):
return hex(int(random_num(n)))[2:]
def get_device_uuid(n=19):
return f'0x{gen_device_uuid(n)}'