serverwatcher 5.27__tar.gz → 5.27.2__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 (22) hide show
  1. {serverwatcher-5.27/src/serverwatcher.egg-info → serverwatcher-5.27.2}/PKG-INFO +1 -1
  2. {serverwatcher-5.27 → serverwatcher-5.27.2}/pyproject.toml +1 -1
  3. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/configclasses/config.py +15 -0
  4. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/configclasses/messages.py +5 -0
  5. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/configclasses/watcher.py +29 -0
  6. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/defaultconfigs/messages.yaml +1 -0
  7. serverwatcher-5.27.2/src/serverwatcher/validator.py +52 -0
  8. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/watcher.py +8 -5
  9. {serverwatcher-5.27 → serverwatcher-5.27.2/src/serverwatcher.egg-info}/PKG-INFO +1 -1
  10. serverwatcher-5.27/src/serverwatcher/validator.py +0 -121
  11. {serverwatcher-5.27 → serverwatcher-5.27.2}/LICENSE +0 -0
  12. {serverwatcher-5.27 → serverwatcher-5.27.2}/README.md +0 -0
  13. {serverwatcher-5.27 → serverwatcher-5.27.2}/setup.cfg +0 -0
  14. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/__init__.py +0 -0
  15. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/__main__.py +0 -0
  16. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/configclasses/__init__.py +0 -0
  17. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/defaultconfigs/config.yaml +0 -0
  18. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher/defaultconfigs/watcher.yaml +0 -0
  19. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher.egg-info/SOURCES.txt +0 -0
  20. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher.egg-info/dependency_links.txt +0 -0
  21. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher.egg-info/requires.txt +0 -0
  22. {serverwatcher-5.27 → serverwatcher-5.27.2}/src/serverwatcher.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 5.27
3
+ Version: 5.27.2
4
4
  Summary: A HungerLib-powered Minecraft server automation engine.
5
5
  Author: iFamished
6
6
  License: GPL-3.0
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
7
7
 
8
8
  [project]
9
9
  name = "serverwatcher"
10
- version = "5.27"
10
+ version = "5.27.2"
11
11
  description = "A HungerLib-powered Minecraft server automation engine."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.14"
@@ -56,3 +56,18 @@ class fallbacks:
56
56
 
57
57
  clear_terminal = True
58
58
  handle_keyboard_interrupt = True
59
+
60
+
61
+ class rules:
62
+ panel_url = "required"
63
+ panel_api_key = "required"
64
+ server_id = "required"
65
+ server_domain = "required"
66
+ bridge_token = "required"
67
+
68
+ timezone = "recommended"
69
+ panel_name = "recommended"
70
+ server_port = "recommended"
71
+ bridge_port = "recommended"
72
+
73
+ # everything else defaults to optional
@@ -33,6 +33,7 @@ class MessagesConfig:
33
33
  status_check: str = 'logging.status_check'
34
34
  validation_fail: str = 'logging.validation_fail'
35
35
  validation_ok: str = 'logging.validation_ok'
36
+ sampling_start: str = 'logging.sampling_start'
36
37
  shutdown: str = 'logging.shutdown'
37
38
  immediate_restart: str = 'logging.immediate_restart'
38
39
  no_restart: str = 'logging.no_restart'
@@ -88,6 +89,7 @@ class fallbacks:
88
89
  status_check = 'Checking server status...'
89
90
  validation_fail = 'Validation FAILED.'
90
91
  validation_ok = 'All validation checks succeeded.'
92
+ sampling_start = 'Starting sampling process...'
91
93
  shutdown = 'Shutting down ServerWatcher.'
92
94
  immediate_restart = 'Restarting immediately.'
93
95
  no_restart = 'The server does not need to restart.'
@@ -113,3 +115,6 @@ class fallbacks:
113
115
  server_back_online = 'Server is back online!'
114
116
  server_back_online_log = 'ServerWatcher successfully restarted the server.'
115
117
  server_failed_restart = 'Server failed to restart!'
118
+
119
+ class rules:
120
+ pass
@@ -68,3 +68,32 @@ class fallbacks:
68
68
  restart_wait_seconds = 30
69
69
  restart_timeout = 120
70
70
  restart_online_interval = 2
71
+
72
+
73
+ class rules:
74
+ threshold_ram = "required"
75
+ threshold_cpu = "required"
76
+ threshold_uptime = "required"
77
+ threshold_tps = "required"
78
+
79
+ restart_wait_seconds = "required"
80
+ restart_timeout = "required"
81
+ restart_online_interval = "required"
82
+
83
+ watch_interval = "recommended"
84
+ sample_duration = "recommended"
85
+ sample_interval = "recommended"
86
+ sample_outlier_drop = "recommended"
87
+ threshold_min_uptime = "recommended"
88
+ threshold_low_gap = "recommended"
89
+ snap_minutes = "recommended"
90
+ low_gap_minutes = "recommended"
91
+ high_gap_minutes = "recommended"
92
+
93
+ weight_restart_soon = "optional"
94
+ weight_ram = "optional"
95
+ weight_cpu = "optional"
96
+ weight_uptime = "optional"
97
+ weight_tps = "optional"
98
+ weight_low_uptime = "optional"
99
+ weight_per_player = "optional"
@@ -51,6 +51,7 @@ logging:
51
51
  status_check: 'Checking server status...'
52
52
  validation_fail: 'Validation FAILED.'
53
53
  validation_ok: 'All validation checks succeeded.'
54
+ sampling_start: 'Starting sampling process...'
54
55
  shutdown: 'Shutting down ServerWatcher.'
55
56
  immediate_restart: 'Restarting immediately.'
56
57
  no_restart: 'The server does not need to restart.'
@@ -0,0 +1,52 @@
1
+ import sys
2
+ from dataclasses import fields
3
+
4
+ from hungerlib import utils, loadConfig, Validator
5
+
6
+ from serverwatcher.configclasses.config import GlobalConfig
7
+ from serverwatcher.configclasses.messages import MessagesConfig
8
+ from serverwatcher.configclasses.watcher import WatcherConfig
9
+
10
+
11
+ utils.clearTerminal()
12
+
13
+ # You can customize messages here if you want
14
+ v = Validator()
15
+
16
+
17
+ def validate_global_config(c):
18
+ for f in fields(GlobalConfig):
19
+ if not f.name.startswith("__"):
20
+ v.check_field(c, f.name)
21
+
22
+
23
+ def validate_watcher_config(c):
24
+ for f in fields(WatcherConfig):
25
+ if not f.name.startswith("__"):
26
+ v.check_field(c, f.name)
27
+
28
+
29
+ def validate_messages_config(c):
30
+ for f in fields(MessagesConfig):
31
+ if not f.name.startswith("__"):
32
+ v.check_field(c, f.name)
33
+
34
+
35
+ def validate_all():
36
+ config = loadConfig(GlobalConfig)
37
+ messages = loadConfig(MessagesConfig)
38
+ watcher = loadConfig(WatcherConfig)
39
+
40
+ v.validate_key_types(config, GlobalConfig)
41
+ v.validate_key_types(messages, MessagesConfig)
42
+ v.validate_key_types(watcher, WatcherConfig)
43
+
44
+ validate_global_config(config)
45
+ validate_watcher_config(watcher)
46
+ validate_messages_config(messages)
47
+
48
+ return v.run(config, messages, watcher)
49
+
50
+
51
+ if __name__ == '__main__':
52
+ validate_all()
@@ -93,6 +93,10 @@ class ServerWatcher:
93
93
 
94
94
  self.tz = ZoneInfo(self.config.timezone)
95
95
 
96
+ def clearTerminal(self):
97
+ if self.config.clear_terminal:
98
+ utils.clearTerminal()
99
+
96
100
  def shutdown(self):
97
101
  self.router.info(self.messages.shutdown)
98
102
  raise SystemExit
@@ -165,8 +169,9 @@ class ServerWatcher:
165
169
  self.router.error(self.messages.validation_fail)
166
170
  self.shutdown()
167
171
 
172
+ self.router.info(self.messages.sampling_start)
168
173
  self.server.refresh()
169
- snap = utils.Snapshot(self.server, duration=self.watcherconfig.sample_duration, interval=self.watcher_config.sample_interval, drop_outliers=self.watcher_config.sample_outlier_drop, gb=True)
174
+ snap = utils.Snapshot(self.server, duration=self.watcherconfig.sample_duration, interval=self.watcherconfig.sample_interval, drop_outliers=self.watcherconfig.sample_outlier_drop, gb=True)
170
175
 
171
176
  pro = 0
172
177
  anti = 0
@@ -245,15 +250,13 @@ class ServerWatcher:
245
250
  if self.config.handle_keyboard_interrupt:
246
251
  try:
247
252
  while True:
248
- if self.config.clear_terminal:
249
- utils.clearTerminal()
253
+ self.clearTerminal()
250
254
  self.evaluate()
251
255
  time.sleep(self.watcherconfig.watch_interval)
252
256
  except KeyboardInterrupt:
253
257
  self.shutdown()
254
258
  else:
255
259
  while True:
256
- if self.config.clear_terminal:
257
- utils.clearTerminal()
260
+ self.clearTerminal()
258
261
  self.evaluate()
259
262
  time.sleep(self.watcherconfig.watch_interval)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 5.27
3
+ Version: 5.27.2
4
4
  Summary: A HungerLib-powered Minecraft server automation engine.
5
5
  Author: iFamished
6
6
  License: GPL-3.0
@@ -1,121 +0,0 @@
1
- import sys
2
- from dataclasses import fields
3
-
4
- from hungerlib import utils, loadConfig, Validator
5
-
6
- from serverwatcher.configclasses.config import GlobalConfig
7
- from serverwatcher.configclasses.messages import MessagesConfig
8
- from serverwatcher.configclasses.watcher import WatcherConfig
9
-
10
-
11
- utils.clearTerminal()
12
- v = Validator()
13
-
14
-
15
- def validate_global_config(config):
16
- c = config
17
-
18
- # timezone
19
- v.check_field(c, "timezone")
20
- if c.timezone == "":
21
- v.errors.append('timezone: must not be empty')
22
-
23
- # panel
24
- v.check_field(c, "panel_name")
25
- v.check_field(c, "panel_url", allow_fallback=False)
26
- v.check_field(c, "panel_api_key", allow_fallback=False)
27
-
28
- if c.panel_url and not (c.panel_url.startswith("http://") or c.panel_url.startswith("https://")):
29
- v.errors.append(f'panel_url: must start with "http://" or "https://" (got "{c.panel_url}")')
30
-
31
- if c.panel_api_key and not c.panel_api_key.startswith("ptlc_"):
32
- v.errors.append(f'panel_api_key: must be a valid Pterodactyl client API key (got "{c.panel_api_key}")')
33
- if c.panel_api_key and c.panel_api_key.startswith("plta_"):
34
- v.errors.append(f'panel_api_key: should not be an application key (got "{c.panel_api_key}")')
35
-
36
- # server
37
- v.check_field(c, "server_name")
38
- v.check_field(c, "server_id", allow_fallback=False)
39
- v.check_field(c, "server_domain", allow_fallback=False)
40
- v.check_field(c, "server_port")
41
-
42
- if c.server_domain and (c.server_domain.startswith("http://") or c.server_domain.startswith("https://")):
43
- v.errors.append(f'server_domain: must not contain protocol (got "{c.server_domain}")')
44
-
45
- if c.server_port is not None and not (1 <= c.server_port <= 65535):
46
- v.errors.append(f'server_port: must be 1–65535 (got "{c.server_port}")')
47
-
48
- # hungerbridge
49
- v.check_field(c, "bridge_token", allow_fallback=False)
50
- v.check_field(c, "bridge_port")
51
- if c.bridge_port is not None and not (1 <= c.bridge_port <= 65535):
52
- v.errors.append(f'bridge_port: must be 1–65535 (got "{c.bridge_port}")')
53
-
54
- # logger
55
- for key in [
56
- "enable_logging", "logger_name", "log_path",
57
- "info_prefix", "warn_prefix", "error_prefix"
58
- ]:
59
- v.check_field(c, key)
60
-
61
- # terminal
62
- v.check_field(c, "clear_terminal")
63
- v.check_field(c, "handle_keyboard_interrupt")
64
-
65
-
66
- def validate_watcher_config(watcherconfig):
67
- c = watcherconfig
68
- raw = c.raw
69
- fb = c.fallbacks
70
-
71
- if c.restart_wait_seconds <= 0:
72
- v.errors.append(f'restart_wait_seconds: must be > 0 (got {c.restart_wait_seconds})')
73
-
74
- if c.threshold_cpu <= 0:
75
- v.errors.append(f'threshold_cpu: must be > 0 (got {c.threshold_cpu})')
76
-
77
- if c.threshold_ram <= 0:
78
- v.errors.append(f'threshold_ram: must be > 0 (got {c.threshold_ram})')
79
-
80
- if c.threshold_tps <= 0 or c.threshold_tps > 20:
81
- v.errors.append(f'threshold_tps: must be 1–20 (got "{c.threshold_tps}")')
82
-
83
- if raw.snap_minutes is None:
84
- v.warnings.append(f'snap_minutes: key does not exist, using fallback "{fb.snap_minutes}"')
85
-
86
- if not isinstance(c.snap_minutes, list) or not c.snap_minutes:
87
- v.errors.append(f'snap_minutes: must be a non-empty list of minute marks (got {c.snap_minutes!r})')
88
- else:
89
- bad = [m for m in c.snap_minutes if not isinstance(m, int) or not (0 <= m <= 59)]
90
- if bad:
91
- v.errors.append(f'snap_minutes: all values must be integers 0–59 (bad values: {bad})')
92
-
93
-
94
- def validate_messages_config(messages):
95
- pass # may add validation later
96
- # for f in fields(MessagesConfig):
97
- # if f.name.startswith("__"):
98
- # continue
99
- # value = getattr(messages, f.name)
100
- # if not isinstance(value, str) or value.strip() == "":
101
- # v.errors.append(f'MessagesConfig.{f.name}: must be a non-empty string')
102
-
103
-
104
- def validate_all():
105
- config = loadConfig(GlobalConfig)
106
- messages = loadConfig(MessagesConfig)
107
- watcherconfig = loadConfig(WatcherConfig)
108
-
109
- v.validate_key_types(config, GlobalConfig)
110
- v.validate_key_types(messages, MessagesConfig)
111
- v.validate_key_types(watcherconfig, WatcherConfig)
112
-
113
- validate_global_config(config)
114
- validate_watcher_config(watcherconfig)
115
- validate_messages_config(messages)
116
-
117
- return v.run(config, messages, watcherconfig)
118
-
119
-
120
- if __name__ == '__main__':
121
- validate_all()
File without changes
File without changes
File without changes