serverwatcher 3.9__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/src/serverwatcher.egg-info → serverwatcher-4.0}/PKG-INFO +1 -1
  2. {serverwatcher-3.9 → serverwatcher-4.0}/pyproject.toml +1 -1
  3. {serverwatcher-3.9 → 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 → serverwatcher-4.0}/src/serverwatcher/watcher.py +49 -44
  8. {serverwatcher-3.9 → 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/src/serverwatcher.egg-info/SOURCES.txt +0 -14
  11. {serverwatcher-3.9 → serverwatcher-4.0}/LICENSE +0 -0
  12. {serverwatcher-3.9 → serverwatcher-4.0}/README.md +0 -0
  13. {serverwatcher-3.9 → serverwatcher-4.0}/setup.cfg +0 -0
  14. {serverwatcher-3.9/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/__init__.py +0 -0
  15. {serverwatcher-3.9/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/global_config.py +0 -0
  16. {serverwatcher-3.9/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/messages.py +0 -0
  17. {serverwatcher-3.9/src/serverwatcher/configmap → serverwatcher-4.0/src/serverwatcher}/configclasses/watcher.py +0 -0
  18. {serverwatcher-3.9 → serverwatcher-4.0}/src/serverwatcher.egg-info/dependency_links.txt +0 -0
  19. {serverwatcher-3.9 → serverwatcher-4.0}/src/serverwatcher.egg-info/requires.txt +0 -0
  20. {serverwatcher-3.9 → 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
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"
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,35 +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
- from serverwatcher.config import GlobalConfig, MessagesConfig, WatcherConfig
18
-
19
- # Set directory
20
- BASE_DIR = os.getcwd()
21
- PACKAGE_DIR = os.path.dirname(__file__)
17
+ from serverwatcher import GlobalConfig, MessagesConfig, WatcherConfig
22
18
 
23
19
 
24
20
  class ServerWatcher:
25
21
  def __init__(self):
26
- # Load all configs in /config using configmap
27
- cfgmap = load_or_default("config", skip_files=[])
28
22
 
29
- self.global_cfg: GlobalConfig = cfgmap["global.yaml"]
30
- self.messages: MessagesConfig = cfgmap["messages.yaml"]
31
- self.cfg: WatcherConfig = cfgmap["watcher.yaml"]
23
+ # load configs
24
+ self.global_cfg = loadConfig(
25
+ "config/global.yaml",
26
+ "/defaultconfigs/global.yaml",
27
+ GlobalConfig
28
+ )
29
+
30
+ self.messages = loadConfig(
31
+ "config/messages.yaml",
32
+ "/defaultconfigs/messages.yaml",
33
+ MessagesConfig
34
+ )
35
+
36
+ self.cfg = loadConfig(
37
+ "config/watcher.yaml",
38
+ "/defaultconfigs/watcher.yaml",
39
+ WatcherConfig
40
+ )
32
41
 
42
+ # initialize panels and servers
33
43
  self.panel = Panel(
34
44
  name=self.global_cfg.panel_name,
35
45
  url=self.global_cfg.panel_url,
36
46
  api_key=self.global_cfg.panel_api_key,
37
47
  )
48
+
38
49
  self.origin = GenericServer(
39
50
  name="Origin",
40
51
  panel=self.panel,
41
52
  server_id=self.global_cfg.origin_server_id
42
53
  )
54
+
43
55
  self.server = MinecraftServer(
44
56
  name=self.global_cfg.server_name,
45
57
  panel=self.panel,
@@ -50,34 +62,36 @@ class ServerWatcher:
50
62
  rcon_password=self.global_cfg.rcon_password,
51
63
  tpsCommand=self.global_cfg.tps_command,
52
64
  )
65
+
53
66
  logger_name = self.cfg.logger_name_template.format(
54
67
  server_name=self.global_cfg.server_name
55
68
  )
69
+
56
70
  self.log = HungerLogger(
57
71
  name=logger_name,
58
72
  server=self.server,
59
73
  log_path=self.cfg.log_path,
60
74
  console_backspaces=self.cfg.console_backspaces,
61
75
  )
76
+
62
77
  self.tz = ZoneInfo(self.cfg.timezone)
63
78
 
64
- # format messages with prefix
79
+ # utility
65
80
  def fmt(self, template: str, **kwargs):
66
81
  return template.format(prefix=self.messages.prefix, **kwargs)
67
82
 
68
- # simple shutdown
69
83
  def shutdown(self):
70
- self.log.info(f"{self.messages.log_shutdown}")
84
+ self.log.info(self.messages.log_shutdown)
71
85
  raise SystemExit
72
86
 
73
87
  # restart logic
74
88
  def restart_and_wait(self):
75
89
  self.origin.disableSchedule(self.cfg.restart_soon_schedule_id)
76
90
  self.server.restart()
77
- self.log.info(f"{self.messages.restart_action_sent}")
91
+ self.log.info(self.messages.restart_action_sent)
78
92
  time.sleep(self.cfg.restart_wait_seconds)
79
93
 
80
- self.log.warn(f"{self.messages.log_status_check}")
94
+ self.log.warn(self.messages.log_status_check)
81
95
  alive = waitForOnline(
82
96
  self.server,
83
97
  timeout=self.cfg.restart_online_timeout,
@@ -85,13 +99,13 @@ class ServerWatcher:
85
99
  )
86
100
 
87
101
  if alive:
88
- self.log.info(f"{self.messages.server_back_online}")
89
- 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)
90
104
  self.origin.enableSchedule(self.cfg.origin_disable_schedule_id)
91
105
  else:
92
- self.log.error(f"{self.messages.server_failed_restart}")
106
+ self.log.error(self.messages.server_failed_restart)
93
107
 
94
- # schedule restart
108
+ # scheduled restart
95
109
  def schedule_restart(self, minutes):
96
110
  info = snapSchedule(minimumMinutes=minutes)
97
111
  scheduled = info["scheduled"]
@@ -99,50 +113,42 @@ class ServerWatcher:
99
113
  local_time = scheduled.astimezone(self.tz)
100
114
  time_str = local_time.strftime("%I:%M %p")
101
115
 
102
- # Broadcast the scheduled restart time
103
- self.server.sendBroadcast(self.fmt(self.messages.broadcast_restart_at, time=time_str))
104
-
105
- # Collect all minute_* keys
106
- minute_keys = [
107
- k for k in vars(self.messages)
108
- if k.startswith("minute_")
109
- ]
116
+ self.server.sendBroadcast(
117
+ self.fmt(self.messages.broadcast_restart_at, time=time_str)
118
+ )
110
119
 
120
+ # minute_* callbacks
111
121
  minute_callbacks = {
112
122
  int(k.split("_")[1]): (
113
123
  lambda msg=self.fmt(getattr(self.messages, k)):
114
124
  self.server.sendBroadcast(msg)
115
125
  )
116
- for k in minute_keys
126
+ for k in vars(self.messages)
127
+ if k.startswith("minute_")
117
128
  }
118
129
 
119
- # Collect all second_* keys
120
- second_keys = [
121
- k for k in vars(self.messages)
122
- if k.startswith("second_")
123
- ]
124
-
130
+ # second_* callbacks
125
131
  second_callbacks = {
126
132
  int(k.split("_")[1]): (
127
133
  lambda msg=self.fmt(getattr(self.messages, k)):
128
134
  self.server.sendBroadcast(msg)
129
135
  )
130
- for k in second_keys
136
+ for k in vars(self.messages)
137
+ if k.startswith("second_")
131
138
  }
132
139
 
133
-
134
140
  runCountdownEvents(
135
141
  target_time=scheduled,
136
142
  minute_callbacks=minute_callbacks,
137
143
  second_callbacks=second_callbacks,
138
144
  )
139
145
 
140
- # main evaluation logic
146
+ # evaluation logic
141
147
  def evaluate(self):
142
- self.log.info(f"{self.messages.log_start}")
148
+ self.log.info(self.messages.log_start)
143
149
 
144
150
  if not validateAll(self.panel, self.server):
145
- self.log.error(f"{self.messages.log_validation_fail}")
151
+ self.log.error(self.messages.log_validation_fail)
146
152
  self.shutdown()
147
153
 
148
154
  self.server.refresh()
@@ -209,8 +215,9 @@ class ServerWatcher:
209
215
 
210
216
  gap = abs(pro - anti)
211
217
 
218
+ # decision
212
219
  if pro == 0:
213
- self.log.info(f"{self.messages.log_no_restart}")
220
+ self.log.info(self.messages.log_no_restart)
214
221
  return
215
222
 
216
223
  if pro > anti and snap.players == 0:
@@ -229,9 +236,7 @@ class ServerWatcher:
229
236
 
230
237
  self.restart_and_wait()
231
238
 
232
- # -----------------------------------------------------
233
- # Main loop
234
- # -----------------------------------------------------
239
+ # main loop
235
240
  def run(self):
236
241
  if self.cfg.clear_terminal:
237
242
  clearTerminal()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: serverwatcher
3
- Version: 3.9
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