serverwatcher 5.8.dev4__tar.gz → 5.8.dev6__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.
- {serverwatcher-5.8.dev4/src/serverwatcher.egg-info → serverwatcher-5.8.dev6}/PKG-INFO +1 -1
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/pyproject.toml +1 -1
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/watcher.py +47 -4
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6/src/serverwatcher.egg-info}/PKG-INFO +1 -1
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/LICENSE +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/README.md +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/setup.cfg +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/__init__.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/__init__.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/config.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/messages.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/watcher.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/config.yaml +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/messages.yaml +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/watcher.yaml +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/validator.py +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher.egg-info/SOURCES.txt +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher.egg-info/dependency_links.txt +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher.egg-info/requires.txt +0 -0
- {serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher.egg-info/top_level.txt +0 -0
|
@@ -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,27 +92,40 @@ 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)
|
|
98
|
-
|
|
101
|
+
|
|
99
102
|
def say(self, template, level="info", **fmt):
|
|
100
103
|
if not template:
|
|
101
104
|
return
|
|
102
|
-
self.router.say(
|
|
105
|
+
self.router.say(
|
|
106
|
+
template,
|
|
107
|
+
level=level,
|
|
108
|
+
log=self.config.enable_logging,
|
|
109
|
+
**fmt
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
103
113
|
|
|
104
114
|
def shutdown(self):
|
|
105
115
|
self.say(self.messages.shutdown)
|
|
106
116
|
raise SystemExit
|
|
107
117
|
|
|
108
118
|
def restart_and_wait(self):
|
|
119
|
+
# disable schedule if configured
|
|
109
120
|
if self.watcherconfig.schedule_control:
|
|
110
121
|
self.origin.disableSchedule(self.watcherconfig.restart_soon_id)
|
|
122
|
+
|
|
123
|
+
# send restart command
|
|
111
124
|
self.server.restart()
|
|
112
125
|
self.say(self.messages.restart_action_sent)
|
|
113
126
|
time.sleep(self.watcherconfig.restart_wait_seconds)
|
|
114
127
|
|
|
128
|
+
# check server status
|
|
115
129
|
self.say(self.messages.status_check, level="warn")
|
|
116
130
|
alive = waitForOnline(
|
|
117
131
|
self.server,
|
|
@@ -119,6 +133,7 @@ class ServerWatcher:
|
|
|
119
133
|
interval=self.watcherconfig.restart_online_interval,
|
|
120
134
|
)
|
|
121
135
|
|
|
136
|
+
# handle restart result
|
|
122
137
|
if alive:
|
|
123
138
|
self.say(self.messages.server_back_online)
|
|
124
139
|
self.say(self.messages.server_back_online_broadcast, broadcast=True)
|
|
@@ -126,14 +141,18 @@ class ServerWatcher:
|
|
|
126
141
|
self.say(self.messages.server_failed_restart, level="error")
|
|
127
142
|
|
|
128
143
|
def schedule_restart(self, minutes):
|
|
144
|
+
# compute scheduled restart time
|
|
129
145
|
info = snapSchedule(minimumMinutes=minutes)
|
|
130
146
|
scheduled = info["scheduled"]
|
|
131
147
|
|
|
148
|
+
# format local time
|
|
132
149
|
local_time = scheduled.astimezone(self.tz)
|
|
133
150
|
time_str = local_time.strftime("%I:%M %p")
|
|
134
151
|
|
|
152
|
+
# broadcast restart time
|
|
135
153
|
self.router.broadcast(self.fmt(self.messages.broadcast_restart_at, time=time_str))
|
|
136
154
|
|
|
155
|
+
# build minute callbacks
|
|
137
156
|
minute_callbacks = {
|
|
138
157
|
int(k.split("_")[1]): (
|
|
139
158
|
lambda msg=self.fmt(getattr(self.messages, k)):
|
|
@@ -143,6 +162,7 @@ class ServerWatcher:
|
|
|
143
162
|
if k.startswith("minute_")
|
|
144
163
|
}
|
|
145
164
|
|
|
165
|
+
# build second callbacks
|
|
146
166
|
second_callbacks = {
|
|
147
167
|
int(k.split("_")[1]): (
|
|
148
168
|
lambda msg=self.fmt(getattr(self.messages, k)):
|
|
@@ -152,6 +172,7 @@ class ServerWatcher:
|
|
|
152
172
|
if k.startswith("second_")
|
|
153
173
|
}
|
|
154
174
|
|
|
175
|
+
# run countdown events
|
|
155
176
|
runCountdownEvents(
|
|
156
177
|
target_time=scheduled,
|
|
157
178
|
minute_callbacks=minute_callbacks,
|
|
@@ -159,32 +180,40 @@ class ServerWatcher:
|
|
|
159
180
|
)
|
|
160
181
|
|
|
161
182
|
def evaluate(self):
|
|
183
|
+
# announce evaluation start
|
|
162
184
|
self.say(self.messages.startup)
|
|
163
185
|
|
|
186
|
+
# validate panel and server
|
|
164
187
|
if not validateAll(self.panel, self.server):
|
|
165
188
|
self.say(self.messages.validation_fail, level="error")
|
|
166
189
|
self.shutdown()
|
|
167
190
|
|
|
191
|
+
# refresh server state
|
|
168
192
|
self.server.refresh()
|
|
169
193
|
snap = Snapshot(self.server, 2, True)
|
|
170
194
|
|
|
195
|
+
# scoring variables
|
|
171
196
|
pro = 0
|
|
172
197
|
anti = 0
|
|
173
198
|
restart_reasons = []
|
|
174
199
|
no_restart_reasons = []
|
|
175
200
|
|
|
201
|
+
# check schedule flag
|
|
176
202
|
if self.watcherconfig.schedule_control and self.server.getSchedule(self.watcherconfig.restart_soon_id)["is_active"]:
|
|
177
203
|
restart_reasons.append(self.messages.reason_restart_soon)
|
|
178
204
|
pro += self.watcherconfig.weight_restart_soon
|
|
179
205
|
|
|
206
|
+
# check RAM threshold
|
|
180
207
|
if snap.ram >= self.watcherconfig.threshold_ram:
|
|
181
208
|
restart_reasons.append(self.fmt(self.messages.reason_ram, ram=snap.ram, threshold=self.watcherconfig.threshold_ram))
|
|
182
209
|
pro += int(round(snap.ram, 0) - (self.watcherconfig.threshold_ram - 1))
|
|
183
210
|
|
|
211
|
+
# check CPU threshold
|
|
184
212
|
if snap.cpu >= self.watcherconfig.threshold_cpu:
|
|
185
213
|
restart_reasons.append(self.fmt(self.messages.reason_cpu, cpu=snap.cpu, threshold=self.watcherconfig.threshold_cpu))
|
|
186
214
|
pro += self.watcherconfig.weight_cpu
|
|
187
215
|
|
|
216
|
+
# check uptime threshold
|
|
188
217
|
if snap.uptime // 3600 >= self.watcherconfig.threshold_uptime:
|
|
189
218
|
restart_reasons.append(
|
|
190
219
|
self.fmt(self.messages.reason_uptime, uptime=snap.uptime_formatted,
|
|
@@ -192,46 +221,57 @@ class ServerWatcher:
|
|
|
192
221
|
)
|
|
193
222
|
pro += self.watcherconfig.weight_uptime
|
|
194
223
|
|
|
224
|
+
# check TPS threshold
|
|
195
225
|
if (snap.tps if snap.tps is not None else 20) <= self.watcherconfig.threshold_tps:
|
|
196
226
|
restart_reasons.append(self.fmt(self.messages.reason_tps, tps=snap.tps, threshold=self.watcherconfig.threshold_tps))
|
|
197
227
|
pro += self.watcherconfig.weight_tps
|
|
198
228
|
|
|
229
|
+
# check low uptime penalty
|
|
199
230
|
if snap.uptime // 60 < 30:
|
|
200
231
|
no_restart_reasons.append(self.fmt(self.messages.reason_low_uptime, uptime=snap.uptime_formatted))
|
|
201
232
|
anti += self.watcherconfig.weight_low_uptime
|
|
202
233
|
|
|
234
|
+
# check player count penalty
|
|
203
235
|
if snap.players > 0:
|
|
204
236
|
verb = "are" if snap.players != 1 else "is"
|
|
205
237
|
plural = "players" if snap.players != 1 else "player"
|
|
206
238
|
no_restart_reasons.append(self.fmt(self.messages.reason_players, verb=verb, count=snap.players, plural=plural))
|
|
207
239
|
anti += snap.players * self.watcherconfig.weight_per_player
|
|
208
240
|
|
|
241
|
+
# output pro-restart reasons
|
|
209
242
|
if restart_reasons:
|
|
210
243
|
self.say(self.messages.pro_restart_splash, level="warn")
|
|
211
244
|
for r in restart_reasons:
|
|
212
245
|
self.say(f"{self.messages.bullet} {r}", level="warn")
|
|
213
246
|
|
|
247
|
+
# output anti-restart reasons
|
|
214
248
|
if no_restart_reasons:
|
|
215
249
|
self.say(self.messages.anti_restart_splash, level="warn")
|
|
216
250
|
for r in no_restart_reasons:
|
|
217
251
|
self.say(f"{self.messages.bullet} {r}", level="warn")
|
|
218
252
|
|
|
253
|
+
# output scores
|
|
219
254
|
self.say(f"{self.messages.pro_restart_number} {pro}", level="warn")
|
|
220
255
|
self.say(f"{self.messages.anti_restart_number} {anti}", level="warn")
|
|
221
256
|
|
|
257
|
+
# compute gap
|
|
222
258
|
gap = abs(pro - anti)
|
|
223
259
|
|
|
260
|
+
# no restart case
|
|
224
261
|
if pro == 0:
|
|
225
262
|
self.say(self.messages.no_restart)
|
|
226
263
|
return
|
|
227
264
|
|
|
265
|
+
# immediate restart case
|
|
228
266
|
if pro > anti and snap.players == 0:
|
|
229
267
|
self.say(self.messages.immediate_restart)
|
|
230
268
|
self.restart_and_wait()
|
|
231
269
|
return
|
|
232
270
|
|
|
271
|
+
# scheduled restart case
|
|
233
272
|
self.say(self.messages.scheduled)
|
|
234
273
|
|
|
274
|
+
# choose schedule window
|
|
235
275
|
if gap <= 2:
|
|
236
276
|
self.say(self.messages.gap_low, level="warn", gap=gap)
|
|
237
277
|
self.schedule_restart(self.watcherconfig.low_gap_minutes)
|
|
@@ -239,8 +279,11 @@ class ServerWatcher:
|
|
|
239
279
|
self.say(self.messages.gap_high, level="warn", gap=gap)
|
|
240
280
|
self.schedule_restart(self.watcherconfig.high_gap_minutes)
|
|
241
281
|
|
|
282
|
+
# perform restart
|
|
242
283
|
self.restart_and_wait()
|
|
243
284
|
|
|
285
|
+
|
|
286
|
+
# main loop
|
|
244
287
|
def run(self):
|
|
245
288
|
if self.config.clear_terminal:
|
|
246
289
|
clearTerminal()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/messages.py
RENAMED
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/configclasses/watcher.py
RENAMED
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/config.yaml
RENAMED
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/messages.yaml
RENAMED
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher/defaultconfigs/watcher.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{serverwatcher-5.8.dev4 → serverwatcher-5.8.dev6}/src/serverwatcher.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|