hungerlib 4.24.2__tar.gz → 4.25.dev4__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.
Files changed (40) hide show
  1. {hungerlib-4.24.2/src/hungerlib.egg-info → hungerlib-4.25.dev4}/PKG-INFO +1 -1
  2. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/pyproject.toml +1 -1
  3. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/bridgeclient.py +150 -10
  4. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/servers/minecraft.py +19 -21
  5. {hungerlib-4.24.2 → hungerlib-4.25.dev4/src/hungerlib.egg-info}/PKG-INFO +1 -1
  6. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/LICENSE +0 -0
  7. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/README.md +0 -0
  8. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/setup.cfg +0 -0
  9. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/__init__.py +0 -0
  10. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/__init__.py +0 -0
  11. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/backups.py +0 -0
  12. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/command.py +0 -0
  13. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/databases.py +0 -0
  14. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/filemanager.py +0 -0
  15. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/schedule.py +0 -0
  16. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/api/startup.py +0 -0
  17. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/configloader.py +0 -0
  18. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/email/__init__.py +0 -0
  19. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/email/client.py +0 -0
  20. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/email/email_templates/restart.html +0 -0
  21. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/email/manager.py +0 -0
  22. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/email/message.py +0 -0
  23. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/messagerouter.py +0 -0
  24. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/panel.py +0 -0
  25. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/servers/__init__.py +0 -0
  26. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/servers/generic.py +0 -0
  27. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/__init__.py +0 -0
  28. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/buffer.py +0 -0
  29. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/convert.py +0 -0
  30. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/exceptions.py +0 -0
  31. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/time.py +0 -0
  32. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/utils/utils.py +0 -0
  33. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/validator.py +0 -0
  34. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/webhook/__init__.py +0 -0
  35. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/webhook/client.py +0 -0
  36. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib/webhook/server.py +0 -0
  37. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib.egg-info/SOURCES.txt +0 -0
  38. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib.egg-info/dependency_links.txt +0 -0
  39. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib.egg-info/requires.txt +0 -0
  40. {hungerlib-4.24.2 → hungerlib-4.25.dev4}/src/hungerlib.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hungerlib
3
- Version: 4.24.2
3
+ Version: 4.25.dev4
4
4
  Summary: Powerful automation library for Pterodactyl.
5
5
  Author: iFamished
6
6
  License: MIT
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "hungerlib"
10
- version = "4.24.2"
10
+ version = "4.25-dev.4"
11
11
  description = "Powerful automation library for Pterodactyl."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.9"
@@ -1,19 +1,163 @@
1
1
  import time
2
+ import threading
3
+ import re
2
4
  import requests
3
5
  from .utils.exceptions import HungerBridgeError, InvalidLevelError, InvalidModeError
4
6
 
5
7
 
8
+ class Stream:
9
+ '''Streaming wrapper for HungerBridge /stream/logs SSE endpoint.'''
10
+ def __init__(
11
+ self,
12
+ base_url: str,
13
+ headers: dict,
14
+ history_handler=None,
15
+ newline_handler=None
16
+ ):
17
+ self.url = base_url.rstrip('/') + '/stream/logs'
18
+ self.headers = headers
19
+
20
+ self.history_handler = history_handler or self._default_history_handler
21
+ self.newline_handler = newline_handler or self._default_newline_handler
22
+
23
+ self.raw_stream = []
24
+ self.sanitized_stream = []
25
+ self.timestamped_stream = {}
26
+
27
+ self._thread = None
28
+ self._stop_event = None
29
+ self._session = None
30
+
31
+ def _default_history_handler(self, historic_lines: list):
32
+ for line in historic_lines:
33
+ clean = self.sanitize(line)
34
+ ts = self.extractTimestamp(clean)
35
+ self.raw_stream.append(line)
36
+ self.sanitized_stream.append(clean)
37
+ if ts is not None:
38
+ self.timestamped_stream[ts] = clean
39
+
40
+ def _default_newline_handler(self, line: str):
41
+ clean = self.sanitize(line)
42
+ ts = self.extractTimestamp(clean)
43
+ self.raw_stream.append(line)
44
+ self.sanitized_stream.append(clean)
45
+ if ts is not None:
46
+ self.timestamped_stream[ts] = clean
47
+
48
+ def connect(self, keepalive: int = 15):
49
+ if self._thread and self._thread.is_alive():
50
+ return
51
+
52
+ self._stop_event = threading.Event()
53
+ self._session = requests.Session()
54
+
55
+ def _run():
56
+ history_phase = True
57
+ history_lines = []
58
+ history_deadline = time.time() + keepalive
59
+
60
+ try:
61
+ with self._session.get(
62
+ self.url,
63
+ headers=self.headers,
64
+ stream=True
65
+ ) as r:
66
+ if not r.ok:
67
+ raise HungerBridgeError(f'HungerBridge error {r.status_code}: {r.text}')
68
+
69
+ for raw in r.iter_lines(decode_unicode=True):
70
+ if self._stop_event.is_set():
71
+ break
72
+ if not raw:
73
+ continue
74
+ if not raw.startswith('data:'):
75
+ continue
76
+
77
+ line = raw[len('data:'):].lstrip()
78
+
79
+ if history_phase:
80
+ history_lines.append(line)
81
+ if time.time() >= history_deadline:
82
+ try:
83
+ self.history_handler(history_lines)
84
+ except Exception:
85
+ pass
86
+ history_phase = False
87
+ continue
88
+
89
+ try:
90
+ self.newline_handler(line)
91
+ except Exception:
92
+ pass
93
+
94
+ except Exception as e:
95
+ raise HungerBridgeError(f'Log stream failed: {e}')
96
+ finally:
97
+ if self._session:
98
+ try:
99
+ self._session.close()
100
+ except Exception:
101
+ pass
102
+ self._thread = None
103
+ self._session = None
104
+ self._stop_event = None
105
+
106
+ self._thread = threading.Thread(
107
+ target=_run,
108
+ name='HungerBridgeStream',
109
+ daemon=True
110
+ )
111
+ self._thread.start()
112
+
113
+ def disconnect(self):
114
+ if self._stop_event:
115
+ self._stop_event.set()
116
+ if self._session:
117
+ try:
118
+ self._session.close()
119
+ except Exception:
120
+ pass
121
+ self._thread = None
122
+ self._session = None
123
+ self._stop_event = None
124
+
125
+ def isConnected(self) -> bool: return self._thread is not None and self._thread.is_alive()
126
+
127
+ def getRaw(self) -> list: return list(self.raw_stream)
128
+ def getSanitized(self) -> list: return list(self.sanitized_stream)
129
+ def getTimestamped(self) -> dict: return dict(self.timestamped_stream)
130
+
131
+ @staticmethod
132
+ def sanitize(line: str) -> str:
133
+ ansi_re = re.compile(r'\x1b\[[0-9;]*m')
134
+ return ansi_re.sub('', line).rstrip
135
+
136
+ @staticmethod
137
+ def extractTimestamp(line: str):
138
+ m = re.match(r'\[([0-9]{2}:[0-9]{2}:[0-9]{2})\]', line)
139
+ if not m:
140
+ return None
141
+ return m.group(1)
142
+
143
+
6
144
  class BridgeClient:
7
- '''
8
- Python client for the HungerBridge v2 API
9
- '''
10
- def __init__(self, url: str, token: str):
145
+ '''Python client for the HungerBridge v2 API'''
146
+ def __init__(self, url: str, token: str, history_handler=None, newline_handler=None):
11
147
  self.base = url.rstrip('/') + '/v2/'
12
148
  self.headers = {
13
149
  'X-Auth-Key': token,
14
150
  'Content-Type': 'application/json'
15
151
  }
16
152
 
153
+ self.stream = Stream(
154
+ base_url=self.base,
155
+ headers=self.headers,
156
+
157
+ history_handler=history_handler,
158
+ newline_handler=newline_handler
159
+ )
160
+
17
161
  # internal helpers
18
162
  def _post(self, path: str, payload):
19
163
  r = requests.post(self.base + path, headers=self.headers, json=payload)
@@ -87,9 +231,7 @@ class BridgeClient:
87
231
  return None
88
232
 
89
233
  def log(self, message: str, level: str = 'info') -> dict:
90
- '''
91
- Logs a message to the server console
92
- '''
234
+ '''Logs a message to the server console'''
93
235
  valid_levels = ['info', 'warn', 'error', None]
94
236
  if level not in valid_levels:
95
237
  raise InvalidLevelError(f'\'{level}\' is not a valid log level')
@@ -106,9 +248,7 @@ class BridgeClient:
106
248
 
107
249
  # convenience getters
108
250
  def getPing(self) -> int:
109
- '''
110
- Round-trip latency (ms) measured client-side.
111
- '''
251
+ '''Round-trip latency (ms) measured client-side.'''
112
252
  start = time.time()
113
253
  self.v2_ping()
114
254
  end = time.time()
@@ -16,8 +16,11 @@ class MinecraftServer(GenericServer):
16
16
  server_id: str,
17
17
  server_domain: str,
18
18
  server_port: int,
19
+
19
20
  bridge_url: str,
20
21
  bridge_token: str,
22
+ history_handler=None,
23
+ newline_handler=None,
21
24
  ):
22
25
  super().__init__(
23
26
  name,
@@ -30,18 +33,17 @@ class MinecraftServer(GenericServer):
30
33
  self.server_port = server_port
31
34
 
32
35
  # HungerBridge client
33
- self.bridge = BridgeClient(bridge_url, bridge_token)
36
+ self.bridge = BridgeClient(bridge_url, bridge_token, history_handler=history_handler, newline_handler=newline_handler)
34
37
 
35
38
 
36
- # basic information properties
37
- @property
38
- def bridge_version(self) -> str | None:
39
+ # basic getter methods
40
+ def getBridgeVersion(self) -> str | None:
39
41
  return self.bridge.getVersion()
40
- @property
41
- def version(self) -> str | None:
42
+
43
+ def getVersion(self) -> str | None:
42
44
  return self.bridge.getMinecraftVersion()
43
- @property
44
- def platform(self) -> str | None:
45
+
46
+ def getPlatform(self) -> str | None:
45
47
  return self.bridge.getPlatform()
46
48
 
47
49
 
@@ -54,15 +56,7 @@ class MinecraftServer(GenericServer):
54
56
  else:
55
57
  raise InvalidModeError(f"Invalid mode: '{mode}'")
56
58
 
57
- @property
58
- def player_count(self) -> int:
59
- return self.getPlayers(mode='count') or 0
60
- @property
61
- def player_list(self) -> list[str]:
62
- return self.getPlayers('list') or []
63
-
64
- @property
65
- def max_players(self) -> int:
59
+ def getMaxPlayers(self) -> int:
66
60
  '''
67
61
  Runs the 'list' command and extracts the max player count.
68
62
  Expected format:
@@ -96,10 +90,6 @@ class MinecraftServer(GenericServer):
96
90
  return None
97
91
  return round(value, rounding) if rounding is not None else value
98
92
 
99
- @property
100
- def tps(self) -> float | None:
101
- return self.getTPS()
102
-
103
93
 
104
94
  # commands
105
95
  def sendConsoleCommand(
@@ -122,3 +112,11 @@ class MinecraftServer(GenericServer):
122
112
  safe = message.replace('"', '\\"')
123
113
  cmd = f'tellraw @a {{"text":"{safe}"}}'
124
114
  return self.bridge.runCommand(cmd, show_console=True)
115
+
116
+ # stream passthrough methods
117
+ def connectStream(self, keepalive: int=15): self.bridge.stream.connect(keepalive)
118
+ def disconnectStream(self): self.bridge.stream.disconnect()
119
+ def isStreamConnected(self): self.bridge.stream.isConnected()
120
+ def getRawStream(self): self.bridge.streamgetRaw()
121
+ def getSanitizedStream(self): self.bridge.stream.getSanitized()
122
+ def getTimestampedStream(self): self.bridge.stream.getTimestamped()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hungerlib
3
- Version: 4.24.2
3
+ Version: 4.25.dev4
4
4
  Summary: Powerful automation library for Pterodactyl.
5
5
  Author: iFamished
6
6
  License: MIT
File without changes
File without changes
File without changes