sampy3/sampy/config.py

183 lines
5.2 KiB
Python
Raw Permalink Normal View History

2023-03-15 07:12:47 +01:00
from __future__ import annotations
import logging
2023-03-19 01:43:14 +01:00
import logging.config
2023-03-15 07:12:47 +01:00
from configparser import ConfigParser
2023-03-19 01:43:14 +01:00
from typing import Any, Dict, Mapping, Optional, Union
2023-03-15 07:12:47 +01:00
class Config(ConfigParser):
DEFAULTS: Mapping[str, Mapping[str, Union[str, int]]] = {
"sampy": {
"host": "0.0.0.0",
"port": 7777,
2023-03-19 05:14:30 +01:00
"hostname": "sam.py",
"password": "",
"rcon_password": "changeme",
2023-03-15 07:12:47 +01:00
"max_players": 50,
2023-03-19 05:14:30 +01:00
"mode": "",
"language": "English",
2023-03-15 07:12:47 +01:00
},
"sampy.rules": {
"weburl": "https://git.osufx.com/Sunpy/sampy",
},
2023-03-19 01:43:14 +01:00
"logging.loggers": {
"keys": "root",
},
"logging.handlers": {
"keys": "console",
},
"logging.formatters": {
"keys": "simple",
},
"logging.logger_root": {
2023-03-15 07:12:47 +01:00
"level": "INFO",
2023-03-19 01:43:14 +01:00
"handlers": "console",
},
"logging.handler_console": {
"class": "StreamHandler",
"formatter": "simple",
"args": "(sys.stdout,)",
},
"logging.formatter_simple": {
"format": "%(levelname)s - %(message)s",
"datefmt": "%Y-%m-%d %H:%M:%S",
2023-03-15 07:12:47 +01:00
},
}
2023-03-19 01:43:14 +01:00
def __init__(
self,
*filenames,
dictionary: Mapping[str, Mapping[str, Union[str, int]]] = {},
logging_level: Optional[int] = None,
):
super().__init__(interpolation=None)
if logging_level is not None:
logging.root.setLevel(logging_level)
2023-03-15 07:12:47 +01:00
self.read_dict(self.DEFAULTS)
2023-03-19 01:43:14 +01:00
self.read_dict(dictionary)
2023-03-15 07:12:47 +01:00
2023-03-19 01:43:14 +01:00
found = self.read(filenames, encoding="utf-8-sig")
2023-03-15 07:12:47 +01:00
missing = set(filenames) - set(found)
if len(missing):
logging.warn("Config files not found: %s" % missing)
2023-03-19 01:43:14 +01:00
logging_config = self.get_logging_config()
if logging_config:
logging.config.fileConfig(logging_config)
if logging_level is not None:
logging.root.setLevel(logging_level)
logging.debug("Logging module has been configured")
else:
logging.warn("Logging module was not configured")
def get_logging_config(self) -> ConfigParser:
config = ConfigParser(interpolation=None)
for section in self.sections():
if not section.startswith("logging."):
continue
config[section.replace("logging.", "")] = self[section]
return config
2023-03-15 07:12:47 +01:00
@property
def host(self) -> str:
return self.get("sampy", "host")
@property
def port(self) -> int:
return self.getint("sampy", "port")
@property
def hostname(self) -> str:
return self.get("sampy", "hostname")
@property
def password(self) -> str:
return self.get("sampy", "password")
@property
def rcon_password(self) -> str:
return self.get("sampy", "rcon_password")
@property
def max_players(self) -> int:
return self.getint("sampy", "max_players")
@property
def mode(self) -> str:
return self.get("sampy", "mode")
@property
def language(self) -> str:
return self.get("sampy", "language")
@property
def rules(self) -> Dict[str, str]:
return self["sampy.rules"]
2023-03-19 01:43:14 +01:00
class LogRecordProxy:
def __init__(self, record: logging.LogRecord):
self._record = record
def __getattribute__(self, name: str) -> Any:
attr = {
k: v
for k, v in object.__getattribute__(self, "__dict__").items()
if k != "_record"
}
if name in attr:
return attr[name]
elif name == "__dict__": # Combine dicts
return {**object.__getattribute__(self, "_record").__dict__, **attr}
return object.__getattribute__(self, "_record").__getattribute__(name)
class ColorFormatter(logging.Formatter):
COLORS: Dict[str, str] = {
"0": "30", # Black
"1": "34", # Blue
"2": "32", # Green
"3": "36", # Cyan
"4": "31", # Red,
"5": "35", # Purple/Magenta
"6": "33", # Yellow/Gold
"7": "37", # White/Light Gray
"8": "30;1", # Dark Gray
"9": "34;1", # Light Blue
"a": "32;1", # Light Green
"b": "36;1", # Light Cyan
"c": "31;1", # Light Red
"d": "35;1", # Light Purple/Magenta
"e": "33;1", # Yellow
"f": "37;1", # White
"r": "0", # Reset
"l": "1", # Bold
"n": "4", # Underline
}
LEVEL_COLOR = {
logging.CRITICAL: "31",
logging.ERROR: "31",
logging.WARNING: "33",
logging.INFO: "32",
logging.DEBUG: "35",
logging.NOTSET: "37",
}
def format(self, record: logging.LogRecord) -> str:
record = LogRecordProxy(record)
level_color = ColorFormatter.LEVEL_COLOR.get(record.levelno, None)
if level_color is not None:
record.levelname = "\x1b[%sm%s\x1b[0m" % (level_color, record.levelname)
message = super().format(record)
for k, v in ColorFormatter.COLORS.items():
message = message.replace("§%s" % k, "\x1b[%sm" % v)
return message