def run_parse(): # extract parameters input_file, id_, file_tag = common.extract_parameters() repo_name = "events.cbrugger.results" # copy previous result files common.clone(repo_name) result_dir = os.path.join(common.project_path(), repo_name, "inputs") for filename in os.listdir(result_dir): shutil.copy(os.path.join(result_dir, filename), common.project_path()) # run script returncode = common.run_returncode([ 'python', 'scripts/parse_results.py', '--chunks', str(common.N_EVENT_CHUNKS), common.to_basename(input_file) ]) # check return code if returncode == common.EXIT_FILE_MISSING: print("INFO: file missing, exiting gracefully") return elif returncode != 0: raise RuntimeError("Error while calling script") # push results to next repository filenames = [ path for path in os.listdir(common.project_path()) if path.endswith(".html") ] common.upload_file(filenames, repo_name, id_, file_tag, do_clone=False) print("Parse done")
def __init__(self, parent=None): super().__init__(parent) self.cf = configparser.RawConfigParser() self.mysql_dir_path = abspath(join(common.project_path(), 'mysql')) self.ini_path = abspath(join(self.mysql_dir_path, 'my.ini')) self.mysql_exist = False self.already_load_cf = False self.sel_exist_mysql()
def __init__(self): self.cf = configparser.RawConfigParser() self.cf.read(abspath(join(common.project_path(), 'base.ini'))) # 同步锁 self.mutex = threading.Lock() self.access_token = self.cf.get('token', 'access_token') self.client_id = self.cf.get('token', 'client_id') self.client_secret = self.cf.get('token', 'client_secret') self.redirect_uri = self.cf.get('token', 'redirect_uri') self.app_url = self.cf.get('token', 'app_url') self.refresh_token = self.cf.get('token', 'refresh_token') # 实例化时立即尝试获取token,避免多线程并发 _thread.start_new_thread(self.__get_access_token, ())
class V2ray(QObject): """ V2ray管理 """ v2ray_dir_path = abspath(join(common.project_path(), 'v2ray')) v2ray_exe_name = 'wv2ray.exe' v2ray_conf_name = 'config.json' pac_name = join(v2ray_dir_path, 'pac.js') proxy_exe_name = 'v2ray_privoxy.exe' proxy_conf_name = 'privoxy.conf' ndata_path = join(v2ray_dir_path, 'ndata') config_path = join(v2ray_dir_path, 'config.json') v2rayLogSignal = pyqtSignal(str, arguments=['log']) startedSignal = pyqtSignal() stopedSignal = pyqtSignal() quitedSignal = pyqtSignal() updPacStateSignal = pyqtSignal(str, arguments=['state']) # processSignal = pyqtSignal(QVariant, arguments=['process']) def __init__(self, parent=None): super().__init__(parent) self.v2ray_popen = None self.proxy_popen = None # 加载存储的节点 try: with open(self.ndata_path, "rb") as f: self.saved_conf = pickle.load(f) except: self.pac_conf = None self.saved_conf = {"local": {}, "subs": {}} try: # 加载pac with open(self.pac_name, "r", encoding="utf-8") as f: self.pac_conf = ''.join(f.readlines()) except: self.pac_conf = None logging.debug('PAC加载失败') self.conf = dict(self.saved_conf['local'], **self.saved_conf['subs']) # 开启pac server _thread.start_new_thread(self.pac_web_server, ()) @pyqtSlot(name='sel', result=QVariant) def sel(self): return self.saved_conf @pyqtSlot(name='checkPac', result=str) def check_pac(self): if self.pac_conf == None: return 'error' return '' @pyqtSlot(name='start') def start(self): _thread.start_new_thread(self.__start, ()) def __start(self): # 停止v2ray进程 common.kill_progress(self.v2ray_exe_name) # 停止代理进程 common.kill_progress(self.proxy_exe_name) _thread.start_new_thread(self.start_v2ray, ()) _thread.start_new_thread(self.start_proxy, ()) mode = setting_instance.settings['proxy_mode'] if mode == 'Off': setting_instance.set_proxy_mode('ProxyOnly') self.set_proxy(mode) self.startedSignal.emit() @pyqtSlot(name='quit') def quit(self): _thread.start_new_thread(self.__quit, ()) def __quit(self): # 停止v2ray进程 common.kill_progress(self.v2ray_exe_name) # 停止代理进程 common.kill_progress(self.proxy_exe_name) self.set_proxy('Off') self.quitedSignal.emit() @pyqtSlot(str, name='changeNode', result=str) def change_node(self, node): try: self.setconf(node, '10808') self.restart() return '' except Exception as e: return e.args[0] @pyqtSlot(str, name='delNode') def del_node(self, node): self.delconf(node) @pyqtSlot(QVariant, name='editNode', result=str) def edit_node(self, node): # 删除旧的节点配置 try: node = node.toVariant() self.delconf(node['oldps']) self.add_conf(node['ps'], node) if setting_instance.settings['proxy_node'] == node['oldps']: setting_instance.set_proxy_node(node['ps']) self.setconf(node['ps'], '10808') self.restart() return '' except: return 'error' def restart(self): _thread.start_new_thread(self.__restart, ()) def __restart(self): common.kill_progress(self.v2ray_exe_name) common.kill_progress(self.proxy_exe_name) self.set_proxy('Off') self.__start() @pyqtSlot(name='parse', result=str) def parse(self): try: paste_str = pyperclip.paste() ret = self.parse_conf_by_uri(paste_str) self.add_conf_by_uri(paste_str) if setting_instance.settings['proxy_node'] == None: setting_instance.set_proxy_node(ret['ps']) self.setconf(ret['ps'], '10808') return '' except Exception as e: return e.args[0] @pyqtSlot(name='stop') def stop(self): _thread.start_new_thread(self.__stop, ()) def __stop(self): # 停止v2ray进程 common.kill_progress(self.v2ray_exe_name) # 停止代理进程 common.kill_progress(self.proxy_exe_name) self.set_proxy('Off') self.stopedSignal.emit() def start_v2ray(self): # 窗口信息 startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = subprocess.CREATE_NEW_CONSOLE | subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE # 启动v2ray进程 cmd = '\"{}\" -config \"{}\"'.format( join(self.v2ray_dir_path, self.v2ray_exe_name), join(self.v2ray_dir_path, self.v2ray_conf_name)) popen = subprocess.Popen(cmd, startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW) self.v2ray_popen = popen # 重定向标准输出 None表示正在执行中 while popen.poll() is None: r = popen.stdout.readline().decode('utf8') if r.replace('\r', '').replace('\n', '').strip(' ') != '': logging.debug(r.replace('\n', '')) self.v2rayLogSignal.emit(r.replace('\n', '')) def start_proxy(self): # 窗口信息 startupinfo = subprocess.STARTUPINFO() startupinfo.dwFlags = subprocess.CREATE_NEW_CONSOLE | subprocess.STARTF_USESHOWWINDOW startupinfo.wShowWindow = subprocess.SW_HIDE # 启动proxy进程 cmd = '\"{}\" \"{}\"'.format( join(self.v2ray_dir_path, self.proxy_exe_name), join(self.v2ray_dir_path, self.proxy_conf_name)) popen = subprocess.Popen(cmd, startupinfo=startupinfo, stdout=subprocess.PIPE, stderr=subprocess.PIPE, creationflags=subprocess.CREATE_NO_WINDOW) self.proxy_popen = popen def get_uri_type(self, uri): try: op = uri.split("://") if op[0] == "vmess": return "vmess" elif op[0] == "ss": return "shadowsocks" else: raise MyException("无法解析的链接格式") except Exception as e: if e.args[0] == "无法解析的链接格式": raise MyException("无法解析的链接格式") raise MyException("解析失败") def b642conf(self, prot, b64str): """ base64转化为dict类型配置 :param prot: :param tp: :param b64str: :return: """ if prot == "vmess": ret = json.loads( parse.unquote(base64.b64decode(b64str + "==").decode()).replace( "\'", "\"")) region = ret['ps'] elif prot == "shadowsocks": string = b64str.split("#") cf = string[0].split("@") if len(cf) == 1: tmp = parse.unquote(base64.b64decode(cf[0] + "==").decode()) else: tmp = parse.unquote( base64.b64decode(cf[0] + "==").decode() + "@" + cf[1]) print(tmp) ret = { "method": tmp.split(":")[0], "port": tmp.split(":")[2], "password": tmp.split(":")[1].split("@")[0], "add": tmp.split(":")[1].split("@")[1], } region = parse.unquote(string[1]) ret["prot"] = prot return ret def setconf(self, region, socks, proxy=None): """ 生成配置 :param region: 当前VPN别名 :param socks: socks端口 :return: """ use_conf = self.conf[region] conf = copy.deepcopy(common.tpl) conf["inbounds"][0]["port"] = socks # 如果是vmess if use_conf['prot'] == "vmess": conf['outbounds'][0]["protocol"] = "vmess" conf['outbounds'][0]["settings"]["vnext"] = list() conf['outbounds'][0]["settings"]["vnext"].append({ "address": use_conf["add"], "port": int(use_conf["port"]), "users": [{ "id": use_conf["id"], "alterId": int(use_conf["aid"]), "security": "auto", "level": 8, }] }) # webSocket 协议 if use_conf["net"] == "ws": conf['outbounds'][0]["streamSettings"] = { "network": use_conf["net"], "security": "tls" if use_conf["tls"] else "", "tlssettings": { "allowInsecure": True, "serverName": use_conf["host"] if use_conf["tls"] else "" }, "wssettings": { "connectionReuse": True, "headers": { "Host": use_conf['host'] }, "path": use_conf["path"] } } # mKcp协议 elif use_conf["net"] == "kcp": conf['outbounds'][0]["streamSettings"] = { "network": use_conf["net"], "kcpsettings": { "congestion": False, "downlinkCapacity": 100, "header": { "type": use_conf["type"] if use_conf["type"] else "none" }, "mtu": 1350, "readBufferSize": 1, "tti": 50, "uplinkCapacity": 12, "writeBufferSize": 1 }, "security": "tls" if use_conf["tls"] else "", "tlssettings": { "allowInsecure": True, "serverName": use_conf["host"] if use_conf["tls"] else "" } } # tcp elif use_conf["net"] == "tcp": conf['outbounds'][0]["streamSettings"] = { "network": use_conf["net"], "security": "tls" if use_conf["tls"] else "", "tlssettings": { "allowInsecure": True, "serverName": use_conf["host"] if use_conf["tls"] else "" }, "tcpsettings": { "connectionReuse": True, "header": { "request": { "version": "1.1", "method": "GET", "path": [use_conf["path"]], "headers": { "User-Agent": [ "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36" ], "Accept-Encoding": ["gzip, deflate"], "Connection": ["keep-alive"], "Pragma": "no-cache", "Host": [use_conf["host"]] } }, "type": use_conf["type"] } } if use_conf["type"] != "none" else {} } # QUIC # elif use_conf["net"] == "quic": # conf['outbounds'][0]["streamSettings"] = { # "network": use_conf["net"], # "security": "tls" if use_conf["tls"] else "none", # "tlssettings": { # "allowInsecure": True, # "serverName": use_conf["host"] # }, # "quicsettings": { # "headers": { # "type": use_conf['type'] # }, # "key": # } # } # 如果是ss elif use_conf['prot'] == "shadowsocks": conf['outbounds'][0]["protocol"] = "shadowsocks" conf['outbounds'][0]["settings"]["servers"] = list() conf['outbounds'][0]["settings"]["servers"].append({ "address": use_conf["add"], "port": int(use_conf["port"]), "password": use_conf["password"], "ota": False, "method": use_conf["method"] }) conf['outbounds'][0]["streamSettings"] = {"network": "tcp"} else: raise MyException("不支持的协议类型") # 是否进行透明代理 # if proxy and use_conf['prot'] == "vmess": # # 修改入站协议 # conf["inbounds"].append({ # "tag": "transparent", # "port": 12345, # "protocol": "dokodemo-door", # "settings": { # "network": "tcp,udp", # "followRedirect": True, # "timeout": 30 # }, # "sniffing": { # "enabled": True, # "destOverride": [ # "http", # "tls" # ] # }, # "streamSettings": { # "sockopt": { # "tproxy": "tproxy" # 透明代理使用 TPROXY 方式 # } # } # }) # # 配置dns # conf['dns']["servers"] = [ # "8.8.8.8", # 非中国大陆域名使用 Google 的 DNS # "1.1.1.1", # "114.114.114.114", # { # "address": "223.5.5.5", # "port": 53, # "domains": [ # "geosite:cn", # "ntp.org", # use_conf['host'] # ] # } # ] # # 每一个outbounds添加mark # conf['outbounds'][0]["streamSettings"]["sockopt"] = {"mark": 255} # conf['outbounds'][1]["settings"] = {"domainStrategy": "UseIP"} # conf['outbounds'][1]["streamSettings"] = dict() # conf['outbounds'][1]["streamSettings"]["sockopt"] = {"mark": 255} # conf['outbounds'].append({ # "tag": "dns-out", # "protocol": "dns", # "streamSettings": { # "sockopt": { # "mark": 255 # } # } # }) # # 配置路由 # conf['routing']["rules"].append({ # "type": "field", # "inboundTag": [ # "transparent" # ], # "port": 53, # 劫持53端口UDP流量,使用V2Ray的DNS # "network": "udp", # "outboundTag": "dns-out" # }) # conf['routing']['rules'].append({ # "type": "field", # "inboundTag": [ # "transparent" # ], # "port": 123, # 直连123端口UDP流量(NTP 协议) # "network": "udp", # "outboundTag": "direct" # }) # conf["routing"]["rules"].append({ # "type": "field", # 设置DNS配置中的国内DNS服务器地址直连,以达到DNS分流目的 # "ip": [ # "223.5.5.5", # "114.114.114.114" # ], # "outboundTag": "direct" # }) # conf["routing"]["rules"].append({ # "type": "field", # "ip": [ # "8.8.8.8", # 设置 DNS 配置中的国内 DNS 服务器地址走代理,以达到DNS分流目的 # "1.1.1.1" # ], # "outboundTag": "proxy" # }) # conf["routing"]["rules"].append({ # "type": "field", # "protocol": ["bittorrent"], # BT流量直连 # "outboundTag": "direct" # }) # if proxy == 1: # 国内网站直连: # conf["routing"]["rules"].append({ # "type": "field", # "ip": [ # "geoip:private", # "geoip:cn" # ], # "outboundTag": "direct" # }) # conf["routing"]["rules"].append({ # "type": "field", # "domain": [ # "geosite:cn" # ], # "outboundTag": "direct" # }) # else: # gfw # conf["routing"]["rules"].append({ # "type": "field", # "domain": [ # "ext:h2y.dat:gfw" # ], # "outboundTag": "proxy" # }) # conf["routing"]["rules"].append({ # "type": "field", # "network": "tcp,udp", # "outboundTag": "direct" # }) with open(self.config_path, "w") as f: f.write(json.dumps(conf, indent=4)) def delconf(self, region): """ 删除一个配置 :param region: 配置名 :return: """ self.conf.pop(region) try: self.saved_conf['local'].pop(region) except KeyError: self.saved_conf['subs'].pop(region) except: raise MyException("配置删除出错,请稍后再试..") with open(self.ndata_path, "wb") as jf: pickle.dump(self.saved_conf, jf) def parse_conf_by_uri(self, uri): uri_type = self.get_uri_type(uri) op = uri.split("://") ret = self.b642conf(uri_type, op[1]) return ret def add_conf_by_uri(self, uri): """ 通过分享的连接添加配置 """ ret = self.parse_conf_by_uri(uri) op = uri.split("://") if op[0] == "vmess": region = ret['ps'] elif op[0] == "ss": string = op[1].split("#") region = parse.unquote(string[1]) if region in self.saved_conf["subs"]: region = region + "_local" self.add_conf(region, ret) def add_conf(self, region, node): self.saved_conf[["local", "subs"][0]][region] = node self.conf = dict(self.saved_conf['local'], **self.saved_conf['subs']) with open(self.ndata_path, "wb") as jf: pickle.dump(self.saved_conf, jf) def conf2b64(self, region): tmp = dict() prot = self.conf[region]['prot'] for k, v in self.conf[region].items(): tmp[k] = v tmp.pop("prot") if prot == "vmess": return prot + "://" + base64.b64encode(str(tmp).encode()).decode() else: prot = "ss" return prot + "://" + base64.b64encode("{}:{}@{}:{}".format( tmp["method"], tmp["password"], tmp["add"], tmp["port"]).encode()).decode() + "#" + region @pyqtSlot(name='updPac') def upd_pac(self): _thread.start_new_thread(self.__upd_pac, ()) def __upd_pac(self): proxies = { "http": "http://127.0.0.1:10809", "https": "http://127.0.0.1:10809", } try: r = requests.get( "https://raw.githubusercontent.com/gfwlist/gfwlist/master/gfwlist.txt", proxies=proxies) rt = base64.b64decode(r.content).decode() ignoredLineBegins = ['!', '['] rt_array = rt.splitlines() new_rt_array = [] for l in rt_array: if not (l.startswith(ignoredLineBegins[0]) or l.startswith(ignoredLineBegins[1])): if not (l.isspace() or len(l) == 0): new_rt_array.append(l) json_str = json.dumps(new_rt_array, indent=2) self.pac_conf = v2ray_adpt.adpt.replace('__RULES__', json_str) self.pac_conf = self.pac_conf.replace( '__PROXY__', 'PROXY {0}:{1};'.format('127.0.0.1', '10809')) with open(self.pac_name, 'w') as f: f.write(self.pac_conf) self.updPacStateSignal.emit('success') except: self.updPacStateSignal.emit('error') def handle_client(self, client_socket): """ 处理客户端请求 """ # 获取客户端请求数据 client_socket.recv(1024) # 构造响应数据 response_start_line = "HTTP/1.1 200 OK\r\n" # response_body = self.pac_conf.replace('\n','\r\n') response_headers = "Server: Microsoft-HTTPAPI/2.0\r\nContent-Type: application/x-ns-proxy-autoconfig\r\nContent-Length: {}\r\n".format( len(self.pac_conf.encode('utf-8'))) response = response_start_line + response_headers + "\r\n" + self.pac_conf # 向客户端返回响应数据 client_socket.send(bytes(response, "utf-8")) # 关闭客户端连接 client_socket.close() def pac_web_server(self): """ 开启pac web 服务 """ server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server_socket.bind(("", 18001)) server_socket.listen(128) print('开始pac运行服务') while True: client_socket, client_address = server_socket.accept() logging.debug("[%s, %s]请求" % client_address) _thread.start_new_thread(self.handle_client, (client_socket, )) def set_proxy(self, op): if op == 'Off': disable_proxy() else: if op == 'ProxyOnly': set_proxy_server('127.0.0.1:10809') elif op == 'PacOnly': set_proxy_auto('http://127.0.0.1:18001/')
def unzip(self, src_file, out_dir): _thread.start_new_thread(self.__unzip, (abspath(join(common.project_path(), src_file)) , abspath(join(common.project_path(), out_dir))))
class Setting(QObject): """ 软件设置 """ yaml_path = os.path.join(common.project_path(), "setting.yaml") program_path = sys.argv[0] futility_signal = pyqtSignal() settings = { 'autostarts': 1, 'lang': 1, 'opacity': 0.98, 'service': 'MysqlServer56', 'top': False, 'block_size': 2, 'init': True, 'log': True, 'autostart': False, 'listenurl': False, 'listenkeyboard': False, 'window_width': 850, 'window_height': 600, } def __init__(self, parent=None): super().__init__(parent) self.background_run_param = False exists = os.path.exists(self.yaml_path) if not exists: self.save_cfg() with open(self.yaml_path, "r", encoding="utf-8") as f: self.settings = yaml.load(f) def save_cfg(self): with open(self.yaml_path, "w", encoding="utf-8") as f: yaml.dump(self.settings, f, default_flow_style=False) @pyqtProperty(bool, notify=futility_signal) def background_run(self): return self.background_run_param @pyqtProperty(int, notify=futility_signal) def lang(self): return self.settings['lang'] @lang.setter def lang(self, val): self.settings['lang'] = val self.save_cfg() @pyqtProperty(float, notify=futility_signal) def opacity(self): return self.settings['opacity'] @opacity.setter def opacity(self, val): self.settings['opacity'] = val self.save_cfg() @pyqtProperty(int, notify=futility_signal) def autostarts(self): return self.settings['autostarts'] @autostarts.setter def autostarts(self, val): self.settings['autostarts'] = val self.save_cfg() @pyqtProperty(str, notify=futility_signal) def service(self): return self.settings['service'] @service.setter def service(self, val): self.settings['service'] = val self.save_cfg() @pyqtProperty(bool, notify=futility_signal) def top(self): return self.settings['top'] @top.setter def top(self, val): self.settings['top'] = val self.save_cfg() @pyqtProperty(bool, notify=futility_signal) def listenurl(self): return self.settings['listenurl'] @listenurl.setter def listenurl(self, val): self.settings['listenurl'] = val self.save_cfg() @pyqtProperty(bool, notify=futility_signal) def listenkeyboard(self): return self.settings['listenkeyboard'] @listenkeyboard.setter def listenkeyboard(self, val): self.settings['listenkeyboard'] = val self.save_cfg() @pyqtProperty(bool, notify=futility_signal) def init(self): return self.settings['init'] @init.setter def init(self, val): self.settings['init'] = val self.save_cfg() @pyqtProperty(bool, notify=futility_signal) def autostart(self): return self.settings['autostart'] @autostart.setter def autostart(self, val): self.settings['autostart'] = val self.save_cfg() # 设置开机自启动 key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Windows\CurrentVersion\Run", access=winreg.KEY_WRITE) if val: winreg.SetValueEx(key, "ZTool", 0, winreg.REG_SZ, '"{0}" background'.format(self.program_path)) else: try: winreg.DeleteValue(key, "ZTool") except: pass @pyqtProperty(int, notify=futility_signal) def window_width(self): return self.settings['window_width'] @window_width.setter def window_width(self, val): self.settings['window_width'] = val self.save_cfg() @pyqtProperty(int, notify=futility_signal) def window_height(self): return self.settings['window_height'] @window_height.setter def window_height(self, val): self.settings['window_height'] = val self.save_cfg()
class MysqlServiceManager(QObject): """ Mysql服务管理 """ statusSignal = pyqtSignal(str, arguments=['status']) pwdSignal = pyqtSignal(str, arguments=['status']) mysql_dir_path = abspath(join(common.project_path(), 'mysql')) mysqld_name = 'mysqlddkw.exe' def __init__(self, parent=None): super().__init__(parent) self.cf = mysql_configuration_instance.cf self.setting = setting_instance self.new_pwd = None self.rboot = None _thread.start_new_thread(self.status_update_thread, ()) @pyqtSlot(result=str, name='installService') def install_service(self): """ 安装mysql服务 """ cmd = '\"{0}\" --install{1} {2} --defaults-file=\"{3}\"'.format( join(self.mysql_dir_path, 'bin', self.mysqld_name), ('' if self.setting.settings['autostarts'] == 1 else '-manual'), self.setting.settings['service'], join(self.mysql_dir_path, 'my.ini')) logging.debug('install mysql cmd:{}'.format(cmd)) tmp = os.popen(cmd).readlines() tmp = "".join(tmp).lower() if tmp.find('successfully') != -1: return 'ok' elif tmp.find('already exists') != -1: return 'exists' else: return 'error' @pyqtSlot(result=str, name='uninstallService') def uninstall_service(self): """ 卸载mysql服务 """ cmd = '\"{0}\" --remove {1}'.format( join(self.mysql_dir_path, 'bin', self.mysqld_name), self.setting.settings['service']) logging.debug('uninstall mysql cmd:{}'.format(cmd)) tmp = os.popen(cmd).readlines() tmp = "".join(tmp).lower() if tmp.find('success') != -1: return 'ok' else: return 'error' @pyqtSlot(str, str, result=str, name='modifiedPassword') def modified_password(self, newp, rboot): """ 强制修改mysql密码 """ self.new_pwd = newp self.rboot = rboot _thread.start_new_thread(self.skip_pwd_start_service, ()) return 'ok' @pyqtSlot(result=str, name='startService') def start_service(self): """ 启动mysql服务 """ cmd = 'sc start ' + self.setting.settings['service'] logging.debug('start mysql cmd:{}'.format(cmd)) tmp = os.popen(cmd).readlines() tmp = "".join(tmp).lower() if tmp.find('start_pending') != -1: return 'ok' else: return 'error' def skip_pwd_start_service(self): """ 跳过密码启动mysql服务 """ self.kill_progress() cmd = '\"{0}\" --defaults-file=\"{1}\" --skip-grant-tables'.format( join(self.mysql_dir_path, 'bin', self.mysqld_name), join(self.mysql_dir_path, 'my.ini')) os.popen(cmd) logging.debug('modified mysql password cmd:{}'.format(cmd)) try_count = 0 successed = False while True: try: try_count += 1 connect = pymysql.connect(host='127.0.0.1', port=3309, user='******', passwd='123', db='mysql', charset='utf8') cursor = connect.cursor() sql = 'update mysql.user set Password=password(\'{0}\') where User=\'root\';'.format( self.new_pwd) # 执行SQL语句 cursor.execute(sql) connect.commit() successed = True self.kill_progress() if self.rboot == '1': self.start_service() break except: logging.debug("try connect mysql fail") if try_count == 3: break self.pwdSignal.emit('ok' if successed else 'false') @pyqtSlot(result=str, name='stopService') def stop_service(self): """ 停止mysql服务 """ cmd = 'sc stop ' + self.setting.settings['service'] logging.debug('stop mysql cmd:{}'.format(cmd)) tmp = os.popen(cmd).readlines() tmp = "".join(tmp).lower() if tmp.find('stop_pending') != -1: return 'ok' else: return 'error' @pyqtSlot(result=str, name='killProgress') def kill_progress(self): """ 强制停止进程 """ status = common.kill_progress(self.mysqld_name) if status: return 'ok' else: return 'error' @pyqtSlot(result=str, name='statusService') def status_service(self): """ 获取mysql服务状态 """ cmd = 'sc query ' + self.setting.settings['service'] tmp = os.popen(cmd).readlines() tmp = "".join(tmp).lower() if tmp.find('stopped') != -1: return 'stopped' elif tmp.find('1060') != -1: return 'notfound' elif tmp.find('running') != -1: return 'running' elif tmp.find('stop_pending') != -1: return 'stopPending' elif tmp.find('start_pending') != -1: return 'startPending' else: return 'error' def status_update_thread(self): """ 会阻塞线程,开启新线程启动 """ while True: mysql_configuration_instance.sel_exist_mysql() if mysql_configuration_instance.mysql_exist: status = self.status_service() else: status = 'notExist' self.statusSignal.emit(status) time.sleep(0.5)
class Wechat(QObject): """ 微信机器人控制器 """ futility_signal = pyqtSignal() websocket_client = None jobs_path = abspath(join(common.project_path(), 'jobs')) userListSignal = pyqtSignal(QVariant, arguments=['userList']) wechatLogSignal = pyqtSignal(str, arguments=['log']) websocketStateSignal = pyqtSignal(bool, arguments=['state']) websocketOnline = False jobs_conf = None jobExedSignal = pyqtSignal(str, arguments=['job_id']) hookStateSignal = pyqtSignal(str, arguments=['state']) weather_template = '晚上好呀!下面是明天的天气情况[吃瓜]\n\n你的城市:{city_name}\n天气:{tomorrow_text}\n温度:{tomorrow_temp}\n风向:{tomorrow_wind}\n贴心提示:{tomorrow_dress_tips}\n运动:{tomorrow_sport_tips}\n紫外线:{tomorrow_ua_tips}\n预测时间:{update_time}\n\nONE.一个:{one}' def __init__(self, parent=None): super().__init__(parent) @pyqtSlot(name='initScheduler') def init_scheduler(self): self.scheduler = BackgroundScheduler() self.scheduler.start() # 加载存储的节点 try: with open(self.jobs_path, "rb") as f: self.jobs_conf = pickle.load(f) except: self.jobs_conf = [] # 初始化执行定时器 self.__reset_scheduler() def sync_request(self,url): req_count = 0 while req_count < 10: try: return requests.get(url, timeout=10, headers={"content-type": "application/json"}) except: req_count += 1 return None @pyqtSlot(name='hook') def hook(self): _thread.start_new_thread(self.__hook, ()) def __hook(self): PAGE_READWRITE = 0x00000040 PROCESS_ALL_ACCESS = (0x000F0000|0x00100000|0xFFF) VIRTUAL_MEM = (0x00001000 | 0x00002000) dll_path = bytes((os.path.abspath('.')+"\\version2.9.0.123-4.5.7.71.dll").encode('utf-8')) print(dll_path) dll_len = len(dll_path) kernel32 = ctypes.windll.kernel32 wechat_path = '' #第一步获取整个系统的进程快照 pids = psutil.pids() #第二步在快照中去比对进程名 for pid in pids: p= psutil.Process(pid) try: if p.name()=='WeChat.exe': wechat_path = p.cwd() break else: pid = 0 except: pass #第三步用找到的pid去打开进程获取到句柄 if pid == 0: self.hookStateSignal.emit('NOT_FOUND_WECHAT') else: h_process=kernel32.OpenProcess(PROCESS_ALL_ACCESS,False,(pid)) if not h_process: self.hookStateSignal.emit('ERROR') return else: arg_adress=kernel32.VirtualAllocEx(h_process,None,dll_len*10,VIRTUAL_MEM,PAGE_READWRITE) NULL = c_int(0) kernel32.WriteProcessMemory(h_process,arg_adress,dll_path,dll_len*10,NULL) h_kernel32 = win32api.GetModuleHandle("kernel32.dll") h_loadlib = win32api.GetProcAddress(h_kernel32, 'LoadLibraryA') thread_id = c_ulong(0) c_remt = kernel32.CreateRemoteThread(h_process,None,0,c_long(h_loadlib),arg_adress,0,byref(thread_id)) self.hookStateSignal.emit('SUCCESS') def get_weather(self, job): req_count = 0 res = self.sync_request('https://geoapi.qweather.net/v2/city/lookup?location={}&key={}'.format( job['location'],setting_instance.settings['qweather_key'])) city_name = None if res is not None: res_content = res.content.decode() print(res_content) json_res = json.loads(res_content) city_name = json_res['location'][0]['name'] req_count = 0 res = self.sync_request('https://api.qweather.net/v7/weather/3d?location={}&key={}'.format( job['location'],setting_instance.settings['qweather_key'])) tomorrow_text = None tomorrow_temp = None tomorrow_wind = None update_time = None if res is not None: res_content = res.content.decode() print(res_content) json_res = json.loads(res_content) update_time = json_res['updateTime'] tomorrow_text = json_res['daily'][1]['textDay'] tomorrow_temp = json_res['daily'][1]['tempMin'] + \ '~' + json_res['daily'][1]['tempMax'] tomorrow_wind = json_res['daily'][1]['windDirDay'] + \ json_res['daily'][1]['windScaleDay'] + '级' print('update_time:{},tomorrow_text:{},tomorrow_temp:{},tomorrow_wind:{}'.format( update_time, tomorrow_text, tomorrow_temp, tomorrow_wind)) req_count = 0 res = self.sync_request('https://api.qweather.net/v7/indices/3d?location={}&type=1,3,5&key={}'.format( job['location'],setting_instance.settings['qweather_key'])) tomorrow_dress_tips = None tomorrow_sport_tips = None tomorrow_ua_tips = None if res is not None: res_content = res.content.decode() print(res_content) json_res = json.loads(res_content) tomorrow_sport_tips = json_res['daily'][3]['text'] tomorrow_dress_tips = json_res['daily'][4]['text'] tomorrow_ua_tips = json_res['daily'][5]['text'] print('tomorrow_dress_tips:{},tomorrow_sport_tips:{},tomorrow_ua_tips:{}'.format( tomorrow_dress_tips, tomorrow_sport_tips, tomorrow_ua_tips)) # 获取ONE one = common.get_wufazhuce_info() result = self.weather_template.format(tomorrow_text=tomorrow_text, tomorrow_temp=tomorrow_temp, tomorrow_wind=tomorrow_wind, tomorrow_dress_tips=tomorrow_dress_tips, tomorrow_sport_tips=tomorrow_sport_tips, tomorrow_ua_tips=tomorrow_ua_tips, update_time=update_time, city_name=city_name, one=one) return result def __job_task(self, job): self.jobExedSignal.emit(job['job_id']) msg = None if job['msg_type'] == 'weather': msg = self.get_weather(job) elif job['msg_type'] == 'text': msg = job['msg'] json_msg = { 'id': self._getid(), 'type': 555, 'content': msg, 'wxid': job['wxid'] } if self.websocketOnline: self.ws.send(json.dumps(json_msg)) def __reset_scheduler(self): self.scheduler.remove_all_jobs() for index, item in enumerate(self.jobs_conf): if item['job_enable']: if item['trigger'] == 'interval': self.scheduler.add_job(self.__job_task, 'interval', coalesce=True, misfire_grace_time=3600, weeks=int(item['weeks']), days=int(item['days']), hours=int( item['hours']), minutes=int(item['minutes']), seconds=int(item['seconds']), jitter=int(item['jitter']), id=item['job_id'], args=[item]) elif item['trigger'] == 'cron': self.scheduler.add_job(self.__job_task, 'cron', coalesce=True, misfire_grace_time=3600, second=item['second'], minute=item[ 'minute'], hour=item['hour'], day_of_week=item['day_of_week'], jitter=int(item['jitter']), id=item['job_id'], args=[item]) @pyqtSlot(QVariant, name='addJob') def add_job(self, job): job = job.toVariant() job['job_id'] = self._getid() self.jobs_conf.append(job) self._save_conf() self.__reset_scheduler() @pyqtSlot(QVariant, name='editJob') def edit_job(self, job): job = job.toVariant() for index, item in enumerate(self.jobs_conf): if item['job_id'] == job['job_id']: self.jobs_conf[index] = job self._save_conf() self.__reset_scheduler() @pyqtSlot(str, name='delJob') def del_job(self, job_id): job_index = 0 for index, item in enumerate(self.jobs_conf): if item['job_id'] == job_id: job_index = index self.jobs_conf.pop(job_index) self._save_conf() self.__reset_scheduler() @pyqtSlot(name='getJobsConf', result=QVariant) def get_jobs_conf(self): return self.jobs_conf @pyqtSlot(name='getJobsState', result=QVariant) def get_jobs_state(self): jobs = self.scheduler.get_jobs() jobs_state = {} for job in jobs: jobs_state[job.id] = datetime_repr(job.next_run_time) return jobs_state def _save_conf(self): with open(self.jobs_path, "wb") as jf: pickle.dump(self.jobs_conf, jf) def _getid(self): id = str(int(time.time() * 1000)) return id @pyqtSlot(name='getUserList') def get_user_list(self): if self.websocketOnline: self.ws.send( '{"id":"1231231236","type":5000,"content":"user list","wxid":"null"}') @pyqtSlot(str, str, name='sendMessage') def send_message(self, wxid, msg): logging.debug("发送消息,wxid:{0},msg:{1}".format(wxid, msg)) json_msg = { 'id': self._getid(), 'type': 555, 'content': msg, 'wxid': wxid } if self.websocketOnline: self.ws.send(json.dumps(json_msg)) @pyqtSlot(name='websocketInit') def websocket_init(self): if self.websocketOnline: self.ws.close() _thread.start_new_thread(self._websocket_init, ()) def _websocket_init(self): self.ws = websocket.WebSocketApp('ws://127.0.0.1:5555', on_open=self.on_open, on_message=self.on_message, on_error=self.on_error, on_close=self.on_close) self.ws.run_forever() def on_message(self, message): logging.debug('wechat msg:{0}'.format(message)) json_message = json.loads(message) self.wechatLogSignal.emit(message) if json_message['type'] == 5000: self.userListSignal.emit(json_message) def on_error(self, error): print("on_error") def on_open(self): print("on_open") self.websocketOnline = True self.websocketStateSignal.emit(True) def on_close(self): print("on_close") self.websocketOnline = False self.websocketStateSignal.emit(False)
def open_dir(self, file_path): if file_path.find(':') != -1: common.open_dir(abspath(file_path)) else: common.open_dir(abspath(join(common.project_path(), file_path)))
class Aria2(QObject): """ 下载控制器 """ processSignal = pyqtSignal(QVariant, arguments=['process']) taskStateSignal = pyqtSignal(str, QVariant, arguments=['gid', 'process']) msgSignal = pyqtSignal(str, arguments=['msg']) flagMsgSignal = pyqtSignal(str, str, str, arguments=['msg', 'flag', 'taskId']) aria2StopedSignal = pyqtSignal() listenerUrl = pyqtSignal(str, arguments=['url']) aria2_path = abspath(join(common.project_path(), 'aria2', 'aria2c.exe')) default_config = { # 文件的保存路径(可使用绝对路径或相对路径), 默认: 当前启动位置 'dir': 'aria2/Download', # 启用磁盘缓存, 0为禁用缓存, 需1.16以上版本, 默认:16M 'disk-cache': '32M', # 文件预分配方式, 能有效降低磁盘碎片, 默认:prealloc # 预分配所需时间: none < falloc < trunc < prealloc # NTFS建议使用falloc 'file-allocation': 'none', # 断点续传 'continue': 'true', # 最大同时下载任务数, 运行时可修改, 默认:5 'max-concurrent-downloads': '5', # 同一服务器连接数, 添加时可指定, 默认:1 'max-connection-per-server': '16', # 最小文件分片大小, 添加时可指定, 取值范围1M -1024M, 默认:20M # 假定size=10M, 文件为20MiB 则使用两个来源下载; 文件为15MiB 则使用一个来源下载 'min-split-size': '1M', # 单个任务最大线程数, 添加时可指定, 默认:5 'split': '100', # 整体上传速度限制, 运行时可修改, 默认:0 'max-overall-upload-limit': '1M', # 禁用IPv6, 默认:false 'disable-ipv6': 'true', # 从会话文件中读取下载任务 'input-file': 'aria2/aria2.session', # 在Aria2退出时保存`错误/未完成`的下载任务到会话文件 'save-session': 'aria2/aria2.session', # 定时保存会话, 0为退出时才保存, 需1.16.1以上版本, 默认:0 'save-session-interval': '60', # 启用RPC, 默认:false 'enable-rpc': 'true', # rpc端口 'rpc-listen-port': '6800', # 允许所有来源, 默认:false 'rpc-allow-origin-all': 'true', # 允许非外部访问, 默认:false 'rpc-listen-all': 'true', } def __init__(self, parent=None): super().__init__(parent) self.popen = None # 启动aria2 _thread.start_new_thread(self.start_aria2, ()) # 启动监听剪贴板 _thread.start_new_thread(self.listener_paste, ()) @pyqtSlot(str, name='openDir') def open_dir(self, file_path): if file_path.find(':') != -1: common.open_dir(abspath(file_path)) else: common.open_dir(abspath(join(common.project_path(), file_path))) def start_aria2(self): """ 启动aria2 需要开启新线程启动,会阻塞 """ # 干掉上次的aria2进程 common.kill_progress('aria2c.exe') args = [] for item in self.default_config.items(): args.append('--' + item[0] + '=' + item[1]) args.insert(0, self.aria2_path) popen = subprocess.Popen( args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, # bufsize=1, creationflags=subprocess.CREATE_NO_WINDOW) self.popen = popen # 重定向标准输出 None表示正在执行中 while popen.poll() is None: r = popen.stdout.readline().decode('utf8') if r.replace('\r', '').replace('\n', '').strip(' ') != '': logging.debug(r.replace('\n', '')) @pyqtSlot(name='stopAria2') def stop_aria2(self): """ 停止aria2 子进程 """ _thread.start_new_thread(self.__stop_aria2, ()) def __stop_aria2(self): aria2 = Aria2RPC() aria2.saveSession() if self.popen is not None: self.popen.kill() self.aria2StopedSignal.emit() @pyqtSlot(str, QVariant, name='addTask') def add_task(self, url, options=None): """ 添加任务 :param url: 文件地址 :param options: 可选项 """ _thread.start_new_thread(self.__add_task, (url, options, None)) @pyqtSlot(str, str, name='addFlagTask') def add_flag_task(self, url, flag, options=None): """ 添加任务 :param flag: 标志 :param url: 文件地址 :param options: 可选项 """ _thread.start_new_thread(self.__add_task, (url, options, flag)) def __add_task(self, url, options, flag): aria2 = Aria2RPC() if options is None: options = {} else: options = options.toVariant() try: id = aria2.addUri([url], options=options) if flag is None: self.msgSignal.emit("addSuccess") else: self.flagMsgSignal.emit("addSuccess", flag, id) except: if flag is None: self.msgSignal.emit("addFail") else: self.flagMsgSignal.emit("addFail", flag, None) @pyqtSlot(str, name='pauseTask') def pause_task(self, gid): """ 暂停任务 :param gid: 主键 """ _thread.start_new_thread(self.__pause_task, (gid, )) def __pause_task(self, gid): aria2 = Aria2RPC() try: aria2.pause(gid) self.msgSignal.emit("pauseSuccess") except: self.msgSignal.emit("pauseFail") @pyqtSlot(str, name='unpauseTask') def start_task(self, gid): """ 开始任务 :param gid: 主键 """ _thread.start_new_thread(self.__start_task, (gid, )) def __start_task(self, gid): aria2 = Aria2RPC() try: aria2.unpause(gid) self.msgSignal.emit("startSuccess") except: self.msgSignal.emit("startFail") @pyqtSlot(str, name='removeTask') def remove_task(self, gid): """ 删除任务 :param gid: 主键 """ _thread.start_new_thread(self.__remove_task, (gid, )) def __remove_task(self, gid): aria2 = Aria2RPC() try: aria2.remove(gid) self.msgSignal.emit("removeSuccess") except: self.msgSignal.emit("removeFail") @pyqtSlot(name='selTask') def sel_task(self): """ 查询当前任务的状态 """ _thread.start_new_thread(self.__sel_task, ()) @pyqtSlot(str, name='selTaskById') def sel_task_id(self, gid): """ 查询任务的状态 """ _thread.start_new_thread(self.__sel_task_id, (gid, )) def __sel_task_id(self, gid): aria2 = Aria2RPC() file_state = aria2.getFiles(gid) self.taskStateSignal.emit(gid, QVariant(file_state)) def __sel_task(self): aria2 = Aria2RPC() res = aria2.multicall([{ 'methodName': 'aria2.getGlobalStat' }, { 'methodName': 'aria2.tellActive' }, { 'methodName': 'aria2.tellWaiting', 'params': [0, 1000] }, { 'methodName': 'aria2.tellStopped', 'params': [0, 1000] }]) self.processSignal.emit(QVariant(res)) def listener_paste(self): """ 监听剪贴板 """ recent_value = '' while True: try: tmp_value = pyperclip.paste() # 读取剪切板复制的内容 if tmp_value != recent_value: # 如果检测到剪切板内容有改动,那么就进入文本的修改 recent_value = tmp_value if recent_value.startswith( 'http://') or recent_value.startswith('https://'): logging.debug("发现链接:" + recent_value) self.listenerUrl.emit(recent_value) except: pass time.sleep(0.1)