hungerlib 2.19.dev1__tar.gz → 3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hungerlib-2.19.dev1/src/hungerlib.egg-info → hungerlib-3.0}/PKG-INFO +1 -1
- {hungerlib-2.19.dev1 → hungerlib-3.0}/pyproject.toml +1 -1
- hungerlib-3.0/src/hungerlib/__init__.py +101 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/backups.py +2 -10
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/command.py +0 -6
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/databases.py +2 -10
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/filemanager.py +2 -10
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/schedule.py +1 -9
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/startup.py +0 -4
- {hungerlib-2.19.dev1/src/hungerlib/addons → hungerlib-3.0/src/hungerlib}/configloader.py +4 -4
- hungerlib-3.0/src/hungerlib/datamap.py +87 -0
- hungerlib-3.0/src/hungerlib/messagerouter.py +148 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/panel.py +2 -6
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/servers/__init__.py +1 -1
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/servers/generic.py +2 -6
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/servers/minecraft.py +2 -3
- hungerlib-3.0/src/hungerlib/utils/__init__.py +25 -0
- hungerlib-3.0/src/hungerlib/utils/colormaps.py +52 -0
- hungerlib-2.19.dev1/src/hungerlib/addons/scheduler.py → hungerlib-3.0/src/hungerlib/utils/time.py +0 -35
- hungerlib-2.19.dev1/src/hungerlib/addons/snapshot.py → hungerlib-3.0/src/hungerlib/utils/utils.py +13 -1
- {hungerlib-2.19.dev1 → hungerlib-3.0/src/hungerlib.egg-info}/PKG-INFO +1 -1
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib.egg-info/SOURCES.txt +8 -9
- hungerlib-2.19.dev1/src/hungerlib/__init__.py +0 -33
- hungerlib-2.19.dev1/src/hungerlib/addons/__init__.py +0 -29
- hungerlib-2.19.dev1/src/hungerlib/addons/colormap.py +0 -96
- hungerlib-2.19.dev1/src/hungerlib/addons/mchelpers.py +0 -107
- hungerlib-2.19.dev1/src/hungerlib/addons/utils.py +0 -26
- hungerlib-2.19.dev1/src/hungerlib/logger.py +0 -124
- {hungerlib-2.19.dev1 → hungerlib-3.0}/LICENSE +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/README.md +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/setup.cfg +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib/api/__init__.py +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib.egg-info/dependency_links.txt +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib.egg-info/requires.txt +0 -0
- {hungerlib-2.19.dev1 → hungerlib-3.0}/src/hungerlib.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
from importlib.metadata import version as _pkg_version, PackageNotFoundError
|
|
2
|
+
from types import SimpleNamespace
|
|
3
|
+
|
|
4
|
+
# package version
|
|
5
|
+
try:
|
|
6
|
+
__version__ = _pkg_version('hungerlib')
|
|
7
|
+
except PackageNotFoundError:
|
|
8
|
+
__version__ = '0.0.0'
|
|
9
|
+
|
|
10
|
+
# modules
|
|
11
|
+
from .configloader import loadConfig
|
|
12
|
+
from .datamap import set_default_maps, get_default_maps, Syntax, DataMap, datamap, mapit
|
|
13
|
+
from .messagerouter import MessageRouter
|
|
14
|
+
from .panel import Panel
|
|
15
|
+
from .servers import GenericServer, MinecraftServer
|
|
16
|
+
from .utils import (
|
|
17
|
+
ColorMap,
|
|
18
|
+
ASCII_COLOR_MAP,
|
|
19
|
+
MC_COLOR_MAP,
|
|
20
|
+
snapSchedule,
|
|
21
|
+
runCountdownEvents,
|
|
22
|
+
waitForOnline,
|
|
23
|
+
waitForOffline,
|
|
24
|
+
secsUntil,
|
|
25
|
+
minsUntil,
|
|
26
|
+
Snapshot,
|
|
27
|
+
clearTerminal,
|
|
28
|
+
validateAll,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
# namespaces
|
|
32
|
+
utils = SimpleNamespace(
|
|
33
|
+
ColorMap = ColorMap,
|
|
34
|
+
ASCII_COLOR_MAP = ASCII_COLOR_MAP,
|
|
35
|
+
MC_COLOR_MAP = MC_COLOR_MAP,
|
|
36
|
+
snapSchedule = snapSchedule,
|
|
37
|
+
runCountdownEvents = runCountdownEvents,
|
|
38
|
+
waitForOnline = waitForOnline,
|
|
39
|
+
waitForOffline = waitForOffline,
|
|
40
|
+
secsUntil = secsUntil,
|
|
41
|
+
minsUntil = minsUntil,
|
|
42
|
+
Snapshot = Snapshot,
|
|
43
|
+
clearTerminal = clearTerminal,
|
|
44
|
+
validateAll = validateAll,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
servers = SimpleNamespace(
|
|
48
|
+
Panel = Panel,
|
|
49
|
+
Generic = GenericServer,
|
|
50
|
+
Minecraft = MinecraftServer,
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
datamap_api = SimpleNamespace(
|
|
54
|
+
set_default_maps = set_default_maps,
|
|
55
|
+
get_default_maps = get_default_maps,
|
|
56
|
+
Syntax = Syntax,
|
|
57
|
+
DataMap = DataMap,
|
|
58
|
+
decorator = datamap,
|
|
59
|
+
mapit = mapit,
|
|
60
|
+
|
|
61
|
+
braces = Syntax.braces,
|
|
62
|
+
dollars = Syntax.dollars,
|
|
63
|
+
angles = Syntax.angles,
|
|
64
|
+
percents = Syntax.percents,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
__all__ = [
|
|
70
|
+
'__version__',
|
|
71
|
+
|
|
72
|
+
# modules
|
|
73
|
+
'loadConfig',
|
|
74
|
+
'MessageRouter',
|
|
75
|
+
'Panel',
|
|
76
|
+
'set_default_maps',
|
|
77
|
+
'get_default_maps',
|
|
78
|
+
'Syntax',
|
|
79
|
+
'DataMap',
|
|
80
|
+
'datamap',
|
|
81
|
+
'mapit',
|
|
82
|
+
'GenericServer',
|
|
83
|
+
'MinecraftServer',
|
|
84
|
+
'ColorMap',
|
|
85
|
+
'ASCII_COLOR_MAP',
|
|
86
|
+
'MC_COLOR_MAP',
|
|
87
|
+
'snapSchedule',
|
|
88
|
+
'runCountdownEvents',
|
|
89
|
+
'waitForOnline',
|
|
90
|
+
'waitForOffline',
|
|
91
|
+
'secsUntil',
|
|
92
|
+
'minsUntil',
|
|
93
|
+
'Snapshot',
|
|
94
|
+
'clearTerminal',
|
|
95
|
+
'validateAll',
|
|
96
|
+
|
|
97
|
+
# namespaces
|
|
98
|
+
'utils',
|
|
99
|
+
'servers',
|
|
100
|
+
'datamap_api',
|
|
101
|
+
]
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
class BackupsAPI:
|
|
2
|
-
"""
|
|
3
|
-
Raw backups endpoints.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
2
|
def __init__(self, panel):
|
|
7
3
|
self.panel = panel
|
|
8
4
|
|
|
@@ -16,11 +12,7 @@ class BackupsAPI:
|
|
|
16
12
|
)
|
|
17
13
|
|
|
18
14
|
def delete(self, server_id, backup_id):
|
|
19
|
-
return self.panel.delete(
|
|
20
|
-
f"/api/client/servers/{server_id}/backups/{backup_id}"
|
|
21
|
-
)
|
|
15
|
+
return self.panel.delete(f"/api/client/servers/{server_id}/backups/{backup_id}")
|
|
22
16
|
|
|
23
17
|
def download(self, server_id, backup_id):
|
|
24
|
-
return self.panel.get(
|
|
25
|
-
f"/api/client/servers/{server_id}/backups/{backup_id}/download"
|
|
26
|
-
)
|
|
18
|
+
return self.panel.get(f"/api/client/servers/{server_id}/backups/{backup_id}/download")
|
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
class DatabasesAPI:
|
|
2
|
-
"""
|
|
3
|
-
Raw database endpoints.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
2
|
def __init__(self, panel):
|
|
7
3
|
self.panel = panel
|
|
8
4
|
|
|
@@ -19,11 +15,7 @@ class DatabasesAPI:
|
|
|
19
15
|
)
|
|
20
16
|
|
|
21
17
|
def rotate_password(self, server_id, db_id):
|
|
22
|
-
return self.panel.post(
|
|
23
|
-
f"/api/client/servers/{server_id}/databases/{db_id}/rotate-password"
|
|
24
|
-
)
|
|
18
|
+
return self.panel.post(f"/api/client/servers/{server_id}/databases/{db_id}/rotate-password")
|
|
25
19
|
|
|
26
20
|
def delete(self, server_id, db_id):
|
|
27
|
-
return self.panel.delete(
|
|
28
|
-
f"/api/client/servers/{server_id}/databases/{db_id}"
|
|
29
|
-
)
|
|
21
|
+
return self.panel.delete(f"/api/client/servers/{server_id}/databases/{db_id}")
|
|
@@ -1,20 +1,12 @@
|
|
|
1
1
|
class FileManagerAPI:
|
|
2
|
-
"""
|
|
3
|
-
Raw file manager endpoints.
|
|
4
|
-
"""
|
|
5
|
-
|
|
6
2
|
def __init__(self, panel):
|
|
7
3
|
self.panel = panel
|
|
8
4
|
|
|
9
5
|
def list(self, server_id, directory="/"):
|
|
10
|
-
return self.panel.get(
|
|
11
|
-
f"/api/client/servers/{server_id}/files/list?directory={directory}"
|
|
12
|
-
)
|
|
6
|
+
return self.panel.get(f"/api/client/servers/{server_id}/files/list?directory={directory}")
|
|
13
7
|
|
|
14
8
|
def download(self, server_id, file_path):
|
|
15
|
-
return self.panel.get(
|
|
16
|
-
f"/api/client/servers/{server_id}/files/download?file={file_path}"
|
|
17
|
-
)
|
|
9
|
+
return self.panel.get(f"/api/client/servers/{server_id}/files/download?file={file_path}")
|
|
18
10
|
|
|
19
11
|
def upload(self, server_id, directory, file_data):
|
|
20
12
|
return self.panel._raw_upload(
|
|
@@ -1,9 +1,4 @@
|
|
|
1
1
|
class ScheduleAPI:
|
|
2
|
-
"""
|
|
3
|
-
Raw schedule endpoints.
|
|
4
|
-
No logic. No models. No convenience.
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
2
|
def __init__(self, panel):
|
|
8
3
|
self.panel = panel
|
|
9
4
|
|
|
@@ -14,7 +9,6 @@ class ScheduleAPI:
|
|
|
14
9
|
return self.panel.post(f"/api/client/servers/{server_id}/schedules", json=payload)
|
|
15
10
|
|
|
16
11
|
def update(self, server_id, schedule_id, payload):
|
|
17
|
-
# Your panel uses POST for full updates
|
|
18
12
|
return self.panel.post(
|
|
19
13
|
f"/api/client/servers/{server_id}/schedules/{schedule_id}",
|
|
20
14
|
json=payload
|
|
@@ -24,6 +18,4 @@ class ScheduleAPI:
|
|
|
24
18
|
return self.panel.delete(f"/api/client/servers/{server_id}/schedules/{schedule_id}")
|
|
25
19
|
|
|
26
20
|
def run(self, server_id, schedule_id):
|
|
27
|
-
return self.panel.post(
|
|
28
|
-
f"/api/client/servers/{server_id}/schedules/{schedule_id}/execute"
|
|
29
|
-
)
|
|
21
|
+
return self.panel.post(f"/api/client/servers/{server_id}/schedules/{schedule_id}/execute")
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import inspect
|
|
1
2
|
import os
|
|
2
3
|
import yaml
|
|
3
4
|
import importlib
|
|
@@ -50,7 +51,7 @@ def loadConfig(path, default_path, schema):
|
|
|
50
51
|
|
|
51
52
|
raw = load_yaml(abs_path)
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
values = {}
|
|
54
55
|
|
|
55
56
|
for f in fields(schema):
|
|
56
57
|
yaml_path = f.metadata.get("yaml_key")
|
|
@@ -61,7 +62,6 @@ def loadConfig(path, default_path, schema):
|
|
|
61
62
|
if value is None:
|
|
62
63
|
continue
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
setattr(target, attr, value)
|
|
65
|
+
values[f.name] = value
|
|
66
66
|
|
|
67
|
-
return
|
|
67
|
+
return schema(**values)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import inspect
|
|
3
|
+
import sys
|
|
4
|
+
from dataclasses import dataclass, fields, is_dataclass
|
|
5
|
+
|
|
6
|
+
# default maps
|
|
7
|
+
_default_maps = []
|
|
8
|
+
|
|
9
|
+
def set_default_maps(*maps):
|
|
10
|
+
global _default_maps
|
|
11
|
+
_default_maps = list(maps)
|
|
12
|
+
|
|
13
|
+
def get_default_maps():
|
|
14
|
+
return _default_maps
|
|
15
|
+
|
|
16
|
+
# syntax patterns
|
|
17
|
+
class Syntax:
|
|
18
|
+
braces = r"\{([^{}]+)\}"
|
|
19
|
+
dollars = r"\$\{([^{}]+)\}"
|
|
20
|
+
angles = r"<([^<>]+)>"
|
|
21
|
+
percents = r"%([^%]+)%"
|
|
22
|
+
|
|
23
|
+
# base datamap
|
|
24
|
+
@dataclass(frozen=True)
|
|
25
|
+
class DataMap:
|
|
26
|
+
__syntax__: str = Syntax.braces
|
|
27
|
+
def as_map(self):
|
|
28
|
+
return {
|
|
29
|
+
f.name: getattr(self, f.name)
|
|
30
|
+
for f in fields(self)
|
|
31
|
+
if f.init and f.name != "__syntax__"
|
|
32
|
+
}
|
|
33
|
+
@classmethod
|
|
34
|
+
def get_syntax(cls):
|
|
35
|
+
return getattr(cls, "__syntax__", Syntax.braces)
|
|
36
|
+
|
|
37
|
+
# decorator
|
|
38
|
+
def datamap(_cls=None, *, syntax=Syntax.braces):
|
|
39
|
+
def wrap(cls):
|
|
40
|
+
cls.__syntax__ = syntax
|
|
41
|
+
cls = type(cls.__name__, (DataMap,), dict(cls.__dict__))
|
|
42
|
+
return dataclass(frozen=True)(cls)
|
|
43
|
+
|
|
44
|
+
return wrap if _cls is None else wrap(_cls)
|
|
45
|
+
|
|
46
|
+
datamap.braces = datamap(syntax=Syntax.braces)
|
|
47
|
+
datamap.angles = datamap(syntax=Syntax.angles)
|
|
48
|
+
datamap.dollars = datamap(syntax=Syntax.dollars)
|
|
49
|
+
datamap.percents = datamap(syntax=Syntax.percents)
|
|
50
|
+
|
|
51
|
+
# core templating
|
|
52
|
+
def mapit(text: str, *maps, **runtime):
|
|
53
|
+
maps = (*get_default_maps(), *maps)
|
|
54
|
+
for m in maps:
|
|
55
|
+
if isinstance(m, type) and is_dataclass(m):
|
|
56
|
+
m = m()
|
|
57
|
+
if is_dataclass(m):
|
|
58
|
+
pattern = m.get_syntax()
|
|
59
|
+
d = m.as_map()
|
|
60
|
+
elif hasattr(m, "as_dict"):
|
|
61
|
+
pattern = Syntax.angles
|
|
62
|
+
d = m.as_dict()
|
|
63
|
+
elif isinstance(m, dict):
|
|
64
|
+
pattern = runtime.get("syntax")
|
|
65
|
+
if not pattern:
|
|
66
|
+
continue
|
|
67
|
+
d = m
|
|
68
|
+
else:
|
|
69
|
+
continue
|
|
70
|
+
|
|
71
|
+
def repl(match):
|
|
72
|
+
k = match.group(1)
|
|
73
|
+
return str(d.get(k, match.group(0)))
|
|
74
|
+
|
|
75
|
+
text = re.sub(pattern, repl, text)
|
|
76
|
+
|
|
77
|
+
if runtime:
|
|
78
|
+
pattern = Syntax.braces
|
|
79
|
+
d = runtime
|
|
80
|
+
|
|
81
|
+
def repl(match):
|
|
82
|
+
k = match.group(1)
|
|
83
|
+
return str(d.get(k, match.group(0)))
|
|
84
|
+
|
|
85
|
+
text = re.sub(pattern, repl, text)
|
|
86
|
+
|
|
87
|
+
return text
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import logging
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from hungerlib.utils.colormaps import ASCII_COLOR_MAP, MC_COLOR_MAP
|
|
6
|
+
from hungerlib.datamap import DataMap, Syntax, mapit
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class MessageRouter:
|
|
10
|
+
def __init__(
|
|
11
|
+
self,
|
|
12
|
+
name,
|
|
13
|
+
server,
|
|
14
|
+
log_path,
|
|
15
|
+
formatter=None,
|
|
16
|
+
console_backspaces=0,
|
|
17
|
+
|
|
18
|
+
origin_map=ASCII_COLOR_MAP,
|
|
19
|
+
destination_map=ASCII_COLOR_MAP,
|
|
20
|
+
broadcast_map=MC_COLOR_MAP,
|
|
21
|
+
log_map=None,
|
|
22
|
+
|
|
23
|
+
info_prefix="<white>[INFO]: ",
|
|
24
|
+
warn_prefix="<yellow>[WARN]: ",
|
|
25
|
+
error_prefix="<red>[ERROR]: "
|
|
26
|
+
):
|
|
27
|
+
self.name = name
|
|
28
|
+
self.server = server
|
|
29
|
+
self.formatter = formatter
|
|
30
|
+
|
|
31
|
+
self.log_path = Path(log_path)
|
|
32
|
+
self.log_path.mkdir(parents=True, exist_ok=True)
|
|
33
|
+
|
|
34
|
+
self.console_backspaces = "\b" * console_backspaces
|
|
35
|
+
|
|
36
|
+
self._origin_map = origin_map
|
|
37
|
+
self._destination_map = destination_map
|
|
38
|
+
self._broadcast_map = broadcast_map
|
|
39
|
+
self._log_map = log_map
|
|
40
|
+
|
|
41
|
+
self.info_prefix = info_prefix
|
|
42
|
+
self.warn_prefix = warn_prefix
|
|
43
|
+
self.error_prefix = error_prefix
|
|
44
|
+
|
|
45
|
+
self.logger = logging.getLogger(name)
|
|
46
|
+
self.logger.setLevel(logging.DEBUG)
|
|
47
|
+
self._init_file_logger()
|
|
48
|
+
|
|
49
|
+
def _init_file_logger(self):
|
|
50
|
+
log_file = self.log_path / f"{self.name}_{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
51
|
+
if not self.logger.handlers:
|
|
52
|
+
handler = logging.FileHandler(str(log_file))
|
|
53
|
+
formatter = logging.Formatter(
|
|
54
|
+
"[%(asctime)s] [%(levelname)s] %(message)s",
|
|
55
|
+
datefmt="%H:%M:%S"
|
|
56
|
+
)
|
|
57
|
+
handler.setFormatter(formatter)
|
|
58
|
+
self.logger.addHandler(handler)
|
|
59
|
+
|
|
60
|
+
# colormap getters/setters
|
|
61
|
+
def setOriginMap(self, cmap): self._origin_map = cmap
|
|
62
|
+
def getOriginMap(self): return self._origin_map
|
|
63
|
+
|
|
64
|
+
def setDestinationMap(self, cmap): self._destination_map = cmap
|
|
65
|
+
def getDestinationMap(self): return self._destination_map
|
|
66
|
+
|
|
67
|
+
def setBroadcastMap(self, cmap): self._broadcast_map = cmap
|
|
68
|
+
def getBroadcastMap(self): return self._broadcast_map
|
|
69
|
+
|
|
70
|
+
def setLogMap(self, cmap): self._log_map = cmap
|
|
71
|
+
def getLogMap(self): return self._log_map
|
|
72
|
+
|
|
73
|
+
# routing primatives
|
|
74
|
+
def origin(self, msg):
|
|
75
|
+
colored = mapit(msg, self._origin_map)
|
|
76
|
+
print(colored)
|
|
77
|
+
|
|
78
|
+
def destination(self, msg):
|
|
79
|
+
if not self.server or not hasattr(self.server, "_rcon_send"):
|
|
80
|
+
return
|
|
81
|
+
colored = mapit(msg, self._destination_map)
|
|
82
|
+
self.server._rcon_send(
|
|
83
|
+
f'logtellraw targetless "{self.console_backspaces}{colored}"'
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
def log(self, msg, level="INFO"):
|
|
87
|
+
clean = msg
|
|
88
|
+
if self._log_map:
|
|
89
|
+
for tag in self._log_map.as_dict().keys():
|
|
90
|
+
clean = clean.replace(tag, "")
|
|
91
|
+
{
|
|
92
|
+
"INFO": self.logger.info,
|
|
93
|
+
"WARN": self.logger.warning,
|
|
94
|
+
"ERROR": self.logger.error
|
|
95
|
+
}[level](clean)
|
|
96
|
+
|
|
97
|
+
def broadcast(self, msg):
|
|
98
|
+
if hasattr(self.server, "sendBroadcast"):
|
|
99
|
+
colored = mapit(msg, self._broadcast_map)
|
|
100
|
+
self.server.sendBroadcast(colored)
|
|
101
|
+
|
|
102
|
+
# high level router
|
|
103
|
+
def say(
|
|
104
|
+
self,
|
|
105
|
+
template,
|
|
106
|
+
level="info",
|
|
107
|
+
destination=False,
|
|
108
|
+
broadcast=False,
|
|
109
|
+
log=True,
|
|
110
|
+
origin=True,
|
|
111
|
+
**fmt
|
|
112
|
+
):
|
|
113
|
+
if not template:
|
|
114
|
+
return
|
|
115
|
+
|
|
116
|
+
if level == "info":
|
|
117
|
+
template = self.info_prefix + template
|
|
118
|
+
elif level == "warn":
|
|
119
|
+
template = self.warn_prefix + template
|
|
120
|
+
elif level == "error":
|
|
121
|
+
template = self.error_prefix + template
|
|
122
|
+
|
|
123
|
+
if self.formatter:
|
|
124
|
+
msg = self.formatter(template, **fmt)
|
|
125
|
+
else:
|
|
126
|
+
msg = template
|
|
127
|
+
|
|
128
|
+
if origin:
|
|
129
|
+
self.origin(msg)
|
|
130
|
+
|
|
131
|
+
if destination:
|
|
132
|
+
self.destination(msg)
|
|
133
|
+
|
|
134
|
+
if log:
|
|
135
|
+
self.log(msg, level=level.upper())
|
|
136
|
+
|
|
137
|
+
if broadcast:
|
|
138
|
+
self.broadcast(msg)
|
|
139
|
+
|
|
140
|
+
# level helpers
|
|
141
|
+
def info(self, template, **fmt):
|
|
142
|
+
self.say(self.info_prefix + template, level="info", **fmt)
|
|
143
|
+
|
|
144
|
+
def warn(self, template, **fmt):
|
|
145
|
+
self.say(self.warn_prefix + template, level="warn", **fmt)
|
|
146
|
+
|
|
147
|
+
def error(self, template, **fmt):
|
|
148
|
+
self.say(self.error_prefix + template, level="error", **fmt)
|
|
@@ -1,11 +1,7 @@
|
|
|
1
|
+
import inspect
|
|
1
2
|
import requests
|
|
2
3
|
|
|
3
|
-
from hungerlib.api import CommandAPI
|
|
4
|
-
from hungerlib.api import ScheduleAPI
|
|
5
|
-
from hungerlib.api import FileManagerAPI
|
|
6
|
-
from hungerlib.api import BackupsAPI
|
|
7
|
-
from hungerlib.api import DatabasesAPI
|
|
8
|
-
from hungerlib.api import StartupAPI
|
|
4
|
+
from hungerlib.api import CommandAPI, ScheduleAPI, FileManagerAPI, BackupsAPI, DatabasesAPI, StartupAPI
|
|
9
5
|
|
|
10
6
|
|
|
11
7
|
class Panel:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Universal server class
|
|
2
|
-
from hungerlib import Panel
|
|
3
|
-
from hungerlib.
|
|
2
|
+
from hungerlib.panel import Panel
|
|
3
|
+
from hungerlib.utils.colormaps import MC_COLOR_MAP, ASCII_COLOR_MAP
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
class GenericServer:
|
|
@@ -187,10 +187,6 @@ class GenericServer:
|
|
|
187
187
|
|
|
188
188
|
|
|
189
189
|
def getSchedule(self, schedule_id: int):
|
|
190
|
-
"""
|
|
191
|
-
Returns a dict containing all schedule attributes for the given schedule_id.
|
|
192
|
-
Works with raw ScheduleAPI responses.
|
|
193
|
-
"""
|
|
194
190
|
resp = self.panel.schedules.list(self.server_id)
|
|
195
191
|
data = resp.json()
|
|
196
192
|
for item in data.get("data", []):
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
# Minecraft server class
|
|
2
1
|
import time
|
|
3
2
|
import re
|
|
4
3
|
import mcrcon
|
|
5
|
-
from hungerlib import Panel
|
|
4
|
+
from hungerlib.panel import Panel
|
|
5
|
+
from hungerlib.utils.colormaps import MC_COLOR_MAP, ASCII_COLOR_MAP
|
|
6
6
|
from hungerlib.servers import GenericServer
|
|
7
|
-
from hungerlib.addons import MC_COLOR_MAP, ASCII_COLOR_MAP
|
|
8
7
|
|
|
9
8
|
|
|
10
9
|
class MinecraftServer(GenericServer):
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from .colormaps import ColorMap, ASCII_COLOR_MAP, MC_COLOR_MAP
|
|
2
|
+
from .time import (
|
|
3
|
+
snapSchedule,
|
|
4
|
+
runCountdownEvents,
|
|
5
|
+
waitForOnline,
|
|
6
|
+
waitForOffline,
|
|
7
|
+
secsUntil,
|
|
8
|
+
minsUntil
|
|
9
|
+
)
|
|
10
|
+
from .utils import Snapshot, clearTerminal, validateAll
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'ColorMap',
|
|
14
|
+
'ASCII_COLOR_MAP',
|
|
15
|
+
'MC_COLOR_MAP',
|
|
16
|
+
'snapSchedule',
|
|
17
|
+
'runCountdownEvents',
|
|
18
|
+
'waitForOnline',
|
|
19
|
+
'waitForOffline',
|
|
20
|
+
'secsUntil',
|
|
21
|
+
'minsUntil',
|
|
22
|
+
'Snapshot',
|
|
23
|
+
'clearTerminal',
|
|
24
|
+
'validateAll',
|
|
25
|
+
]
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
from hungerlib.datamap import datamap, Syntax, mapit, set_default_maps
|
|
2
|
+
|
|
3
|
+
@datamap(syntax=Syntax.angles) # produces <>
|
|
4
|
+
class ColorMap:
|
|
5
|
+
black: str = "\033[30m"
|
|
6
|
+
dark_blue: str = "\033[34m"
|
|
7
|
+
dark_green: str = "\033[32m"
|
|
8
|
+
dark_aqua: str = "\033[36m"
|
|
9
|
+
dark_red: str = "\033[31m"
|
|
10
|
+
dark_purple: str = "\033[35m"
|
|
11
|
+
gold: str = "\033[33m"
|
|
12
|
+
gray: str = "\033[37m"
|
|
13
|
+
dark_gray: str = "\033[90m"
|
|
14
|
+
blue: str = "\033[94m"
|
|
15
|
+
green: str = "\033[92m"
|
|
16
|
+
aqua: str = "\033[96m"
|
|
17
|
+
red: str = "\033[91m"
|
|
18
|
+
light_purple: str = "\033[95m"
|
|
19
|
+
yellow: str = "\033[93m"
|
|
20
|
+
white: str = "\033[97m"
|
|
21
|
+
reset: str = "\033[0m"
|
|
22
|
+
bold: str = "\033[1m"
|
|
23
|
+
italic: str = "\033[3m"
|
|
24
|
+
|
|
25
|
+
def as_dict(self):
|
|
26
|
+
return {f"<{k}>": getattr(self, k) for k in self.__dataclass_fields__}
|
|
27
|
+
|
|
28
|
+
# ASCII color map
|
|
29
|
+
ASCII_COLOR_MAP = ColorMap()
|
|
30
|
+
|
|
31
|
+
# Minecraft color map
|
|
32
|
+
MC_COLOR_MAP = ColorMap(
|
|
33
|
+
black="§0",
|
|
34
|
+
dark_blue="§1",
|
|
35
|
+
dark_green="§2",
|
|
36
|
+
dark_aqua="§3",
|
|
37
|
+
dark_red="§4",
|
|
38
|
+
dark_purple="§5",
|
|
39
|
+
gold="§6",
|
|
40
|
+
gray="§7",
|
|
41
|
+
dark_gray="§8",
|
|
42
|
+
blue="§9",
|
|
43
|
+
green="§a",
|
|
44
|
+
aqua="§b",
|
|
45
|
+
red="§c",
|
|
46
|
+
light_purple="§d",
|
|
47
|
+
yellow="§e",
|
|
48
|
+
white="§f",
|
|
49
|
+
reset="§r",
|
|
50
|
+
bold="§l",
|
|
51
|
+
italic="§o"
|
|
52
|
+
)
|
hungerlib-2.19.dev1/src/hungerlib/addons/scheduler.py → hungerlib-3.0/src/hungerlib/utils/time.py
RENAMED
|
@@ -21,33 +21,12 @@ def snapSchedule(minimumMinutes=30, snapMinutes=(0, 30)):
|
|
|
21
21
|
"formatted": scheduled.strftime("%I:%M %p")
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
24
|
def runCountdownEvents(
|
|
26
25
|
target_time,
|
|
27
26
|
minute_callbacks=None,
|
|
28
27
|
second_callbacks=None,
|
|
29
28
|
tick_interval=1
|
|
30
29
|
):
|
|
31
|
-
"""
|
|
32
|
-
A simple, readable countdown engine.
|
|
33
|
-
|
|
34
|
-
- Counts down until `target_time`
|
|
35
|
-
- When the countdown hits a configured minute mark, it runs that callback
|
|
36
|
-
- When the countdown hits a configured second mark, it runs that callback
|
|
37
|
-
|
|
38
|
-
Parameters:
|
|
39
|
-
target_time (datetime):
|
|
40
|
-
The time we are counting down to.
|
|
41
|
-
|
|
42
|
-
minute_callbacks (dict[int, callable]):
|
|
43
|
-
Example: {5: func, 1: func}
|
|
44
|
-
|
|
45
|
-
second_callbacks (dict[int, callable]):
|
|
46
|
-
Example: {10: func, 5: func, 1: func}
|
|
47
|
-
|
|
48
|
-
tick_interval (int):
|
|
49
|
-
How often to check the countdown (in seconds).
|
|
50
|
-
"""
|
|
51
30
|
|
|
52
31
|
# Default to empty dicts if none provided
|
|
53
32
|
minute_callbacks = minute_callbacks or {}
|
|
@@ -78,13 +57,7 @@ def runCountdownEvents(
|
|
|
78
57
|
|
|
79
58
|
time.sleep(tick_interval)
|
|
80
59
|
|
|
81
|
-
|
|
82
|
-
|
|
83
60
|
def waitForOnline(server, timeout=60, interval=2):
|
|
84
|
-
"""
|
|
85
|
-
Wait until the server reports status 'running'.
|
|
86
|
-
Returns True if online before timeout.
|
|
87
|
-
"""
|
|
88
61
|
elapsed = 0
|
|
89
62
|
while elapsed < timeout:
|
|
90
63
|
if server.isOnline():
|
|
@@ -93,12 +66,7 @@ def waitForOnline(server, timeout=60, interval=2):
|
|
|
93
66
|
elapsed += interval
|
|
94
67
|
return False
|
|
95
68
|
|
|
96
|
-
|
|
97
69
|
def waitForOffline(server, timeout=60, interval=2):
|
|
98
|
-
"""
|
|
99
|
-
Wait until the server reports status 'offline'.
|
|
100
|
-
Returns True if offline before timeout.
|
|
101
|
-
"""
|
|
102
70
|
elapsed = 0
|
|
103
71
|
while elapsed < timeout:
|
|
104
72
|
if server.isOffline():
|
|
@@ -107,13 +75,10 @@ def waitForOffline(server, timeout=60, interval=2):
|
|
|
107
75
|
elapsed += interval
|
|
108
76
|
return False
|
|
109
77
|
|
|
110
|
-
|
|
111
|
-
|
|
112
78
|
def secsUntil(target):
|
|
113
79
|
now = datetime.now()
|
|
114
80
|
return int((target - now).total_seconds())
|
|
115
81
|
|
|
116
|
-
|
|
117
82
|
def minsUntil(target):
|
|
118
83
|
now = datetime.now()
|
|
119
84
|
return int((target - now).total_seconds()) // 60
|
hungerlib-2.19.dev1/src/hungerlib/addons/snapshot.py → hungerlib-3.0/src/hungerlib/utils/utils.py
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import os
|
|
2
|
+
|
|
1
3
|
class Snapshot:
|
|
2
4
|
def __init__(self, Server, rounding=2, gb=False):
|
|
3
5
|
self.Server = Server
|
|
@@ -28,4 +30,14 @@ class Snapshot:
|
|
|
28
30
|
if self.players is not None:
|
|
29
31
|
base += f'\nOnline players: {self.players}'
|
|
30
32
|
|
|
31
|
-
return base
|
|
33
|
+
return base
|
|
34
|
+
|
|
35
|
+
def clearTerminal():
|
|
36
|
+
os.system("clear" if os.name == "posix" else "cls")
|
|
37
|
+
|
|
38
|
+
def validateAll(panel, server):
|
|
39
|
+
return (
|
|
40
|
+
panel.ping() is True and
|
|
41
|
+
panel.validateAPI() is True and
|
|
42
|
+
server.getStatus() == "running"
|
|
43
|
+
)
|
|
@@ -2,20 +2,15 @@ LICENSE
|
|
|
2
2
|
README.md
|
|
3
3
|
pyproject.toml
|
|
4
4
|
src/hungerlib/__init__.py
|
|
5
|
-
src/hungerlib/
|
|
5
|
+
src/hungerlib/configloader.py
|
|
6
|
+
src/hungerlib/datamap.py
|
|
7
|
+
src/hungerlib/messagerouter.py
|
|
6
8
|
src/hungerlib/panel.py
|
|
7
9
|
src/hungerlib.egg-info/PKG-INFO
|
|
8
10
|
src/hungerlib.egg-info/SOURCES.txt
|
|
9
11
|
src/hungerlib.egg-info/dependency_links.txt
|
|
10
12
|
src/hungerlib.egg-info/requires.txt
|
|
11
13
|
src/hungerlib.egg-info/top_level.txt
|
|
12
|
-
src/hungerlib/addons/__init__.py
|
|
13
|
-
src/hungerlib/addons/colormap.py
|
|
14
|
-
src/hungerlib/addons/configloader.py
|
|
15
|
-
src/hungerlib/addons/mchelpers.py
|
|
16
|
-
src/hungerlib/addons/scheduler.py
|
|
17
|
-
src/hungerlib/addons/snapshot.py
|
|
18
|
-
src/hungerlib/addons/utils.py
|
|
19
14
|
src/hungerlib/api/__init__.py
|
|
20
15
|
src/hungerlib/api/backups.py
|
|
21
16
|
src/hungerlib/api/command.py
|
|
@@ -25,4 +20,8 @@ src/hungerlib/api/schedule.py
|
|
|
25
20
|
src/hungerlib/api/startup.py
|
|
26
21
|
src/hungerlib/servers/__init__.py
|
|
27
22
|
src/hungerlib/servers/generic.py
|
|
28
|
-
src/hungerlib/servers/minecraft.py
|
|
23
|
+
src/hungerlib/servers/minecraft.py
|
|
24
|
+
src/hungerlib/utils/__init__.py
|
|
25
|
+
src/hungerlib/utils/colormaps.py
|
|
26
|
+
src/hungerlib/utils/time.py
|
|
27
|
+
src/hungerlib/utils/utils.py
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
from importlib.metadata import version as _pkg_version, PackageNotFoundError
|
|
2
|
-
|
|
3
|
-
# Package version
|
|
4
|
-
try:
|
|
5
|
-
__version__ = _pkg_version("hungerlib")
|
|
6
|
-
except PackageNotFoundError:
|
|
7
|
-
__version__ = "0.0.0"
|
|
8
|
-
|
|
9
|
-
# --- Core modules ---
|
|
10
|
-
from .panel import Panel
|
|
11
|
-
from .logger import HungerLogger
|
|
12
|
-
|
|
13
|
-
# --- API endpoints ---
|
|
14
|
-
from .api.schedule import ScheduleAPI
|
|
15
|
-
from .api.filemanager import FileManagerAPI
|
|
16
|
-
from .api.backups import BackupsAPI
|
|
17
|
-
from .api.databases import DatabasesAPI
|
|
18
|
-
from .api.startup import StartupAPI
|
|
19
|
-
|
|
20
|
-
__all__ = [
|
|
21
|
-
"__version__",
|
|
22
|
-
|
|
23
|
-
# core utilities
|
|
24
|
-
"Panel",
|
|
25
|
-
"HungerLogger",
|
|
26
|
-
|
|
27
|
-
# API endpoints
|
|
28
|
-
"ScheduleAPI",
|
|
29
|
-
"FileManagerAPI",
|
|
30
|
-
"BackupsAPI",
|
|
31
|
-
"DatabasesAPI",
|
|
32
|
-
"StartupAPI",
|
|
33
|
-
]
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
from .colormap import *
|
|
2
|
-
from .snapshot import Snapshot
|
|
3
|
-
from .scheduler import *
|
|
4
|
-
from .utils import *
|
|
5
|
-
from .configloader import *
|
|
6
|
-
|
|
7
|
-
__all__ = [
|
|
8
|
-
'ColorMap',
|
|
9
|
-
'MC_COLOR_MAP',
|
|
10
|
-
'ASCII_COLOR_MAP',
|
|
11
|
-
'runCountdownEvents',
|
|
12
|
-
'waitForOnline',
|
|
13
|
-
'waitForOffline',
|
|
14
|
-
'Snapshot',
|
|
15
|
-
'snapSchedule',
|
|
16
|
-
'secsUntil',
|
|
17
|
-
'minsUntil',
|
|
18
|
-
'validateAll',
|
|
19
|
-
'mb_gb',
|
|
20
|
-
'gb_mb',
|
|
21
|
-
'mib_gib',
|
|
22
|
-
'gib_mib',
|
|
23
|
-
'clearTerminal',
|
|
24
|
-
'load_yaml',
|
|
25
|
-
'loadConfig',
|
|
26
|
-
'clrz',
|
|
27
|
-
'set_default_colormap',
|
|
28
|
-
'get_default_colormap',
|
|
29
|
-
]
|
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# Environment-based color translation and mapping
|
|
2
|
-
from dataclasses import dataclass, field
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
@dataclass(frozen=True)
|
|
6
|
-
class ColorMap:
|
|
7
|
-
black: str
|
|
8
|
-
dark_blue: str
|
|
9
|
-
dark_green: str
|
|
10
|
-
dark_aqua: str
|
|
11
|
-
dark_red: str
|
|
12
|
-
dark_purple: str
|
|
13
|
-
gold: str
|
|
14
|
-
gray: str
|
|
15
|
-
dark_gray: str
|
|
16
|
-
blue: str
|
|
17
|
-
green: str
|
|
18
|
-
aqua: str
|
|
19
|
-
red: str
|
|
20
|
-
light_purple: str
|
|
21
|
-
yellow: str
|
|
22
|
-
white: str
|
|
23
|
-
reset: str
|
|
24
|
-
bold: str
|
|
25
|
-
italic: str
|
|
26
|
-
|
|
27
|
-
def as_dict(self):
|
|
28
|
-
"""Convert dataclass to dict with <tags> as keys."""
|
|
29
|
-
return {
|
|
30
|
-
f"<{field}>": getattr(self, field)
|
|
31
|
-
for field in self.__dataclass_fields__
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
MC_COLOR_MAP = ColorMap(
|
|
36
|
-
black="§0",
|
|
37
|
-
dark_blue="§1",
|
|
38
|
-
dark_green="§2",
|
|
39
|
-
dark_aqua="§3",
|
|
40
|
-
dark_red="§4",
|
|
41
|
-
dark_purple="§5",
|
|
42
|
-
gold="§6",
|
|
43
|
-
gray="§7",
|
|
44
|
-
dark_gray="§8",
|
|
45
|
-
blue="§9",
|
|
46
|
-
green="§a",
|
|
47
|
-
aqua="§b",
|
|
48
|
-
red="§c",
|
|
49
|
-
light_purple="§d",
|
|
50
|
-
yellow="§e",
|
|
51
|
-
white="§f",
|
|
52
|
-
reset="§r",
|
|
53
|
-
bold="§l",
|
|
54
|
-
italic="§o"
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
ASCII_COLOR_MAP = ColorMap(
|
|
58
|
-
black="\033[30m",
|
|
59
|
-
dark_blue="\033[34m",
|
|
60
|
-
dark_green="\033[32m",
|
|
61
|
-
dark_aqua="\033[36m",
|
|
62
|
-
dark_red="\033[31m",
|
|
63
|
-
dark_purple="\033[35m",
|
|
64
|
-
gold="\033[33m",
|
|
65
|
-
gray="\033[37m",
|
|
66
|
-
dark_gray="\033[90m",
|
|
67
|
-
blue="\033[94m",
|
|
68
|
-
green="\033[92m",
|
|
69
|
-
aqua="\033[96m",
|
|
70
|
-
red="\033[91m",
|
|
71
|
-
light_purple="\033[95m",
|
|
72
|
-
yellow="\033[93m",
|
|
73
|
-
white="\033[97m",
|
|
74
|
-
reset="\033[0m",
|
|
75
|
-
bold="\033[1m",
|
|
76
|
-
italic="\033[3m"
|
|
77
|
-
)
|
|
78
|
-
|
|
79
|
-
_DEFAULT_COLORMAP = ASCII_COLOR_MAP
|
|
80
|
-
|
|
81
|
-
def set_default_colormap(cmap):
|
|
82
|
-
global _DEFAULT_COLORMAP
|
|
83
|
-
_DEFAULT_COLORMAP = cmap
|
|
84
|
-
|
|
85
|
-
def get_default_colormap():
|
|
86
|
-
return _DEFAULT_COLORMAP
|
|
87
|
-
|
|
88
|
-
def clrz(text: str, cmap=None):
|
|
89
|
-
if cmap is None:
|
|
90
|
-
cmap = get_default_colormap()
|
|
91
|
-
if hasattr(cmap, "as_dict"):
|
|
92
|
-
cmap = cmap.as_dict()
|
|
93
|
-
for tag, code in cmap.items():
|
|
94
|
-
text = text.replace(tag, code)
|
|
95
|
-
reset = cmap.get("<reset>", "")
|
|
96
|
-
return text + reset
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
# Minecraft-specific helper functions that operate on a MinecraftServer instance.
|
|
2
|
-
|
|
3
|
-
class MCHelpers:
|
|
4
|
-
def __init__(self, server):
|
|
5
|
-
"""
|
|
6
|
-
Helper utilities for a MinecraftServer instance.
|
|
7
|
-
"""
|
|
8
|
-
self.server = server
|
|
9
|
-
|
|
10
|
-
def run(self, command):
|
|
11
|
-
"""Send a raw RCON command."""
|
|
12
|
-
return self.server._rcon_send(command)
|
|
13
|
-
|
|
14
|
-
def tellraw(self, target, message):
|
|
15
|
-
"""Send a tellraw message with color translation."""
|
|
16
|
-
translated = self.server._translate_mc_colors(message)
|
|
17
|
-
safe = translated.replace('"', '\\"')
|
|
18
|
-
cmd = f'tellraw {target} {{"text":"{safe}"}}'
|
|
19
|
-
return self.run(cmd)
|
|
20
|
-
|
|
21
|
-
def kick(self, player, message="Kicked"):
|
|
22
|
-
safe = message.replace('"', '\\"')
|
|
23
|
-
return self.run(f'kick {player} "{safe}"')
|
|
24
|
-
|
|
25
|
-
def kickAll(self, message="Server restarting"):
|
|
26
|
-
safe = message.replace('"', '\\"')
|
|
27
|
-
return self.run(f'kick @a "{safe}"')
|
|
28
|
-
|
|
29
|
-
def whitelistAdd(self, player):
|
|
30
|
-
return self.run(f"whitelist add {player}")
|
|
31
|
-
|
|
32
|
-
def whitelistRemove(self, player):
|
|
33
|
-
return self.run(f"whitelist remove {player}")
|
|
34
|
-
|
|
35
|
-
def whitelistList(self):
|
|
36
|
-
return self.run("whitelist list")
|
|
37
|
-
|
|
38
|
-
def runFunction(self, function_name):
|
|
39
|
-
"""Run a datapack function."""
|
|
40
|
-
return self.run(f"function {function_name}")
|
|
41
|
-
|
|
42
|
-
def enableDatapack(self, name):
|
|
43
|
-
return self.run(f"datapack enable {name}")
|
|
44
|
-
|
|
45
|
-
def disableDatapack(self, name):
|
|
46
|
-
return self.run(f"datapack disable {name}")
|
|
47
|
-
|
|
48
|
-
def listDatapacks(self):
|
|
49
|
-
return self.run("datapack list")
|
|
50
|
-
|
|
51
|
-
# ============================================================
|
|
52
|
-
# GAMERULE HELPERS
|
|
53
|
-
# ============================================================
|
|
54
|
-
|
|
55
|
-
def setGamerule(self, rule, value):
|
|
56
|
-
return self.run(f"gamerule {rule} {value}")
|
|
57
|
-
|
|
58
|
-
def getGamerule(self, rule):
|
|
59
|
-
return self.run(f"gamerule {rule}")
|
|
60
|
-
|
|
61
|
-
# ============================================================
|
|
62
|
-
# SCOREBOARD HELPERS
|
|
63
|
-
# ============================================================
|
|
64
|
-
|
|
65
|
-
def scoreboardAddObjective(self, name, criteria="dummy", display_name=None):
|
|
66
|
-
if display_name:
|
|
67
|
-
safe = display_name.replace('"', '\\"')
|
|
68
|
-
return self.run(f'scoreboard objectives add {name} {criteria} "{safe}"')
|
|
69
|
-
return self.run(f"scoreboard objectives add {name} {criteria}")
|
|
70
|
-
|
|
71
|
-
def scoreboardRemoveObjective(self, name):
|
|
72
|
-
return self.run(f"scoreboard objectives remove {name}")
|
|
73
|
-
|
|
74
|
-
def scoreboardSetDisplay(self, slot, objective):
|
|
75
|
-
return self.run(f"scoreboard objectives setdisplay {slot} {objective}")
|
|
76
|
-
|
|
77
|
-
def scoreboardSet(self, player, objective, value):
|
|
78
|
-
return self.run(f"scoreboard players set {player} {objective} {value}")
|
|
79
|
-
|
|
80
|
-
def scoreboardAdd(self, player, objective, value):
|
|
81
|
-
return self.run(f"scoreboard players add {player} {objective} {value}")
|
|
82
|
-
|
|
83
|
-
def scoreboardGet(self, player, objective):
|
|
84
|
-
return self.run(f"scoreboard players get {player} {objective}")
|
|
85
|
-
|
|
86
|
-
# ============================================================
|
|
87
|
-
# TIME & WEATHER HELPERS
|
|
88
|
-
# ============================================================
|
|
89
|
-
|
|
90
|
-
def setTime(self, value):
|
|
91
|
-
return self.run(f"time set {value}")
|
|
92
|
-
|
|
93
|
-
def addTime(self, value):
|
|
94
|
-
return self.run(f"time add {value}")
|
|
95
|
-
|
|
96
|
-
def setWeather(self, weather, duration=None):
|
|
97
|
-
if duration:
|
|
98
|
-
return self.run(f"weather {weather} {duration}")
|
|
99
|
-
return self.run(f"weather {weather}")
|
|
100
|
-
|
|
101
|
-
# ============================================================
|
|
102
|
-
# BROADCAST HELPERS
|
|
103
|
-
# ============================================================
|
|
104
|
-
|
|
105
|
-
def broadcast(self, message):
|
|
106
|
-
"""Broadcast using tellraw @a."""
|
|
107
|
-
return self.tellraw("@a", message)
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
|
|
3
|
-
def mb_gb(mb, floor=False):
|
|
4
|
-
return mb / 1000 if not floor else mb // 1000
|
|
5
|
-
|
|
6
|
-
def gb_mb(gb):
|
|
7
|
-
return gb * 1000
|
|
8
|
-
|
|
9
|
-
def mib_gib(mib, floor=False):
|
|
10
|
-
return mib / 1024 if not floor else mib // 1024
|
|
11
|
-
|
|
12
|
-
def gib_mib(gib):
|
|
13
|
-
return gib * 1024
|
|
14
|
-
|
|
15
|
-
def clearTerminal():
|
|
16
|
-
os.system("clear" if os.name == "posix" else "cls")
|
|
17
|
-
|
|
18
|
-
def validateAll(panel, server):
|
|
19
|
-
"""
|
|
20
|
-
Validate panel connectivity, API access, and server running state.
|
|
21
|
-
"""
|
|
22
|
-
return (
|
|
23
|
-
panel.ping() is True and
|
|
24
|
-
panel.validateAPI() is True and
|
|
25
|
-
server.getStatus() == "running"
|
|
26
|
-
)
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# Logging system
|
|
2
|
-
|
|
3
|
-
import os
|
|
4
|
-
os.environ['TZ'] = 'America/Chicago'
|
|
5
|
-
import time
|
|
6
|
-
time.tzset()
|
|
7
|
-
|
|
8
|
-
import logging
|
|
9
|
-
from pathlib import Path
|
|
10
|
-
from datetime import datetime
|
|
11
|
-
from hungerlib.addons import ASCII_COLOR_MAP, MC_COLOR_MAP, clrz
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class HungerLogger:
|
|
15
|
-
def __init__(
|
|
16
|
-
self,
|
|
17
|
-
name,
|
|
18
|
-
server,
|
|
19
|
-
log_path,
|
|
20
|
-
log_destination_method='rcon',
|
|
21
|
-
|
|
22
|
-
# backspaces
|
|
23
|
-
console_backspaces=0,
|
|
24
|
-
|
|
25
|
-
# color mapping
|
|
26
|
-
file_color_map=None,
|
|
27
|
-
origin_color_map=ASCII_COLOR_MAP,
|
|
28
|
-
destination_color_map=ASCII_COLOR_MAP,
|
|
29
|
-
|
|
30
|
-
# prefixes
|
|
31
|
-
info_prefix='<white>[INFO]: ',
|
|
32
|
-
warn_prefix='<yellow>[WARN]: ',
|
|
33
|
-
error_prefix='<red>[ERROR]: '
|
|
34
|
-
):
|
|
35
|
-
|
|
36
|
-
self.name = name
|
|
37
|
-
self.server = server
|
|
38
|
-
self.log_path = Path(f'{log_path}')
|
|
39
|
-
self.log_destination_method = log_destination_method
|
|
40
|
-
|
|
41
|
-
self.console_backspaces = '\b' * console_backspaces
|
|
42
|
-
|
|
43
|
-
self.file_color_map = file_color_map
|
|
44
|
-
self.origin_color_map = origin_color_map
|
|
45
|
-
self.destination_color_map = destination_color_map
|
|
46
|
-
|
|
47
|
-
self.info_prefix = info_prefix
|
|
48
|
-
self.warn_prefix = warn_prefix
|
|
49
|
-
self.error_prefix = error_prefix
|
|
50
|
-
|
|
51
|
-
self.prefixes = {
|
|
52
|
-
"INFO": self.info_prefix,
|
|
53
|
-
"WARN": self.warn_prefix,
|
|
54
|
-
"ERROR": self.error_prefix
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
self.log_path.mkdir(parents=True, exist_ok=True)
|
|
58
|
-
self.logger = logging.getLogger(name)
|
|
59
|
-
self.logger.setLevel(logging.DEBUG)
|
|
60
|
-
self._initializeLogger()
|
|
61
|
-
|
|
62
|
-
def _initializeLogger(self):
|
|
63
|
-
logFile = self.log_path / f"{self.name}_{datetime.now().strftime('%Y-%m-%d')}.log"
|
|
64
|
-
|
|
65
|
-
if not self.logger.handlers:
|
|
66
|
-
handler = logging.FileHandler(str(logFile))
|
|
67
|
-
formatter = logging.Formatter(
|
|
68
|
-
"[%(asctime)s] [%(levelname)s] %(message)s",
|
|
69
|
-
datefmt="%H:%M:%S"
|
|
70
|
-
)
|
|
71
|
-
handler.setFormatter(formatter)
|
|
72
|
-
self.logger.addHandler(handler)
|
|
73
|
-
|
|
74
|
-
self.logger.info("Logger initialized.")
|
|
75
|
-
|
|
76
|
-
def _strip_colors(self, msg):
|
|
77
|
-
if not self.file_color_map:
|
|
78
|
-
return msg
|
|
79
|
-
for tag in self.file_color_map.as_dict().keys():
|
|
80
|
-
msg = msg.replace(tag, "")
|
|
81
|
-
return msg
|
|
82
|
-
|
|
83
|
-
def _destinationLog(self, msg):
|
|
84
|
-
if not self.server:
|
|
85
|
-
return
|
|
86
|
-
if not hasattr(self.server, "_rcon_send"):
|
|
87
|
-
return
|
|
88
|
-
colored = clrz(msg, cmap=self.destination_color_map)
|
|
89
|
-
if self.log_destination_method == 'rcon':
|
|
90
|
-
self.server._rcon_send(f'logtellraw targetless \"{self.console_backspaces}{colored}\"')
|
|
91
|
-
if self.log_destination_method == 'api':
|
|
92
|
-
self.server.sendConsoleCommand(f'logtellraw targetless \"{self.console_backspaces}{colored}\"')
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
def _log(self, level, msg, destination, origin, logs):
|
|
96
|
-
prefix = self.prefixes[level] + f"[{self.name}] "
|
|
97
|
-
full = prefix + msg
|
|
98
|
-
|
|
99
|
-
if destination:
|
|
100
|
-
self._destinationLog(full)
|
|
101
|
-
|
|
102
|
-
if origin:
|
|
103
|
-
colored = clrz(full + "<reset>", cmap=self.origin_color_map)
|
|
104
|
-
print(colored)
|
|
105
|
-
|
|
106
|
-
if logs:
|
|
107
|
-
clean = self._strip_colors(full)
|
|
108
|
-
{
|
|
109
|
-
"INFO": self.logger.info,
|
|
110
|
-
"WARN": self.logger.warning,
|
|
111
|
-
"ERROR": self.logger.error
|
|
112
|
-
}[level](clean)
|
|
113
|
-
|
|
114
|
-
def info(self, msg, destination=False, origin=True, logs=True):
|
|
115
|
-
'''Log to the INFO channel'''
|
|
116
|
-
self._log("INFO", msg, destination, origin, logs)
|
|
117
|
-
|
|
118
|
-
def warn(self, msg, destination=False, origin=True, logs=True):
|
|
119
|
-
'''Log to the WARN channel'''
|
|
120
|
-
self._log("WARN", msg, destination, origin, logs)
|
|
121
|
-
|
|
122
|
-
def error(self, msg, destination=False, origin=True, logs=True):
|
|
123
|
-
'''Log to the ERROR channel'''
|
|
124
|
-
self._log("ERROR", msg, destination, origin, logs)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|