188 lines
8.3 KiB
Python
Executable File
188 lines
8.3 KiB
Python
Executable File
#!/usr/bin/python3
|
|
|
|
import os
|
|
import sys
|
|
import time
|
|
import json
|
|
import psutil
|
|
import signal
|
|
import logging
|
|
import requests
|
|
import argparse
|
|
import configparser
|
|
|
|
from subprocess import Popen, PIPE
|
|
from multiprocessing.pool import ThreadPool
|
|
|
|
### функция для преобразования элемента в список
|
|
def ini_item(value: str=""):
|
|
tmp=value.split(',')
|
|
if len(tmp) > 1:
|
|
return tmp
|
|
return value
|
|
|
|
### функция запуска сервера
|
|
def server_start(param):
|
|
return Popen(["/usr/bin/python3", param[0], f"{param[1]} {str(param[2])} {param[3]} {str(param[4])} >/dev/null 2>&1"], stdout=PIPE, stderr=PIPE, shell=False).pid
|
|
|
|
### функция проверки версии игры
|
|
def server_version(ver):
|
|
try:
|
|
if 'steamcmd_update_check' in cfg_settings and cfg_settings['steamcmd_update_check'] != "":
|
|
# делаем запрос к api steam
|
|
result = requests.get(cfg_settings['steamcmd_update_check'] + str(ver))
|
|
if result.status_code == 200:
|
|
result=result.json()
|
|
print(result)
|
|
# если версия устарела, возвращаем текущую
|
|
if not result['response']['up_to_date']:
|
|
return str(result['response']['required_version'])
|
|
elif 'steamcmd_news_update_check' in cfg_settings and cfg_settings['steamcmd_news_update_check'] != "":
|
|
# делаем запрос к api steam
|
|
result = requests.get(cfg_settings['steamcmd_news_update_check'])
|
|
if result.status_code == 200:
|
|
result=result.json()['appnews']['newsitems'][0]
|
|
# проверяем связана ли новость с обновлением
|
|
title=str(result['title']).lower()
|
|
contents=str(result['contents']).lower()
|
|
if title and contents and \
|
|
('fix' in title or 'fix' in contents or \
|
|
'version' in title or 'version' in contents or \
|
|
'changelog' in title or 'changelog' in contents or \
|
|
'update' in title or 'update' in contents):
|
|
# если дата новости не равна текущей
|
|
if str(ver) != str(result['date']):
|
|
return str(result['date'])
|
|
except:
|
|
None
|
|
# если версия актуальна, или код ответа с ошибкой
|
|
return True
|
|
|
|
### главная функция
|
|
if __name__ == "__main__":
|
|
sys.stderr = open('/dev/null')
|
|
# парсим аргументы
|
|
parser = argparse.ArgumentParser(add_help=False)
|
|
parser.add_argument("action", choices=["start", "stop", "restart", "status"])
|
|
parser.add_argument("config")
|
|
args = parser.parse_args()
|
|
|
|
# конфигурационный файл серверов
|
|
c_cfg = configparser.ConfigParser()
|
|
c_cfg.optionxform = str # для правельного учета регистра
|
|
c_cfg.read(args.config)
|
|
cfg_settings={}
|
|
|
|
# пробегаем основные параметры
|
|
for key, value in c_cfg.items("SETTINGS"):
|
|
cfg_settings[key]=ini_item(value)
|
|
|
|
# проверяем существование папки для логов
|
|
if not os.path.exists(log_folder_path:=os.path.dirname(cfg_settings['log'])):
|
|
try:
|
|
# создание папки
|
|
os.makedirs(log_folder_path)
|
|
except:
|
|
None
|
|
# создаем объект класса logging
|
|
logging.basicConfig(filename=cfg_settings['log'], encoding='utf-8', level=logging.INFO,format='%(asctime)s.%(msecs)03d %(levelname)s %(message)s', datefmt='%Y-%m-%d %H:%M:%S',)
|
|
|
|
# пытаемся прочитать текущую версию из файла
|
|
try:
|
|
with open(cfg_settings['steamcmd_game_version'], "r") as f:
|
|
c_version = f.read()
|
|
except FileNotFoundError:
|
|
c_version=""
|
|
|
|
## функция запуска сервиса
|
|
def s_start(c_version, cfg_settings, args_config):
|
|
print("Start ...")
|
|
count=0
|
|
c_pid=str(os.getppid())
|
|
pool = ThreadPool()
|
|
for game in cfg_settings['modes_game']:
|
|
for dif in cfg_settings['difficulty_game']:
|
|
time.sleep(0.5)
|
|
c=pool.map(server_start, ([os.path.join(cfg_settings['dir_work'],"Daemon") + "/kf2-server.py", count, game, dif, args_config] ,))
|
|
c_pid+=f" {c[0]}"
|
|
count+=1
|
|
if game in ['KFGameContent.KFGameInfo_WeeklySurvival', 'KFGameContent.KFGameInfo_VersusSurvival']:
|
|
break
|
|
pool.close()
|
|
pool.join()
|
|
# пишем в файл pid процессов
|
|
with open(cfg_settings['pid_kf2'], "w") as f:
|
|
f.write(str(c_pid))
|
|
while True:
|
|
# проверяем наличие обновлений в цикле
|
|
version=server_version(c_version)
|
|
if version != True:
|
|
# если прилетели обновления, обновляем
|
|
command=f"echo {cfg_settings['sys_user']} | su --pty - {cfg_settings['sys_user']} -c \"steamcmd +force_install_dir {cfg_settings['dir_server_data']} {cfg_settings['steamcmd_update_key']}\""
|
|
with Popen(command, stdout=PIPE, stderr=PIPE, shell=True, user=cfg_settings['sys_user'], group=cfg_settings['sys_group'], ) as process: # запускаем процесс от пользователя steam
|
|
print("Update ...")
|
|
logging.info(f"Update: New version - {version}, old - {c_version}")
|
|
c_version=str(version)
|
|
process.communicate()
|
|
# после обновления пишим новую версию в файл
|
|
with open(cfg_settings['steamcmd_game_version'], "w") as f:
|
|
f.write(str(version))
|
|
# после обновления перезапускаемся
|
|
s_stop(1)
|
|
return s_start(c_version, cfg_settings, args_config)
|
|
time.sleep(3600) # проверяем обновление каждый час
|
|
|
|
## функция остановки сервиса
|
|
def s_stop(split: int=0):
|
|
global c_version,cfg_settings
|
|
print("Stop ...")
|
|
with open(cfg_settings['pid_kf2'], "r") as f:
|
|
c_pid = f.read()
|
|
c_pid=c_pid.split()
|
|
for i in range(len(c_pid)-split):
|
|
try:
|
|
os.killpg(os.getpgid(int(c_pid[(i+split)])), signal.SIGINT)
|
|
time.sleep(0.5)
|
|
except:
|
|
None
|
|
|
|
# если старт
|
|
if args.action == "start":
|
|
try:
|
|
# проверка на запущенность сервиса, проверяем первый pid
|
|
with open(cfg_settings['pid_kf2'], "r") as f:
|
|
c_pid = f.read()
|
|
c_pid=c_pid.split()
|
|
if str(os.getppid()) != c_pid[0]:
|
|
try:
|
|
# если запущен, выходим
|
|
os.getpgid(int(c_pid[0]))
|
|
raise KeyboardInterrupt()
|
|
except OSError:
|
|
# если не запущен, запускаем
|
|
s_start(c_version, cfg_settings, args.config)
|
|
# если запускаем из терминала
|
|
s_start(c_version, cfg_settings, args.config)
|
|
except Exception:
|
|
# если файл pid не существует, запускаем
|
|
s_start(c_version, cfg_settings, args.config)
|
|
# если стоп
|
|
elif args.action == "stop":
|
|
s_stop()
|
|
# если перезапуск
|
|
elif args.action == "restart":
|
|
s_stop()
|
|
time.sleep(1)
|
|
s_start()
|
|
# если информация о работе
|
|
elif args.action == "status":
|
|
bin_name=os.path.basename(cfg_settings['bin_server'])
|
|
# проверяем все системные процессы и показываем наши сервера
|
|
for pid in psutil.pids():
|
|
p = psutil.Process(pid)
|
|
if p.name() == bin_name:
|
|
print(f"[{pid}] {' '.join(p.cmdline())}")
|
|
# значение по умолчанию
|
|
else:
|
|
parser.print_help()
|