serverwatcher 3.9.1__tar.gz → 4.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.
Files changed (20) hide show
  1. {serverwatcher-3.9.1/src/serverwatcher.egg-info → serverwatcher-4.0}/PKG-INFO +1 -1
  2. {serverwatcher-3.9.1 → serverwatcher-4.0}/pyproject.toml +1 -1
  3. {serverwatcher-3.9.1 → serverwatcher-4.0}/src/serverwatcher/__init__.py +6 -2
  4. serverwatcher-4.0/src/serverwatcher/defaultconfigs/global.yaml +16 -0
  5. serverwatcher-4.0/src/serverwatcher/defaultconfigs/messages.yaml +51 -0
  6. serverwatcher-4.0/src/serverwatcher/defaultconfigs/watcher.yaml +39 -0
  7. {serverwatcher-3.9.1 → serverwatcher-4.0}/src/serverwatcher/watcher.py +48 -42
  8. {serverwatcher-3.9.1 → serverwatcher-4.0/src/serverwatcher.egg-info}/PKG-INFO +1 -1
  9. serverwatcher-4.0/src/serverwatcher.egg-info/SOURCES.txt +17 -0
  10. serverwatcher-3.9.1/src/serverwatcher.egg-info/SOURCES.txt +0 -14
  11. {serverwatcher-3.9.1 → serverwatcher-4.0}/LICENSE +0 -0
  12. {serverwatcher-3.9.1 → serverwatcher-4.0}/README.md +0 -0
  13. {serverwatcher-3.9.1 → serverwatcher-4.0}/setup.cfg +0 -0
  14. {serverwatcher-3.9.1/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/__init__.py +0 -0
  15. {serverwatcher-3.9.1/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/global_config.py +0 -0
  16. {serverwatcher-3.9.1/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/messages.py +0 -0
  17. {serverwatcher-3.9.1/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/watcher.py +0 -0
  18. {serverwatcher-3.9.1 → serverwatcher-4.0}/src/serverwatcher.egg-info/dependency_links.txt +0 -0
  19. {serverwatcher-3.9.1 → serverwatcher-4.0}/src/serverwatcher.egg-info/requires.txt +0 -0
  20. {serverwatcher-3.9.1 → serverwatcher-4.0}/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: 3.9.1
3
+ Version: 4.0
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 = "3.9.1"
10
+ version = "4.0"
11
11
  description = "A HungerLib-powered Minecraft server automation engine."
12
12
  readme = "README.md"
13
13
  requires-python = ">=3.10"
@@ -7,9 +7,13 @@ except PackageNotFoundError:
7
7
  __version__ = '0.0.0'
8
8
 
9
9
  from .watcher import ServerWatcher
10
-
10
+ from .configclasses.global_config import GlobalConfig
11
+ from .configclasses.messages import MessagesConfig
12
+ from .configclasses.watcher import WatcherConfig
11
13
 
12
14
  __all__ = [
13
- # core utilities
14
15
  'ServerWatcher',
16
+ 'GlobalConfig',
17
+ 'MessagesConfig',
18
+ 'WatcherConfig',
15
19
  ]
@@ -0,0 +1,16 @@
1
+ panel:
2
+ panel_name: My Panel
3
+ panel_url: https://example.com
4
+ panel_api_key: CHANGE_ME
5
+
6
+ origin:
7
+ origin_server_id: CHANGE_ME
8
+
9
+ server:
10
+ server_name: My SMP
11
+ server_id: CHANGE_ME
12
+ server_domain: mc.example.com
13
+ server_port: 25565
14
+ rcon_port: 25575
15
+ rcon_password: password
16
+ tps_command: ticks
@@ -0,0 +1,51 @@
1
+ prefix: "<aqua>[Server Watcher]"
2
+
3
+ broadcast_restart_at: "{prefix} The server will restart at {time} CDT."
4
+
5
+ broadcast_minute:
6
+ minute_120: "{prefix} Restart in 2 hours!"
7
+ minute_60: "{prefix} Restart in 1 hour!"
8
+ minute_45: "{prefix} Restart in 45 minutes!"
9
+ minute_30: "{prefix} Restart in 30 minutes!"
10
+ minute_15: "{prefix} Restart in 15 minutes!"
11
+ minute_5: "{prefix} Restart in 5 minutes!"
12
+ minute_1: "{prefix} Restart in 1 minute!"
13
+
14
+ broadcast_second:
15
+ second_10: "{prefix} Restart in 10 seconds!"
16
+ second_9: "{prefix} Restart in 9 seconds!"
17
+ second_8: "{prefix} Restart in 8 seconds!"
18
+ second_7: "{prefix} Restart in 7 seconds!"
19
+ second_6: "{prefix} Restart in 6 seconds!"
20
+ second_5: "{prefix} Restart in 5 seconds!"
21
+ second_4: "{prefix} Restart in 4 seconds!"
22
+ second_3: "{prefix} Restart in 3 seconds!"
23
+ second_2: "{prefix} Restart in 2 seconds!"
24
+ second_1: "{prefix} Restart in 1 second!"
25
+
26
+ logging:
27
+ log_start: "ServerWatcher is running!"
28
+ log_status_check: "Checking server status..."
29
+ log_validation_fail: "Validation FAILED."
30
+ log_validation_ok: "All validation checks succeeded."
31
+ log_shutdown: "Shutting down ServerWatcher."
32
+ log_immediate_restart: "Restarting immediately."
33
+ log_no_restart: "The server does not need to restart."
34
+ log_scheduled: "Restart needed, but anti-restart factors outweigh it."
35
+ log_gap_low: "Gap {gap}. Scheduling restart in 2 hours."
36
+ log_gap_high: "Gap {gap}. Scheduling restart in 1 hour."
37
+
38
+ reasons:
39
+ reason_restart_soon: "The server is set to restart soon"
40
+ reason_ram: "RAM usage ({ram}) is higher than {threshold} GB"
41
+ reason_cpu: "CPU usage ({cpu}) is higher than {threshold}%"
42
+ reason_uptime: "Uptime {uptime} exceeds {threshold}h"
43
+ reason_tps: "TPS {tps} is lower than {threshold}"
44
+ reason_low_uptime: "Uptime {uptime} is shorter than 30m"
45
+ reason_players: "There {verb} {count} {plural} online"
46
+
47
+ restarts:
48
+ restart_action_sent: "Restart action sent. Waiting..."
49
+ server_back_online: "Server is back online!"
50
+ server_back_online_broadcast: "{prefix} <green>Restart successful!"
51
+ server_failed_restart: "Server failed to restart!"
@@ -0,0 +1,39 @@
1
+ logging:
2
+ logger_name_template: "Server Watcher"
3
+ log_path: "/home/container/logs/"
4
+ timezone: "America/Chicago"
5
+
6
+ terminal_settings:
7
+ console_backspaces: 8
8
+ clear_terminal: True
9
+
10
+ schedules:
11
+ restart_soon_schedule_id: 0 # replace this with real schedule id
12
+ origin_disable_schedule_id: 0 # replace this with real schedule id
13
+
14
+ thresolds:
15
+ ram_threshold: 6
16
+ cpu_threshold: 150
17
+ uptime_hours_threshold: 12
18
+ tps_threshold: 19.5
19
+
20
+ weights:
21
+ weight_restart_soon: 3
22
+ weight_ram: 1
23
+ weight_cpu: 1
24
+ weight_uptime: 1
25
+ weight_tps: 1
26
+ weight_low_uptime: 5
27
+ weight_per_player: 1
28
+
29
+ gaps:
30
+ low_gap_minutes: 120
31
+ high_gap_minutes: 60
32
+
33
+ restart_intervals:
34
+ restart_wait_seconds: 45
35
+ restart_online_timeout: 120
36
+ restart_online_interval: 2
37
+
38
+ watcher_intervals:
39
+ watch_interval: 60
@@ -11,34 +11,47 @@ from hungerlib.addons import (
11
11
  waitForOnline,
12
12
  validateAll,
13
13
  runCountdownEvents,
14
+ loadConfig,
14
15
  )
15
- from hungerlib.addons.configmap import load_or_default
16
16
 
17
- # Set directory
18
- BASE_DIR = os.getcwd()
19
- PACKAGE_DIR = os.path.dirname(__file__)
17
+ from serverwatcher import GlobalConfig, MessagesConfig, WatcherConfig
20
18
 
21
19
 
22
20
  class ServerWatcher:
23
21
  def __init__(self):
24
- # Load all configs in /config using configmap
25
- cfgmap = load_or_default("config", skip_files=[])
26
22
 
27
- self.global_cfg = cfgmap["global.yaml"]
28
- self.messages = cfgmap["messages.yaml"]
29
- self.cfg = cfgmap["watcher.yaml"]
23
+ # load configs
24
+ self.global_cfg = loadConfig(
25
+ "config/global.yaml",
26
+ "/defaultconfigs/global.yaml",
27
+ GlobalConfig
28
+ )
30
29
 
30
+ self.messages = loadConfig(
31
+ "config/messages.yaml",
32
+ "/defaultconfigs/messages.yaml",
33
+ MessagesConfig
34
+ )
31
35
 
36
+ self.cfg = loadConfig(
37
+ "config/watcher.yaml",
38
+ "/defaultconfigs/watcher.yaml",
39
+ WatcherConfig
40
+ )
41
+
42
+ # initialize panels and servers
32
43
  self.panel = Panel(
33
44
  name=self.global_cfg.panel_name,
34
45
  url=self.global_cfg.panel_url,
35
46
  api_key=self.global_cfg.panel_api_key,
36
47
  )
48
+
37
49
  self.origin = GenericServer(
38
50
  name="Origin",
39
51
  panel=self.panel,
40
52
  server_id=self.global_cfg.origin_server_id
41
53
  )
54
+
42
55
  self.server = MinecraftServer(
43
56
  name=self.global_cfg.server_name,
44
57
  panel=self.panel,
@@ -49,34 +62,36 @@ class ServerWatcher:
49
62
  rcon_password=self.global_cfg.rcon_password,
50
63
  tpsCommand=self.global_cfg.tps_command,
51
64
  )
65
+
52
66
  logger_name = self.cfg.logger_name_template.format(
53
67
  server_name=self.global_cfg.server_name
54
68
  )
69
+
55
70
  self.log = HungerLogger(
56
71
  name=logger_name,
57
72
  server=self.server,
58
73
  log_path=self.cfg.log_path,
59
74
  console_backspaces=self.cfg.console_backspaces,
60
75
  )
76
+
61
77
  self.tz = ZoneInfo(self.cfg.timezone)
62
78
 
63
- # format messages with prefix
79
+ # utility
64
80
  def fmt(self, template: str, **kwargs):
65
81
  return template.format(prefix=self.messages.prefix, **kwargs)
66
82
 
67
- # simple shutdown
68
83
  def shutdown(self):
69
- self.log.info(f"{self.messages.log_shutdown}")
84
+ self.log.info(self.messages.log_shutdown)
70
85
  raise SystemExit
71
86
 
72
87
  # restart logic
73
88
  def restart_and_wait(self):
74
89
  self.origin.disableSchedule(self.cfg.restart_soon_schedule_id)
75
90
  self.server.restart()
76
- self.log.info(f"{self.messages.restart_action_sent}")
91
+ self.log.info(self.messages.restart_action_sent)
77
92
  time.sleep(self.cfg.restart_wait_seconds)
78
93
 
79
- self.log.warn(f"{self.messages.log_status_check}")
94
+ self.log.warn(self.messages.log_status_check)
80
95
  alive = waitForOnline(
81
96
  self.server,
82
97
  timeout=self.cfg.restart_online_timeout,
@@ -84,13 +99,13 @@ class ServerWatcher:
84
99
  )
85
100
 
86
101
  if alive:
87
- self.log.info(f"{self.messages.server_back_online}")
88
- self.server.sendBroadcast(f"{self.messages.server_back_online_broadcast}")
102
+ self.log.info(self.messages.server_back_online)
103
+ self.server.sendBroadcast(self.messages.server_back_online_broadcast)
89
104
  self.origin.enableSchedule(self.cfg.origin_disable_schedule_id)
90
105
  else:
91
- self.log.error(f"{self.messages.server_failed_restart}")
106
+ self.log.error(self.messages.server_failed_restart)
92
107
 
93
- # schedule restart
108
+ # scheduled restart
94
109
  def schedule_restart(self, minutes):
95
110
  info = snapSchedule(minimumMinutes=minutes)
96
111
  scheduled = info["scheduled"]
@@ -98,50 +113,42 @@ class ServerWatcher:
98
113
  local_time = scheduled.astimezone(self.tz)
99
114
  time_str = local_time.strftime("%I:%M %p")
100
115
 
101
- # Broadcast the scheduled restart time
102
- self.server.sendBroadcast(self.fmt(self.messages.broadcast_restart_at, time=time_str))
103
-
104
- # Collect all minute_* keys
105
- minute_keys = [
106
- k for k in vars(self.messages)
107
- if k.startswith("minute_")
108
- ]
116
+ self.server.sendBroadcast(
117
+ self.fmt(self.messages.broadcast_restart_at, time=time_str)
118
+ )
109
119
 
120
+ # minute_* callbacks
110
121
  minute_callbacks = {
111
122
  int(k.split("_")[1]): (
112
123
  lambda msg=self.fmt(getattr(self.messages, k)):
113
124
  self.server.sendBroadcast(msg)
114
125
  )
115
- for k in minute_keys
126
+ for k in vars(self.messages)
127
+ if k.startswith("minute_")
116
128
  }
117
129
 
118
- # Collect all second_* keys
119
- second_keys = [
120
- k for k in vars(self.messages)
121
- if k.startswith("second_")
122
- ]
123
-
130
+ # second_* callbacks
124
131
  second_callbacks = {
125
132
  int(k.split("_")[1]): (
126
133
  lambda msg=self.fmt(getattr(self.messages, k)):
127
134
  self.server.sendBroadcast(msg)
128
135
  )
129
- for k in second_keys
136
+ for k in vars(self.messages)
137
+ if k.startswith("second_")
130
138
  }
131
139
 
132
-
133
140
  runCountdownEvents(
134
141
  target_time=scheduled,
135
142
  minute_callbacks=minute_callbacks,
136
143
  second_callbacks=second_callbacks,
137
144
  )
138
145
 
139
- # main evaluation logic
146
+ # evaluation logic
140
147
  def evaluate(self):
141
- self.log.info(f"{self.messages.log_start}")
148
+ self.log.info(self.messages.log_start)
142
149
 
143
150
  if not validateAll(self.panel, self.server):
144
- self.log.error(f"{self.messages.log_validation_fail}")
151
+ self.log.error(self.messages.log_validation_fail)
145
152
  self.shutdown()
146
153
 
147
154
  self.server.refresh()
@@ -208,8 +215,9 @@ class ServerWatcher:
208
215
 
209
216
  gap = abs(pro - anti)
210
217
 
218
+ # decision
211
219
  if pro == 0:
212
- self.log.info(f"{self.messages.log_no_restart}")
220
+ self.log.info(self.messages.log_no_restart)
213
221
  return
214
222
 
215
223
  if pro > anti and snap.players == 0:
@@ -228,9 +236,7 @@ class ServerWatcher:
228
236
 
229
237
  self.restart_and_wait()
230
238
 
231
- # -----------------------------------------------------
232
- # Main loop
233
- # -----------------------------------------------------
239
+ # main loop
234
240
  def run(self):
235
241
  if self.cfg.clear_terminal:
236
242
  clearTerminal()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 3.9.1
3
+ Version: 4.0
4
4
  Summary: A HungerLib-powered Minecraft server automation engine.
5
5
  Author: iFamished
6
6
  License: GPL-3.0
@@ -0,0 +1,17 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ src/serverwatcher/__init__.py
5
+ src/serverwatcher/watcher.py
6
+ src/serverwatcher.egg-info/PKG-INFO
7
+ src/serverwatcher.egg-info/SOURCES.txt
8
+ src/serverwatcher.egg-info/dependency_links.txt
9
+ src/serverwatcher.egg-info/requires.txt
10
+ src/serverwatcher.egg-info/top_level.txt
11
+ src/serverwatcher/configclasses/__init__.py
12
+ src/serverwatcher/configclasses/global_config.py
13
+ src/serverwatcher/configclasses/messages.py
14
+ src/serverwatcher/configclasses/watcher.py
15
+ src/serverwatcher/defaultconfigs/global.yaml
16
+ src/serverwatcher/defaultconfigs/messages.yaml
17
+ src/serverwatcher/defaultconfigs/watcher.yaml
@@ -1,14 +0,0 @@
1
- LICENSE
2
- README.md
3
- pyproject.toml
4
- src/serverwatcher/__init__.py
5
- src/serverwatcher/watcher.py
6
- src/serverwatcher.egg-info/PKG-INFO
7
- src/serverwatcher.egg-info/SOURCES.txt
8
- src/serverwatcher.egg-info/dependency_links.txt
9
- src/serverwatcher.egg-info/requires.txt
10
- src/serverwatcher.egg-info/top_level.txt
11
- src/serverwatcher/configmap/configclasses/__init__.py
12
- src/serverwatcher/configmap/configclasses/global_config.py
13
- src/serverwatcher/configmap/configclasses/messages.py
14
- src/serverwatcher/configmap/configclasses/watcher.py
File without changes
File without changes
File without changes