@@ -24,17 +24,14 @@ def __init__(self):
24
24
self .daemon_time = self .conf ['daemon_time' ]
25
25
self .arguments = self .conf .get ('arguments' , '' ).split ()
26
26
self .is_first_run = True
27
+ self .is_restarting = False
27
28
28
29
# 修改rcon源代码,忽略SessionTimeout异常
29
30
def patched_run (self , command : str , * args : str , encoding : str = "utf-8" ) -> str :
30
31
"""Patched run method that ignores SessionTimeout exceptions."""
31
32
request = Packet .make_command (command , * args , encoding = encoding )
32
33
response = self .communicate (request )
33
34
34
- # Ignore SessionTimeout exceptions
35
- # if response.id != request.id:
36
- # raise SessionTimeout()
37
-
38
35
return response .payload .decode (encoding )
39
36
40
37
# Apply the monkey patch
@@ -56,7 +53,10 @@ def check_rcon(self):
56
53
except TimeoutError :
57
54
INFO .logger .error ("[ RCON ] 正在检测RCON连接,请不要关闭......" )
58
55
print ("[ RCON ] 正在检测RCON连接,请不要关闭......" )
59
- return False
56
+ if self .is_first_run :
57
+ time .sleep (1 )
58
+ else :
59
+ return False
60
60
except rcon .exceptions .WrongPassword :
61
61
INFO .logger .error ("[ RCON ] RCON密码错误,请检查相关设置" )
62
62
print ("[ RCON ] RCON密码错误,请检查相关设置" )
@@ -93,7 +93,7 @@ def start_program(self):
93
93
while time .time () - start_time < 60 :
94
94
if self .check_rcon ():
95
95
break
96
- time .sleep (1 ) # 每次尝试后,暂停1秒
96
+ time .sleep (1 )
97
97
98
98
else :
99
99
INFO .logger .error ("[ RCON ] 无法在60秒内建立RCON连接" )
@@ -126,59 +126,54 @@ def polling_task(self):
126
126
INFO .logger .info (f'[ 轮询任务 ] 服务器将进入重启倒计时,设置时长为 { self .conf ["restart_interval" ]} 秒......' )
127
127
print (f'\r [ 轮询任务 ] 服务器将进入重启倒计时,设置时长为 { self .conf ["restart_interval" ]} 秒......' )
128
128
129
- # 如果设置了检查内存使用情况memory_monitor_enabled
130
- if self .conf ['memory_monitor_enabled' ]:
131
- time .sleep (1 )
132
- INFO .logger .info (f"[ 内存监控 ] 已开启内存监控,每{ self .conf ['polling_interval_seconds' ]} 秒检查一次,将在内存使用超过{ self .conf ['memory_usage_threshold' ]} %时重启程序" )
133
- print (f"\r [ 内存监控 ] 已开启内存监控,每{ self .conf ['polling_interval_seconds' ]} 秒检查一次,将在内存使用超过{ self .conf ['memory_usage_threshold' ]} %时重启程序" )
134
-
135
129
# 服务器持续运行时间(重启间隔)
136
130
for i in range (int (self .conf ['restart_interval' ]), 0 , - 1 ):
131
+ print ("\r \033 [K" , end = '' ) # 清除当前行
132
+ print (f'\r [ 轮询任务 ] 服务器将在 { i } 秒后重启......' , end = '' )
133
+ time .sleep (1 )
134
+ # 检查内存使用情况
137
135
if self .conf ['memory_monitor_enabled' ]:
138
136
if self .conf ['polling_interval_seconds' ] > 5 :
139
- # 检查内存使用情况
140
137
mem_info = psutil .virtual_memory ()
141
138
mem_usage = mem_info .percent # 获取内存使用百分比
142
- # 如果内存使用超过阈值,则跳出倒计时,进行重启操作
139
+
140
+ # 内存超限关服消息提醒
143
141
if mem_usage > self .conf ['memory_usage_threshold' ]:
142
+ self .is_restarting = True # 开始重启
143
+ max_notice_time = max (map (int , self .conf ['shutdown_notices' ].keys ())) # 获取最大关服通知时间
144
144
INFO .logger .error (f"[ 内存监控 ] 内存使用超过{ self .conf ['memory_usage_threshold' ]} %,正在重启程序......" )
145
- print (f"[ 内存监控 ] 内存使用超过{ self .conf ['memory_usage_threshold' ]} %,正在重启程序......" )
146
- break
145
+ print (f"\r [ 内存监控 ] 内存使用超过{ self .conf ['memory_usage_threshold' ]} %,正在重启程序......" )
146
+ time .sleep (1 )
147
+ # 倒计时关闭服务端
148
+ for j in range (max_notice_time , 0 , - 1 ):
149
+ time .sleep (1 )
150
+ self .send_shutdown_notice (j )
151
+ subprocess .run (['taskkill' , '/f' , '/im' , self .appName ], stderr = subprocess .DEVNULL )
152
+ self .is_first_run = True
153
+ time .sleep (5 )
154
+ self .start_program ()
155
+ self .is_restarting = False # 重启完成
156
+
147
157
else :
148
158
INFO .logger .error ("[ 内存监控 ] 轮询间隔 polling_interval_seconds 必须大于等于5秒,请重新设置!" )
149
159
print ("[ 内存监控 ] 轮询间隔 polling_interval_seconds 必须大于5秒,请重新设置!" )
150
160
time .sleep (2 )
151
161
exit (0 )
152
162
153
- # 还剩30秒的时候发送rcon关服消息提醒
163
+ # 还剩 x 秒的时候发送rcon关服消息提醒
154
164
if str (i ) in self .conf ['shutdown_notices' ] and self .conf ['rcon_enabled' ]: # 检查是否有对应的通知
155
165
if self .conf ['rcon_command' ]:
156
- INFO .logger .info ("RCON指令 {0},正在发送通知......" .format (self .conf ['rcon_command' ]))
157
- print ("\r \033 [K" , end = '' )
158
- print ("RCON指令 {0},正在发送通知......" .format (self .conf ['rcon_command' ]))
159
- try :
160
- with Client (
161
- host = self .conf ['rcon_host' ],
162
- port = self .conf ['rcon_port' ],
163
- passwd = self .conf ['rcon_password' ],
164
- timeout = 1 ) as client :
165
- message = self .conf ['shutdown_notices' ][str (i )]
166
- response = client .run (f"{ self .conf ['rcon_command' ]} { message } " , 'utf-8' )
167
- INFO .logger .info ('[指令发送] {0}' .format (response ))
168
- print ('[指令发送] ' , response )
169
- except TimeoutError :
170
- INFO .logger .error ("RCON连接超时,请检查IP和端口是否填写正确" )
171
- print ("\r \033 [K" , end = '' )
172
- print ("RCON连接超时,请检查IP和端口是否填写正确" )
173
- except rcon .exceptions .WrongPassword :
174
- INFO .logger .error ("RCON密码错误,请检查相关设置" )
175
- print ("\r \033 [K" , end = '' )
176
- print ("RCON密码错误,请检查相关设置" )
177
-
178
- print (f'\r [ 轮询任务 ] 服务器将在 { i } 秒后重启......' , end = '' )
179
- time .sleep (1 )
180
-
181
- # 关闭服务端 放在循环的结尾,可以让用户不用关闭服务器的情况下启动本脚本
166
+ with Client (
167
+ host = self .conf ['rcon_host' ],
168
+ port = self .conf ['rcon_port' ],
169
+ passwd = self .conf ['rcon_password' ],
170
+ timeout = 1 ) as client :
171
+ message = self .conf ['shutdown_notices' ][str (i )]
172
+ response = client .run (f"{ self .conf ['rcon_command' ]} { message } " , 'utf-8' )
173
+ INFO .logger .info ('[指令发送] {0}' .format (response ))
174
+ print ('\r [指令发送]' , response )
175
+
176
+ # 关闭服务端
182
177
INFO .logger .info ("[ 轮询任务 ] 正在关闭任何在运行的 PalServer 服务......" )
183
178
print ("\r \033 [K" , end = '' )
184
179
print ("[ 轮询任务 ] 正在关闭任何在运行的 PalServer 服务......" )
@@ -193,7 +188,7 @@ def start_daemon(self):
193
188
try :
194
189
result = subprocess .run (['tasklist' , '/FI' , 'IMAGENAME eq PalServer.exe' ], capture_output = True ,
195
190
text = True )
196
- if 'PalServer.exe' not in result .stdout :
191
+ if 'PalServer.exe' not in result .stdout and ( not self . is_restarting ) :
197
192
print ("\r \033 [K" , end = '' )
198
193
print ('[ 守护进程 ] 监控到 PalServer 已停止,正在重新启动......' )
199
194
@@ -211,6 +206,21 @@ def start_daemon(self):
211
206
print (f"[ 守护进程 ] 程序异常终止,错误信息:{ e } \n 正在尝试重启程序......" )
212
207
continue
213
208
209
+ def send_shutdown_notice (self , countdown ):
210
+ """Send a shutdown notice through RCON."""
211
+ if self .conf ['rcon_enabled' ]: # 检查是否开启通知
212
+ if str (countdown ) in self .conf ['shutdown_notices' ]:
213
+ if self .conf ['rcon_command' ]:
214
+ with Client (
215
+ host = self .conf ['rcon_host' ],
216
+ port = self .conf ['rcon_port' ],
217
+ passwd = self .conf ['rcon_password' ],
218
+ timeout = 1 ) as client :
219
+ message = self .conf ['shutdown_notices' ][str (countdown )]
220
+ response = client .run (f"{ self .conf ['rcon_command' ]} { message } " , 'utf-8' )
221
+ INFO .logger .info ('[指令发送] {0}' .format (response ))
222
+ print ('\r [指令发送]' , response )
223
+
214
224
215
225
def main ():
216
226
Task = TaskScheduler ()
@@ -220,15 +230,24 @@ def main():
220
230
print ("[ 轮询任务 ] 已启动,每隔{0}秒重启 PalServer 进程......" .format (Task .conf ['restart_interval' ]))
221
231
polling_thread .start ()
222
232
time .sleep (1 )
233
+
223
234
# [ 轮询任务 ] 必须在最初启动 防止[ 轮询任务 ] kill掉[ 守护进程 ] 刚启动的服务端
224
235
if Task .conf ['daemon_enabled' ]:
225
236
print ("\r \033 [K" , end = '' )
226
- INFO .logger .info ("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......" .format (Task .conf ['daemon_time' ]))
227
- print ("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......" .format (Task .conf ['daemon_time' ]))
237
+ INFO .logger .info ("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......" .format (
238
+ Task .conf ['daemon_time' ]))
239
+ print ("[ 守护进程 ] 守护进程已开启,延迟5秒启动避免双端开启,每隔{0}秒检查一次......" .format (
240
+ Task .conf ['daemon_time' ]))
228
241
time .sleep (5 ) # 再延迟5秒 避免脚本启动时双开服务端。尽量避免10结尾以免和[ 轮询任务 ] 倒计时同时结束
229
242
daemon_thread = threading .Thread (target = Task .start_daemon )
230
243
daemon_thread .start ()
231
244
245
+ if Task .conf ['memory_monitor_enabled' ]:
246
+ INFO .logger .info ("[ 内存监控 ] 已开启内存监控,每{0}秒检查一次,将在内存使用超过{1}%时重启程序" .format (
247
+ Task .conf ['polling_interval_seconds' ], Task .conf ['memory_usage_threshold' ]))
248
+ print ("[ 内存监控 ] 已开启内存监控,每{0}秒检查一次,将在内存使用超过{1}%时重启程序" .format (
249
+ Task .conf ['polling_interval_seconds' ], Task .conf ['memory_usage_threshold' ]))
250
+
232
251
polling_thread .join ()
233
252
if Task .conf ['daemon_enabled' ]:
234
253
daemon_thread .join ()
0 commit comments