Skip to content

Commit

Permalink
Merge pull request #22 from triwinds/dev
Browse files Browse the repository at this point in the history
PR for 0.2.6
  • Loading branch information
triwinds authored Jan 28, 2023
2 parents ced4f58 + 5888f2c commit 36b5796
Show file tree
Hide file tree
Showing 19 changed files with 1,334 additions and 305 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -217,3 +217,5 @@ download/
output/
web/
http_cache.sqlite
**/CloudflareSpeedTest/
storage.json
24 changes: 24 additions & 0 deletions api/cfst_api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from config import config
from api.common_response import *

import eel


@eel.expose
def optimize_cloudflare_hosts():
from module.cfst import optimize_cloudflare_hosts
try:
optimize_cloudflare_hosts()
return success_response()
except Exception as e:
return exception_response(e)


@eel.expose
def remove_cloudflare_hosts():
from module.cfst import remove_cloudflare_hosts
try:
remove_cloudflare_hosts()
return success_response()
except Exception as e:
return exception_response(e)
23 changes: 23 additions & 0 deletions api/common_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,26 @@ def get_net_release_info_by_tag(tag: str):
return success_response(get_release_info_by_tag(tag))
except Exception as e:
return exception_response(e)


@eel.expose
def load_history_path(emu_type: str):
from storage import storage
from config import config
emu_type = emu_type.lower()
if emu_type == 'yuzu':
return success_response(list(_merge_to_set(storage.yuzu_history.keys(), config.yuzu.yuzu_path)))
else:
return success_response(list(_merge_to_set(storage.ryujinx_history.keys(), config.ryujinx.path)))


def _merge_to_set(*cols):
from collections.abc import Iterable
s = set()
for c in cols:
if isinstance(c, Iterable) and not isinstance(c, str):
for i in c:
s.add(i)
else:
s.add(c)
return s
9 changes: 8 additions & 1 deletion api/ryujinx_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,20 @@ def ask_and_update_ryujinx_path():
folder = ask_folder()
logger.info(f'select folder: {folder}')
if folder:
from config import update_ryujinx_path
from module.ryujinx import update_ryujinx_path
update_ryujinx_path(folder)
return success_response(msg=f'修改 ryujinx 目录至 {folder}')
else:
return error_response(100, '修改已取消')


@eel.expose
def update_ryujinx_path(folder: str):
from module.ryujinx import update_ryujinx_path
update_ryujinx_path(folder)
return success_response(msg=f'修改 ryujinx 目录至 {folder}')


@eel.expose
def get_ryujinx_release_infos():
try:
Expand Down
9 changes: 8 additions & 1 deletion api/yuzu_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,20 @@ def ask_and_update_yuzu_path():
folder = ask_folder()
logger.info(f'select folder: {folder}')
if folder:
from config import update_yuzu_path
from module.yuzu import update_yuzu_path
update_yuzu_path(folder)
return success_response(msg=f'修改 yuzu 目录至 {folder}')
else:
return error_response(100, '修改已取消')


@eel.expose
def update_yuzu_path(folder: str):
from module.yuzu import update_yuzu_path
update_yuzu_path(folder)
return success_response(msg=f'修改 yuzu 目录至 {folder}')


@eel.expose
def detect_yuzu_version():
try:
Expand Down
5 changes: 5 additions & 0 deletions changelog.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## 0.2.6
- 新增试验性功能: Cloudflare 节点选优
- 修复 yuzu mod 文件夹路径获取错误的问题 (#19)
- 新增模拟器路径的历史记录 (#20)

## 0.2.5
- webview 版本增加运行前环境检测,并自动下载缺失的组件
- 替换不安全的 Unicode decode 方式
Expand Down
49 changes: 14 additions & 35 deletions config.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import json
import os
from dataclasses import dataclass
from typing import Optional, Dict
from typing import Optional, Dict, List
from pathlib import Path
from dataclasses_json import dataclass_json, Undefined
import logging
from logging.handlers import RotatingFileHandler
import sys


current_version = '0.2.5'
current_version = '0.2.6'
user_agent = f'ns-emu-tools/{current_version}'


Expand Down Expand Up @@ -42,7 +42,7 @@ def log_versions():
@dataclass_json
@dataclass
class YuzuConfig:
yuzu_path: Optional[str] = 'D:/Yuzu'
yuzu_path: Optional[str] = 'D:\\Yuzu'
yuzu_version: Optional[str] = None
yuzu_firmware: Optional[str] = None
branch: Optional[str] = 'ea'
Expand All @@ -51,7 +51,7 @@ class YuzuConfig:
@dataclass_json
@dataclass
class RyujinxConfig:
path: Optional[str] = 'D:/Ryujinx'
path: Optional[str] = 'D:\\Ryujinx'
version: Optional[str] = None
firmware: Optional[str] = None
branch: Optional[str] = 'ava'
Expand Down Expand Up @@ -80,12 +80,19 @@ class UiSetting:
dark: Optional[bool] = True


@dataclass_json
@dataclass
class CloudflareSpeedTestSetting:
override_hostnames: Optional[str] = 'nsarchive.e6ex.com,proxy.zyun.vip'


@dataclass_json(undefined=Undefined.EXCLUDE)
@dataclass
class CommonSetting:
ui: UiSetting = UiSetting()
network: NetworkSetting = NetworkSetting()
download: DownloadSetting = DownloadSetting()
cfst: CloudflareSpeedTestSetting = CloudflareSpeedTestSetting()


@dataclass_json(undefined=Undefined.EXCLUDE)
Expand All @@ -99,6 +106,8 @@ class Config:
if os.path.exists(config_path):
with open(config_path, 'r', encoding='utf-8') as f:
config = Config.from_dict(json.load(f))
config.yuzu.yuzu_path = str(Path(config.yuzu.yuzu_path).absolute())
config.ryujinx.path = str(Path(config.ryujinx.path).absolute())
if not config:
config = Config()

Expand All @@ -109,36 +118,6 @@ def dump_config():
f.write(config.to_json(ensure_ascii=False, indent=2))


def update_yuzu_path(new_yuzu_path: str):
new_path = Path(new_yuzu_path)
if not new_path.exists():
logger.info(f'create directory: {new_path}')
new_path.mkdir(parents=True, exist_ok=True)
if new_path.absolute() == Path(config.yuzu.yuzu_path).absolute():
logger.info(f'No different with old yuzu path, skip update.')
return
logger.info(f'setting yuzu path to {new_path}')
cfg = YuzuConfig()
cfg.yuzu_path = str(new_path.absolute())
config.yuzu = cfg
dump_config()


def update_ryujinx_path(new_ryujinx_path: str):
new_path = Path(new_ryujinx_path)
if not new_path.exists():
logger.info(f'create directory: {new_path}')
new_path.mkdir(parents=True, exist_ok=True)
if new_path.absolute() == Path(config.ryujinx.path).absolute():
logger.info(f'No different with old ryujinx path, skip update.')
return
logger.info(f'setting ryujinx path to {new_path}')
cfg = RyujinxConfig()
cfg.path = str(new_path.absolute())
config.ryujinx = cfg
dump_config()


def update_last_open_emu_page(page: str):
if page == 'ryujinx':
config.setting.ui.lastOpenEmuPage = 'ryujinx'
Expand All @@ -162,5 +141,5 @@ def update_setting(setting: Dict[str, object]):
dump_config()


__all__ = ['config', 'dump_config', 'update_yuzu_path', 'current_version', 'update_ryujinx_path',
__all__ = ['config', 'dump_config', 'YuzuConfig', 'current_version', 'RyujinxConfig', 'update_dark_state',
'update_last_open_emu_page', 'update_setting', 'user_agent']
132 changes: 132 additions & 0 deletions module/cfst.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
from typing import List
from config import config
from module.downloader import download
from utils.network import get_github_download_url
from module.msg_notifier import send_notify
from pathlib import Path
import logging
import subprocess


logger = logging.getLogger(__name__)


def download_cfst():
filepath = Path('download/CloudflareST_windows_amd64.zip')
if not filepath.exists():
logger.info('downloading CloudflareSpeedTest...')
send_notify('开始下载 CloudflareSpeedTest...')
url = get_github_download_url('https://github.com/XIU2/CloudflareSpeedTest/releases/download'
'/v2.1.0/CloudflareST_windows_amd64.zip')
info = download(url)
filepath = info.files[0].path
import zipfile
logger.info('unzip CloudflareSpeedTest...')
send_notify('正在解压 CloudflareSpeedTest...')
with zipfile.ZipFile(filepath, 'r') as zf:
zf.extractall('CloudflareSpeedTest')


def run_cfst():
exe_path = Path('CloudflareSpeedTest/CloudflareST.exe')
if not exe_path.exists():
logger.info('CloudflareSpeedTest not exist.')
send_notify('CloudflareSpeedTest not exist.')
raise RuntimeError('CloudflareSpeedTest not exist.')
logger.info('starting CloudflareSpeedTest...')
send_notify('正在运行 CloudflareSpeedTest...')
p = subprocess.Popen(['CloudflareSpeedTest/CloudflareST.exe', '-p', '0', '-url',
'https://cloudflaremirrors.com/archlinux/images/latest/Arch-Linux-x86_64-basic.qcow2'],
cwd='./CloudflareSpeedTest',
creationflags=subprocess.CREATE_NEW_CONSOLE)
p.wait()


def get_fastest_ip_from_result():
result_path = Path('CloudflareSpeedTest/result.csv')
if not result_path.exists():
logger.info('CloudflareSpeedTest result not exist.')
send_notify('未能检测到 CloudflareSpeedTest 结果, 请先运行一次测试.')
raise RuntimeError('未能检测到 CloudflareSpeedTest 结果, 请先运行一次测试.')
with open(result_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
if len(lines) < 2:
logger.info('Fail to parse CloudflareSpeedTest result.')
send_notify('无法解析 CloudflareSpeedTest 结果, 请先运行一次测试.')
raise RuntimeError('无法解析 CloudflareSpeedTest 结果, 请先运行一次测试.')
ip = lines[1].split(',', 1)[0]
logger.info(f'fastest ip from result: {ip}')
return ip


def show_result():
result_path = Path('CloudflareSpeedTest/result.csv')
if not result_path.exists():
logger.info('CloudflareSpeedTest result not exist.')
send_notify('未能检测到 CloudflareSpeedTest 结果, 请先运行一次测试.')
raise RuntimeError('未能检测到 CloudflareSpeedTest 结果, 请先运行一次测试.')
with open(result_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
send_notify('===============测速结果===============')
for line in lines:
send_notify(line)


def get_override_host_names():
return [s.strip() for s in config.setting.cfst.override_hostnames.split(',')]


def install_ip_to_hosts(ip: str, host_names: List[str]):
logger.info('writing hosts...')
send_notify('正在更新 hosts 文件...')
try:
from module.hosts import Hosts, HostsEntry
hosts = Hosts()
new_entry = HostsEntry(entry_type='ipv4', address=ip, names=host_names)
logger.info(f'new_entry: {new_entry}')
send_notify(f'使用 ip: {ip}')
hosts.add([new_entry], force=True)
hosts.write()
subprocess.Popen(['ipconfig', '/flushdns'], stdout=subprocess.DEVNULL).wait()
logger.info(f'updated hosts: {hosts}')
send_notify('hosts 文件更新完成, 请重启程序使修改生效.')
except Exception as e:
logger.error(f'fail in update hosts, exception: {str(e)}')
send_notify('hosts 文件更新失败, 请使用管理员权限重新启动程序.')


def optimize_cloudflare_hosts():
exe_path = Path('CloudflareSpeedTest/CloudflareST.exe')
if not exe_path.exists():
download_cfst()
run_cfst()
show_result()
fastest_ip = get_fastest_ip_from_result()
host_names = get_override_host_names()
if not host_names:
host_names = ['nsarchive.e6ex.com']
install_ip_to_hosts(fastest_ip, host_names)


def remove_cloudflare_hosts():
try:
logger.info('removing ip from hosts...')
send_notify('正在删除 hosts 文件中的相关配置...')
from module.hosts import Hosts, HostsEntry
hosts = Hosts()
host_names = get_override_host_names()
for hn in host_names:
hosts.remove_all_matching(name=hn)
hosts.write()
subprocess.Popen(['ipconfig', '/flushdns'], stdout=subprocess.DEVNULL).wait()
logger.info(f'updated hosts: {hosts}')
send_notify('hosts 文件更新完成, 请重启程序使修改生效.')
except Exception as e:
logger.error(f'fail in update hosts, exception: {str(e)}')
send_notify('hosts 文件更新失败, 请使用管理员权限重新启动程序.')


if __name__ == '__main__':
# optimize_cloudflare_hosts()
remove_cloudflare_hosts()
install_ip_to_hosts(get_fastest_ip_from_result(), get_override_host_names())
Loading

0 comments on commit 36b5796

Please sign in to comment.