# -*- coding:utf-8 -*- import ast import configparser import pathlib import re import subprocess import psutil import time from subprocess import Popen import sys import pymysql from PyQt5.QtCore import pyqtSignal, QThread from PyQt5.QtGui import QTextCursor from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox from configparser import ExtendedInterpolation # 界面文件为 mainui.py from mainui import * import requests import os configFile = 'config.ini' # 创建配置文件对象 config = configparser.ConfigParser(interpolation=ExtendedInterpolation(), inline_comment_prefixes=['#', ';'], allow_no_value=True) # 读取配置文件 config.read(configFile, encoding='utf-8') class MainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setupUi(self) self.apktool_path = config['TOOL_PATH']['apktool_path'] self.android_name = config['ANDROID']['android_name'] self.android_name_file = config['ANDROID']['android_name_file'] self.tmp_android_name = config['ANDROID']['tmp_android_name'] self.new_android_name = config['ANDROID']['new_android_name'] # 初始赋值 self.nowIpLabel.setText(config['GAME']['now_ip']) self.newIpInput.setText(config['GAME']['new_ip']) self.nowGameLabel.setText(config['GAME']['game_name']) self.newGameInput.setText(config['GAME']['game_name']) # 设置按钮状态 if isinstance(checkprocess("nginx.exe"), int): self.nginxButton.setText("关闭Nginx") else: self.nginxButton.setText("启动Nginx") if isinstance(checkprocess("mysqld.exe"), int): self.mysqlButton.setText("关闭MySql") else: self.mysqlButton.setText("启动MySql") def saveSet(self, event): print('保存设置,按钮被单击') # print(config['GAME_FILE_PATH']['game']) # tinydict = ast.literal_eval(config['GAME_PATH']['game']) # print("字典值 : %s" %tinydict.items()) # # 遍历字典列表 # for key, values in tinydict.items(): # print(key, values) # print(config.items("GAME_FILE_PATH")) # return message = QMessageBox.information(self, "提示信息", "确定要保存设置吗?", QMessageBox.Ok | QMessageBox.No, QMessageBox.No) if message == QMessageBox.No: return # 取值 now_ip = config['GAME']['now_ip'] new_ip = self.newIpInput.text() now_game = config['GAME']['game_name'] new_game = self.newGameInput.text() compile_ip = re.compile('^(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|[1-9])\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)\.(1\d{2}|2[0-4]\d|25[0-5]|[1-9]\d|\d)$') # 验证IP地址格式 if (new_ip == "") or new_game == "" or not (compile_ip.match(new_ip)): QMessageBox.information(self, "提示信息", "IP地址、游戏名称为空或有误,请正确填写IPv4地址或游戏名称!") return # 处理SQL语句 sql_game_ip = config['GAME_DATA_SQL']['game_ip'].replace(now_ip, new_ip) sql_game_name = config['GAME_DATA_SQL']['game_name'].replace(now_game + '_new', new_game) sqls = [sql_game_ip, sql_game_name] # 判断MYSQL是否启动 if isinstance(checkprocess("mysqld.exe"), int): mysql_run(sqls) else: message = QMessageBox.information(self, "提示信息", "MYSQL尚未启动,数据库相关脚本无法执行,是否现在启动MYSQL?", QMessageBox.Ok | QMessageBox.No, QMessageBox.Ok) if message == QMessageBox.Ok: self.mysql(self.mysqlButton) # 触发MYSQL启动按钮 sum = 0 # 以0.5秒的频次检测MYSQL是否启动,超过20次则超时 while not isinstance(checkprocess("mysqld.exe"), int): if sum > 20: QMessageBox.information(self, "提示信息", "MYSQL启动失败,请重新尝试!") return time.sleep(0.5) sum = sum + 1 mysql_run(sqls) else: return # 配置文件处理 sum = 0 for key, value in config.items('GAME_FILE_PATH'): print(key, value) # 处理文件编码 if len(value.split(",")) < 2: code = config['GAME']['file_encoding'] else: code = value.split(",")[1] filename = value.split(",")[0] # 执行文件内容替换 try: with open(filename, 'rt+', encoding=code) as f: t = f.read() t = t.replace(now_ip, new_ip) t = t.replace(now_game, new_game) # 读写偏移位置移到最开始处 f.seek(0, 0) f.write(t) # 设置文件结尾 EOF f.truncate() sum = sum + 1 except: QMessageBox.information(self, "提示信息", "替换“" + filename + "”出错,可能文件不存在或编码不对,请检查需要替换的文件编码与配置文件编码是否相符!") return # 写入配置文件 config.set('GAME', 'game_name', new_game) config.set('GAME', 'now_ip', new_ip) config.set('GAME', 'new_ip', new_ip) saveconfig = open(configFile, 'wt', encoding=config['GAME']['file_encoding']) config.write(saveconfig) # 把要修改的节点的内容写到文件中 saveconfig.close() # 设置按钮文字变化 self.nowGameLabel.setText(new_game) self.nowIpLabel.setText(new_ip) # 成功提示 QMessageBox.information(self, "提示信息", "配置保存成功!重启游戏后生效!
游戏名称:" + new_game + "----游戏IP:" + new_ip + "
共配置了" + str(sum) + "个文件") print('修改完成:' + new_game + ':' + new_ip) def nginx(self, event): if self.nginxButton.text() == '启动Nginx': Popen('start .\\nginx.exe', shell=True, cwd=config['NGINX']['nginx_path'], # encoding='utf-8' ) Popen( config['PHP']['php_spawner_path'] + 'php-cgi-spawner.exe "' + config['PHP']['php_path'] + 'php-cgi.exe -c ' + config['PHP']['php_path'] + 'php.ini" ' + config['PHP']['php_cgi_port'] + ' 1+16', shell=True, # cwd=config['GAME']['dir'] + 'phpstudy_pro', # encoding='utf-8' ) self.nginxButton.setText("关闭Nginx") else: nginx_process = Popen('.\\nginx.exe -s stop', shell=True, cwd=config['NGINX']['nginx_path'], # encoding='utf-8' ) spawner_process = Popen('taskkill /f /t /im php-cgi-spawner.exe', shell=True, # encoding='utf-8' ) PHP_process = Popen('taskkill /f /t /im php-cgi.exe', shell=True, # encoding='utf-8' ) self.nginxButton.setText("启动Nginx") # print(process) # os.chdir("D:\\LYserver\\phpstudy_pro\\Extensions\\Nginx1.15.11") # nginxtype = os.system('start .\\nginx.exe') # 不弹出界面 # if nginxtype # os.system('start .\\nginx.exe') #弹出界面 print('启动Nginx,按钮被单击') def mysql(self, event): if self.mysqlButton.text() == '启动MySql': Popen('.\\mysqld.exe', shell=True, cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) self.mysqlButton.setText("关闭MySql") else: Popen('taskkill /f /t /im mysqld.exe', shell=True, # encoding='utf-8' ) self.mysqlButton.setText("启动MySql") print('启动MySql,按钮被单击') def game(self, event): if self.gameButton.text() == '启动游戏': # 读取游戏启动路径 for key, value in config.items('GAME_PATH'): print(key, value) # 处理启动时间 if len(value.split(",")) < 2: sleeptime = 0 else: sleeptime = float(value.split(",")[1]) game_file = value.split(",")[0] try: Popen('start ' + game_file, shell=True, # cwd=values, # encoding='utf-8' ) time.sleep(float(sleeptime)) # 延迟启动时间 except: QMessageBox.information(self, "提示信息", "启动“" + game_file + "”出错,可能文件不存在或配置不对!") return self.gameButton.setText("关闭游戏") else: # 读取游戏启动路径 for key, value in config.items('GAME_PATH'): print(key, value) # 获取进程名称并结束进程 game_file = value.split(",")[0].split("\\") game_file = game_file[len(game_file) - 1] try: Popen( 'taskkill /f /t /im ' + game_file, shell=True, # encoding='utf-8' ) except: QMessageBox.information(self, "提示信息", "关闭游戏进程:“" + game_file + "”出错!") return # Popen( # 'taskkill /f /t /im LocalLogServer64_R.exe & taskkill /f /t /im LoggerServer64_R.exe & taskkill /f /t /im SessionServer64_R.exe & taskkill /f /t /im NameServer64_R.exe & taskkill /f /t /im LogicServerCQ64_R.exe & taskkill /f /t /im GateServer64_R.exe & taskkill /f /t /im DBCenterServer64_R.exe & taskkill /f /t /im DBServer64_R.exe & taskkill /f /t /im BackStageServer64_R.exe & taskkill /f /t /im AMServer64_R.exe', # shell=True, # # encoding='utf-8' # ) self.gameButton.setText("启动游戏") print('启动游戏,按钮被单击') def fanbianyi(self, event): obj = self.fanbianyiButton # obj.setText('运行中') title = obj.text() cmd = 'apktool d ' + self.android_name + ' -f -o ' + self.android_name_file cwd = self.apktool_path code = "gbk" path = self.android_name_file self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('反编译APK,按钮被单击') def shengcheng(self, event): obj = self.shengchengButton # obj.setText('运行中') title = obj.text() cmd = 'apktool b ' + self.android_name_file + ' -o ' + self.tmp_android_name cwd = self.apktool_path code = "gbk" path = self.tmp_android_name self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('生成APK,按钮被单击') def qianming(self, event): obj = self.qianmingButton # obj.setText('运行中') title = obj.text() cmd = 'jarsigner -verbose -keystore key.keystore -storepass 123456 -signedjar ' + self.new_android_name + ' ' + self.tmp_android_name + ' key.keystore' cwd = self.apktool_path code = "gbk" path = self.new_android_name self.add_cmd_msg(cmd, cwd, title, obj, path, code) print('APK签名,按钮被单击') def heidisql(self, event): cmd = 'start "" ' + config['TOOL_PATH']['heidisql_path'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('heidisql,按钮被单击') def gmurl(self, event): cmd = 'start ' + config['WEB']['gm_url'] Popen(cmd, shell=True, # cwd=config['MYSQL']['mysql_path'] + 'bin', # encoding='utf-8' ) print('gmurl,按钮被单击') #TODO 增加自动登录GM后台功能 # 利用新线程进行脚本执行回显 def add_cmd_msg(self, cmd, cwd="", title="", obj="", path="", code="utf8"): obj.setEnabled(False) self.CMDtextEdit.clear() self.CMDtextEdit.append(title + "脚本开始执行!") self.work = Thread(cmd, cwd, title, obj, path, code) self.work.trigger.connect(self.show_msg) # 线程中的trigger与主类中的方法进行绑定 self.work.daemon = True # 主进程退出则该线程也退出 self.work.start() # 开启线程 # 更新UI方法 def show_msg(self, str): self.CMDtextEdit.moveCursor(QTextCursor.End) self.CMDtextEdit.append(str) # self.CMDtextEdit.insertPlainText(str) # self.CMDtextEdit.insertHtml(str) # 线程类 class Thread(QThread): trigger = pyqtSignal(str) # 注意pyqtSignal一定要实例到__init__前面 def __init__(self, cmd, cwd="", title="", obj="", path="", code="utf8"): super(Thread, self).__init__() # 定义的变量 self.cmd = cmd self.cwd = cwd self.title = title self.obj = obj self.path = path self.code = code self.state = True # 执行耗时操作 def run(self): process = subprocess.Popen(self.cmd, shell=True, cwd=self.cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) while process.poll() is None: line = process.stdout.readline() line = line.strip() if line: self.trigger.emit(line.decode(self.code, 'ignore')) print(line.decode(self.code, 'ignore')) self.trigger.emit(self.title + '脚本执行结束!') self.obj.setEnabled(True) # self.obj.setText(self.title) # print(self.obj) # self.fanbianyiButton.setEnabled(False) # self.fanbianyiButton.setText('运行中') if self.path != "": self.trigger.emit('文件路径:' + self.path) startfile(self.path) # MYSQL操作函数 def mysql_run(sqls, table=""): print(sqls) # 打开数据库连接 db = pymysql.connect(host=config['MYSQL']['mysql_host'], user=config['MYSQL']['mysql_user'], password=config['MYSQL']['mysql_pass'], database=table, port=int(config['MYSQL']['mysql_port']) ) # 使用cursor()方法获取操作游标 cursor = db.cursor() for sql in sqls: try: # 执行SQL语句 cursor.execute(sql) # 提交到数据库执行 db.commit() print('更新成功') except: print('出错了') # 发生错误时回滚 db.rollback() # 关闭数据库连接 db.close() print('MySql执行完毕') # 进程判断,返回进程ID def checkprocess(processname): pl = psutil.pids() for pid in pl: if psutil.Process(pid).name() == processname: return pid # 打开文件或文件夹,并且选中文件 def startfile(filename): try: os.startfile(f'explorer /select, "{pathlib.Path(filename)}') except: subprocess.Popen(f'explorer /select, "{pathlib.Path(filename)}') if __name__ == '__main__': app = QApplication(sys.argv) myWin = MainWindow() myWin.show() sys.exit(app.exec_())