serverwatcher 5.8.dev5__py3-none-any.whl → 5.8.dev7__py3-none-any.whl

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.
@@ -6,6 +6,7 @@ def yaml_key(path: str, default=None):
6
6
  @dataclass
7
7
  class GlobalConfig:
8
8
  watch_interval: int = yaml_key("watch_interval")
9
+ timezone: str = yaml_key("timezone")
9
10
 
10
11
  panel_name: str = yaml_key("panel.name")
11
12
  panel_url: str = yaml_key("panel.url")
@@ -25,7 +26,6 @@ class GlobalConfig:
25
26
  enable_logging: bool = yaml_key("logger.enabled")
26
27
  logger_name: str = yaml_key("logger.name")
27
28
  log_path: str = yaml_key("logger.log_path")
28
- timezone: str = yaml_key("logger.timezone")
29
29
 
30
30
  console_backspaces: int = yaml_key("terminal.backspaces")
31
31
  clear_terminal: bool = yaml_key("terminal.enable_clearing")
@@ -19,16 +19,16 @@ class MessagesConfig:
19
19
  minute_1: str = yaml_key("broadcast_minutes.1")
20
20
 
21
21
  # second messages
22
- second_10: str = yaml_key("broadcast_seconds.10")
23
- second_9: str = yaml_key("broadcast_seconds.9")
24
- second_8: str = yaml_key("broadcast_seconds.8")
25
- second_7: str = yaml_key("broadcast_seconds.7")
26
- second_6: str = yaml_key("broadcast_seconds.6")
27
- second_5: str = yaml_key("broadcast_seconds.5")
28
- second_4: str = yaml_key("broadcast_seconds.4")
29
- second_3: str = yaml_key("broadcast_seconds.3")
30
- second_2: str = yaml_key("broadcast_seconds.2")
31
- second_1: str = yaml_key("broadcast_seconds.1")
22
+ second_10: str = yaml_key("broadcast_seconds.10", default="{prefix} Restart in 10 seconds!")
23
+ second_9: str = yaml_key("broadcast_seconds.9", default="{prefix} Restart in 9 seconds!")
24
+ second_8: str = yaml_key("broadcast_seconds.8", default="{prefix} Restart in 8 seconds!")
25
+ second_7: str = yaml_key("broadcast_seconds.7", default="{prefix} Restart in 7 seconds!")
26
+ second_6: str = yaml_key("broadcast_seconds.6", default="{prefix} Restart in 6 seconds!")
27
+ second_5: str = yaml_key("broadcast_seconds.5", default="{prefix} Restart in 5 seconds!")
28
+ second_4: str = yaml_key("broadcast_seconds.4", default="{prefix} Restart in 4 seconds!")
29
+ second_3: str = yaml_key("broadcast_seconds.3", default="{prefix} Restart in 3 seconds!")
30
+ second_2: str = yaml_key("broadcast_seconds.2", default="{prefix} Restart in 2 seconds!")
31
+ second_1: str = yaml_key("broadcast_seconds.1", default="{prefix} Restart in 1 second!")
32
32
 
33
33
  # logging
34
34
  startup: str = yaml_key("logging.startup")
@@ -1,4 +1,5 @@
1
1
  watch_interval: 300
2
+ timezone: 'America/Chicago'
2
3
 
3
4
  panel:
4
5
  name: 'My Panel'
@@ -21,7 +22,6 @@ logger:
21
22
  enabled: True
22
23
  name: 'Server Watcher'
23
24
  log_path: '/home/container/logs/'
24
- timezone: 'America/Chicago'
25
25
 
26
26
  terminal:
27
27
  backspaces: 8
@@ -46,7 +46,7 @@ reasons:
46
46
  uptime: 'Uptime {uptime} exceeds {threshold}h'
47
47
  tps: 'TPS {tps} is lower than {threshold}'
48
48
  low_uptime: 'Uptime {uptime} is shorter than 30m'
49
- players: 'There {verb} {count} {plural} online'
49
+ players: 'There {verb} {count} {plural} online' # produces: "There are 2 players online" or "There is 1 player online"
50
50
 
51
51
  pro_restart_number: 'Pro-restart: '
52
52
  anti_restart_number: 'Anti-restart:'
serverwatcher/watcher.py CHANGED
@@ -1,4 +1,3 @@
1
- # serverwatcher.py
2
1
  import os
3
2
  import time
4
3
  import re
@@ -27,6 +26,7 @@ validate_all()
27
26
  _T_EXPR = re.compile(r"{([^{}]+)}")
28
27
 
29
28
  def t_eval(template: str, /, **ctx):
29
+ # evaluate inline expressions inside message templates
30
30
  def repl(match):
31
31
  expr = match.group(1).strip()
32
32
  try:
@@ -37,7 +37,6 @@ def t_eval(template: str, /, **ctx):
37
37
 
38
38
  class ServerWatcher:
39
39
  def __init__(self):
40
-
41
40
  self.config = loadConfig(
42
41
  "config/config.yaml",
43
42
  "/defaultconfigs/config.yaml",
@@ -79,10 +78,12 @@ class ServerWatcher:
79
78
  tpsCommand=self.config.tps_command,
80
79
  )
81
80
 
81
+ # formatted logger name
82
82
  logger_name = self.config.logger_name.format(
83
83
  server_name=self.config.server_name
84
84
  )
85
85
 
86
+ # initialize message router
86
87
  self.router = MessageRouter(
87
88
  name=logger_name,
88
89
  server=self.server,
@@ -91,44 +92,67 @@ class ServerWatcher:
91
92
  console_backspaces=self.config.console_backspaces,
92
93
  )
93
94
 
95
+ # timezone for scheduling
94
96
  self.tz = ZoneInfo(self.config.timezone)
95
97
 
96
98
  def fmt(self, template: str, **fmt):
99
+ # apply t-eval formatting to templates
97
100
  return t_eval(template, self=self, **fmt)
101
+
102
+ def say(self, template, level="info", **fmt):
103
+ if not template:
104
+ return
105
+ self.router.say(
106
+ template,
107
+ level=level,
108
+ log=self.config.enable_logging,
109
+ **fmt
110
+ )
111
+
112
+
98
113
 
99
114
  def shutdown(self):
100
- self.router.say(self.messages.shutdown)
115
+ self.say(self.messages.shutdown)
101
116
  raise SystemExit
102
117
 
103
118
  def restart_and_wait(self):
119
+ # disable schedule if configured
104
120
  if self.watcherconfig.schedule_control:
105
121
  self.origin.disableSchedule(self.watcherconfig.restart_soon_id)
122
+
123
+ # send restart command
106
124
  self.server.restart()
107
- self.router.say(self.messages.restart_action_sent)
125
+ self.say(self.messages.restart_action_sent)
108
126
  time.sleep(self.watcherconfig.restart_wait_seconds)
109
127
 
110
- self.router.say(self.messages.status_check, level="warn")
128
+ # check server status
129
+ self.say(self.messages.status_check, level="warn")
111
130
  alive = waitForOnline(
112
131
  self.server,
113
132
  timeout=self.watcherconfig.restart_timeout,
114
133
  interval=self.watcherconfig.restart_online_interval,
115
134
  )
116
135
 
136
+ # handle restart result
117
137
  if alive:
118
- self.router.say(self.messages.server_back_online)
119
- self.router.say(self.messages.server_back_online_broadcast, broadcast=True)
138
+ self.say(self.messages.server_back_online)
139
+ self.say(self.messages.server_back_online_broadcast, broadcast=True)
120
140
  else:
121
- self.router.say(self.messages.server_failed_restart, level="error")
141
+ self.say(self.messages.server_failed_restart, level="error")
122
142
 
123
143
  def schedule_restart(self, minutes):
144
+ # compute scheduled restart time
124
145
  info = snapSchedule(minimumMinutes=minutes)
125
146
  scheduled = info["scheduled"]
126
147
 
148
+ # format local time
127
149
  local_time = scheduled.astimezone(self.tz)
128
150
  time_str = local_time.strftime("%I:%M %p")
129
151
 
152
+ # broadcast restart time
130
153
  self.router.broadcast(self.fmt(self.messages.broadcast_restart_at, time=time_str))
131
154
 
155
+ # build minute callbacks
132
156
  minute_callbacks = {
133
157
  int(k.split("_")[1]): (
134
158
  lambda msg=self.fmt(getattr(self.messages, k)):
@@ -138,6 +162,7 @@ class ServerWatcher:
138
162
  if k.startswith("minute_")
139
163
  }
140
164
 
165
+ # build second callbacks
141
166
  second_callbacks = {
142
167
  int(k.split("_")[1]): (
143
168
  lambda msg=self.fmt(getattr(self.messages, k)):
@@ -147,6 +172,7 @@ class ServerWatcher:
147
172
  if k.startswith("second_")
148
173
  }
149
174
 
175
+ # run countdown events
150
176
  runCountdownEvents(
151
177
  target_time=scheduled,
152
178
  minute_callbacks=minute_callbacks,
@@ -154,32 +180,40 @@ class ServerWatcher:
154
180
  )
155
181
 
156
182
  def evaluate(self):
157
- self.router.say(self.messages.startup)
183
+ # announce evaluation start
184
+ self.say(self.messages.startup)
158
185
 
186
+ # validate panel and server
159
187
  if not validateAll(self.panel, self.server):
160
- self.router.say(self.messages.validation_fail, level="error")
188
+ self.say(self.messages.validation_fail, level="error")
161
189
  self.shutdown()
162
190
 
191
+ # refresh server state
163
192
  self.server.refresh()
164
193
  snap = Snapshot(self.server, 2, True)
165
194
 
195
+ # scoring variables
166
196
  pro = 0
167
197
  anti = 0
168
198
  restart_reasons = []
169
199
  no_restart_reasons = []
170
200
 
201
+ # check schedule flag
171
202
  if self.watcherconfig.schedule_control and self.server.getSchedule(self.watcherconfig.restart_soon_id)["is_active"]:
172
203
  restart_reasons.append(self.messages.reason_restart_soon)
173
204
  pro += self.watcherconfig.weight_restart_soon
174
205
 
206
+ # check RAM threshold
175
207
  if snap.ram >= self.watcherconfig.threshold_ram:
176
208
  restart_reasons.append(self.fmt(self.messages.reason_ram, ram=snap.ram, threshold=self.watcherconfig.threshold_ram))
177
209
  pro += int(round(snap.ram, 0) - (self.watcherconfig.threshold_ram - 1))
178
210
 
211
+ # check CPU threshold
179
212
  if snap.cpu >= self.watcherconfig.threshold_cpu:
180
213
  restart_reasons.append(self.fmt(self.messages.reason_cpu, cpu=snap.cpu, threshold=self.watcherconfig.threshold_cpu))
181
214
  pro += self.watcherconfig.weight_cpu
182
215
 
216
+ # check uptime threshold
183
217
  if snap.uptime // 3600 >= self.watcherconfig.threshold_uptime:
184
218
  restart_reasons.append(
185
219
  self.fmt(self.messages.reason_uptime, uptime=snap.uptime_formatted,
@@ -187,55 +221,69 @@ class ServerWatcher:
187
221
  )
188
222
  pro += self.watcherconfig.weight_uptime
189
223
 
224
+ # check TPS threshold
190
225
  if (snap.tps if snap.tps is not None else 20) <= self.watcherconfig.threshold_tps:
191
226
  restart_reasons.append(self.fmt(self.messages.reason_tps, tps=snap.tps, threshold=self.watcherconfig.threshold_tps))
192
227
  pro += self.watcherconfig.weight_tps
193
228
 
229
+ # check low uptime penalty
194
230
  if snap.uptime // 60 < 30:
195
231
  no_restart_reasons.append(self.fmt(self.messages.reason_low_uptime, uptime=snap.uptime_formatted))
196
232
  anti += self.watcherconfig.weight_low_uptime
197
233
 
234
+ # check player count penalty
198
235
  if snap.players > 0:
199
236
  verb = "are" if snap.players != 1 else "is"
200
237
  plural = "players" if snap.players != 1 else "player"
201
238
  no_restart_reasons.append(self.fmt(self.messages.reason_players, verb=verb, count=snap.players, plural=plural))
202
239
  anti += snap.players * self.watcherconfig.weight_per_player
203
240
 
241
+ # output pro-restart reasons
204
242
  if restart_reasons:
205
- self.router.say(self.messages.pro_restart_splash, level="warn")
243
+ self.say(self.messages.pro_restart_splash, level="warn")
206
244
  for r in restart_reasons:
207
- self.router.say(f"{self.messages.bullet} {r}", level="warn")
245
+ self.say(f"{self.messages.bullet} {r}", level="warn")
208
246
 
247
+ # output anti-restart reasons
209
248
  if no_restart_reasons:
210
- self.router.say(self.messages.anti_restart_splash, level="warn")
249
+ self.say(self.messages.anti_restart_splash, level="warn")
211
250
  for r in no_restart_reasons:
212
- self.router.say(f"{self.messages.bullet} {r}", level="warn")
251
+ self.say(f"{self.messages.bullet} {r}", level="warn")
213
252
 
214
- self.router.say(f"{self.messages.pro_restart_number} {pro}", level="warn")
215
- self.router.say(f"{self.messages.anti_restart_number} {anti}", level="warn")
253
+ # output scores
254
+ self.say(f"{self.messages.pro_restart_number} {pro}", level="warn")
255
+ self.say(f"{self.messages.anti_restart_number} {anti}", level="warn")
216
256
 
257
+ # compute gap
217
258
  gap = abs(pro - anti)
218
259
 
260
+ # no restart case
219
261
  if pro == 0:
220
- self.router.say(self.messages.no_restart)
262
+ self.say(self.messages.no_restart)
221
263
  return
222
264
 
265
+ # immediate restart case
223
266
  if pro > anti and snap.players == 0:
224
- self.router.say(self.messages.immediate_restart)
267
+ self.say(self.messages.immediate_restart)
225
268
  self.restart_and_wait()
226
269
  return
227
270
 
228
- self.router.say(self.messages.scheduled)
271
+ # scheduled restart case
272
+ self.say(self.messages.scheduled)
229
273
 
274
+ # choose schedule window
230
275
  if gap <= 2:
231
- self.router.say(self.messages.gap_low, level="warn", gap=gap)
276
+ self.say(self.messages.gap_low, level="warn", gap=gap)
232
277
  self.schedule_restart(self.watcherconfig.low_gap_minutes)
233
278
  else:
234
- self.router.say(self.messages.gap_high, level="warn", gap=gap)
279
+ self.say(self.messages.gap_high, level="warn", gap=gap)
235
280
  self.schedule_restart(self.watcherconfig.high_gap_minutes)
236
281
 
282
+ # perform restart
237
283
  self.restart_and_wait()
238
284
 
285
+
286
+ # main loop
239
287
  def run(self):
240
288
  if self.config.clear_terminal:
241
289
  clearTerminal()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 5.8.dev5
3
+ Version: 5.8.dev7
4
4
  Summary: A HungerLib-powered Minecraft server automation engine.
5
5
  Author: iFamished
6
6
  License: GPL-3.0
@@ -0,0 +1,15 @@
1
+ serverwatcher/__init__.py,sha256=Q_afN0XU29n48d6Gf0-LT2lLo3RiTWlHRT6rC_fYbjw,486
2
+ serverwatcher/validator.py,sha256=W1-RX8UQWeO2DKEe3vC1_U6xISe_WnAVXHYT0pf4uWc,4753
3
+ serverwatcher/watcher.py,sha256=t9NJ87eTQn0UUumkjudkwA9Z56G4RGciEpfqddtIYbw,9781
4
+ serverwatcher/configclasses/__init__.py,sha256=YS0KhxtAJGdMcaiFstqTRNxIPLnR7s9v3Tkt5h2uKE4,182
5
+ serverwatcher/configclasses/config.py,sha256=g5QF_QxyQxcKRYagBCoozBYWT70ibpP684bpFg74SGM,1103
6
+ serverwatcher/configclasses/messages.py,sha256=g3Ko1R7I3zTiAm7J58eYnNHEIncRuLWelmLudhW9N6Q,3208
7
+ serverwatcher/configclasses/watcher.py,sha256=urQvRr8b7OjK0sm5eovSg9S3vo0LWZxE0cqpwX6NXbE,1230
8
+ serverwatcher/defaultconfigs/config.yaml,sha256=7jAFWDkC6S68z6co0A_9H8vPYPDKDvDeopaaDHUX_Ks,459
9
+ serverwatcher/defaultconfigs/messages.yaml,sha256=OthW7v-KzORPOUQuhXVjG6n82pW4TM317f4dGLQPDvA,2169
10
+ serverwatcher/defaultconfigs/watcher.yaml,sha256=1XUr7p5qRiaZkSccULVgEAGvHMFOM2IPNBRxdnG86NA,380
11
+ serverwatcher-5.8.dev7.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
+ serverwatcher-5.8.dev7.dist-info/METADATA,sha256=VV_Yb8GPYBQQLNeW7fVRA-XObIMnVOAj2ro3OjZ-Yvc,1686
13
+ serverwatcher-5.8.dev7.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
14
+ serverwatcher-5.8.dev7.dist-info/top_level.txt,sha256=8DJAf8WmmglgtZHkp8aoTriRJ2YPcS4F3DfOIkytASo,14
15
+ serverwatcher-5.8.dev7.dist-info/RECORD,,
@@ -1,15 +0,0 @@
1
- serverwatcher/__init__.py,sha256=Q_afN0XU29n48d6Gf0-LT2lLo3RiTWlHRT6rC_fYbjw,486
2
- serverwatcher/validator.py,sha256=W1-RX8UQWeO2DKEe3vC1_U6xISe_WnAVXHYT0pf4uWc,4753
3
- serverwatcher/watcher.py,sha256=B6Y23pbqqUPtl6a1j1c6XwGJ-EFRv91MoC8YcR6kUUw,8502
4
- serverwatcher/configclasses/__init__.py,sha256=YS0KhxtAJGdMcaiFstqTRNxIPLnR7s9v3Tkt5h2uKE4,182
5
- serverwatcher/configclasses/config.py,sha256=cnrRYaJ7W-SuUuVZI2tFgGWtmlLkMNNy51HxTud4tB8,1110
6
- serverwatcher/configclasses/messages.py,sha256=JZawv8_Kn9rns_bbuw0cuk5DhwinlueCao63NJIttXo,2770
7
- serverwatcher/configclasses/watcher.py,sha256=urQvRr8b7OjK0sm5eovSg9S3vo0LWZxE0cqpwX6NXbE,1230
8
- serverwatcher/defaultconfigs/config.yaml,sha256=lq-eTwAG4QQKIJKniMeEj9eD_DG06zMNf-C7Scqa9KI,461
9
- serverwatcher/defaultconfigs/messages.yaml,sha256=Zft8a1XrZj2YcdVg1njQM55RZTCZdDWzaxi2raIPeOo,2090
10
- serverwatcher/defaultconfigs/watcher.yaml,sha256=1XUr7p5qRiaZkSccULVgEAGvHMFOM2IPNBRxdnG86NA,380
11
- serverwatcher-5.8.dev5.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
12
- serverwatcher-5.8.dev5.dist-info/METADATA,sha256=SqQIIAWImbrmG_IaZMY4QOG6dCap7o6SV2gjNjWx4Vw,1686
13
- serverwatcher-5.8.dev5.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
14
- serverwatcher-5.8.dev5.dist-info/top_level.txt,sha256=8DJAf8WmmglgtZHkp8aoTriRJ2YPcS4F3DfOIkytASo,14
15
- serverwatcher-5.8.dev5.dist-info/RECORD,,