mirror of
https://github.com/LorenEteval/Furious.git
synced 2026-10-01 19:38:07 +03:00
215 lines
6.8 KiB
Python
215 lines
6.8 KiB
Python
# Copyright (C) 2024–present Loren Eteval & contributors <loren.eteval@proton.me>
|
||
#
|
||
# This file is part of Furious.
|
||
#
|
||
# This program is free software: you can redistribute it and/or modify
|
||
# it under the terms of the GNU General Public License as published by
|
||
# the Free Software Foundation, either version 3 of the License, or
|
||
# (at your option) any later version.
|
||
#
|
||
# This program is distributed in the hope that it will be useful,
|
||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
# GNU General Public License for more details.
|
||
#
|
||
# You should have received a copy of the GNU General Public License
|
||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||
|
||
from __future__ import annotations
|
||
|
||
from Furious.QtFramework.QtNetwork import *
|
||
from Furious.QtFramework.QtWidgets import *
|
||
from Furious.QtFramework.DynamicTranslate import gettext as _
|
||
from Furious.QtFramework.WebGETManager import *
|
||
from Furious.Utility import *
|
||
from Furious.Library import *
|
||
|
||
from PySide6 import QtCore
|
||
from PySide6.QtGui import *
|
||
from PySide6.QtNetwork import *
|
||
|
||
from typing import AnyStr, Union, Callable
|
||
|
||
import os
|
||
import logging
|
||
import hashlib
|
||
import functools
|
||
|
||
__all__ = ['XrayAssetDownloadManager']
|
||
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
class SHA256Worker(QtCore.QObject, QtCore.QRunnable):
|
||
finished = QtCore.Signal(str)
|
||
|
||
def __init__(self, string=b''):
|
||
# Explictly called __init__
|
||
QtCore.QObject.__init__(self)
|
||
QtCore.QRunnable.__init__(self)
|
||
|
||
self.string = string
|
||
|
||
def run(self):
|
||
self.finished.emit(hashlib.sha256(self.string).hexdigest())
|
||
|
||
|
||
class XrayAssetSHA256DownloadManager(WebGETManager):
|
||
def __init__(self, parent=None, **kwargs):
|
||
actionMessage = kwargs.pop('actionMessage', 'download sha256')
|
||
|
||
super().__init__(parent, actionMessage=actionMessage)
|
||
|
||
@staticmethod
|
||
def fileContent(filepath, mode='rb') -> AnyStr:
|
||
try:
|
||
with open(filepath, mode) as file:
|
||
return file.read()
|
||
except Exception:
|
||
# Any non-exit exceptions
|
||
|
||
return b''
|
||
|
||
def successCallback(self, networkReply, **kwargs):
|
||
filepath = kwargs.pop('filepath', '')
|
||
downloadCallback = kwargs.pop('downloadCallback', None)
|
||
|
||
data = networkReply.readAll().data()
|
||
|
||
if isinstance(data, bytes):
|
||
datastr = data.decode('utf-8', 'replace')
|
||
else:
|
||
datastr = str(data)
|
||
|
||
logger.debug(f'data: {data}')
|
||
|
||
# 6068a73edfa08b63080b8d362bd4c5b069689a3548f413f43cfa58227a201571 geosite.dat
|
||
# 3a12beaa33c81b6751b45833a0a942b9462420d91182e7fa1d768b418e604049 geoip.dat
|
||
value = datastr.split()[0]
|
||
|
||
basename = os.path.basename(filepath)
|
||
|
||
def handleFinished(_digest, _value=''):
|
||
logger.debug(
|
||
f'computed digest is \'{_digest}\' while repo digest is \'{_value}\''
|
||
)
|
||
|
||
if _digest != _value:
|
||
logger.info(f'digest not equal for {basename}. Start downloading asset')
|
||
|
||
if callable(downloadCallback):
|
||
downloadCallback()
|
||
else:
|
||
logger.info(f'digest equal for {basename}. Nothing to do')
|
||
|
||
worker = SHA256Worker(self.fileContent(filepath))
|
||
|
||
worker.setAutoDelete(True)
|
||
worker.finished.connect(functools.partial(handleFinished, _value=value))
|
||
|
||
AppThreadPool().start(worker)
|
||
|
||
def download(self, url, filepath, downloadCallback: Callable[[], None]):
|
||
self.webGET(
|
||
url,
|
||
filepath=str(filepath),
|
||
downloadCallback=downloadCallback,
|
||
)
|
||
|
||
|
||
class XrayAssetAssetsDownloadManager(WebGETManager):
|
||
def __init__(self, parent=None, **kwargs):
|
||
actionMessage = kwargs.pop('actionMessage', 'download assets')
|
||
|
||
super().__init__(parent, actionMessage=actionMessage)
|
||
|
||
def successCallback(self, networkReply, **kwargs):
|
||
filepath = kwargs.pop('filepath', '')
|
||
|
||
saveFile = QtCore.QSaveFile(filepath)
|
||
|
||
data = networkReply.readAll().data()
|
||
|
||
if not saveFile.open(QtCore.QSaveFile.OpenModeFlag.WriteOnly):
|
||
logger.error(
|
||
f'failed to open \'{filepath}\' for writing. {saveFile.errorString()}'
|
||
)
|
||
else:
|
||
saveFile.write(data)
|
||
|
||
if not saveFile.commit():
|
||
logger.error(
|
||
f'save file to \'{filepath}\' failed. {saveFile.errorString()}'
|
||
)
|
||
else:
|
||
logger.info(f'save file to \'{filepath}\' success')
|
||
|
||
def download(self, url, filepath):
|
||
self.webGET(url, filepath=str(filepath))
|
||
|
||
|
||
class XrayAssetPairDownloadHelper:
|
||
def __init__(self, *args, **kwargs):
|
||
sha256ActionMessage = kwargs.pop('sha256ActionMessage', 'download sha256')
|
||
assetsActionMessage = kwargs.pop('assetsActionMessage', 'download assets')
|
||
|
||
super().__init__(*args, **kwargs)
|
||
|
||
self.sha256Downloader = XrayAssetSHA256DownloadManager(
|
||
actionMessage=sha256ActionMessage
|
||
)
|
||
self.assetsDownloader = XrayAssetAssetsDownloadManager(
|
||
actionMessage=assetsActionMessage
|
||
)
|
||
|
||
def configureHttpProxy(self, httpProxy: Union[str, None]) -> bool:
|
||
return all(
|
||
[
|
||
self.sha256Downloader.configureHttpProxy(httpProxy),
|
||
self.assetsDownloader.configureHttpProxy(httpProxy),
|
||
]
|
||
)
|
||
|
||
def download(self, sha256URL, assetsURL, filepath):
|
||
self.sha256Downloader.download(
|
||
url=sha256URL,
|
||
filepath=filepath,
|
||
downloadCallback=functools.partial(
|
||
self.assetsDownloader.download, assetsURL, filepath
|
||
),
|
||
)
|
||
|
||
|
||
class XrayAssetDownloadManager:
|
||
def __init__(self, *args, **kwargs):
|
||
super().__init__(*args, **kwargs)
|
||
|
||
self.downloadHelperGeosite = XrayAssetPairDownloadHelper(
|
||
sha256ActionMessage='download geosite sha256',
|
||
assetsActionMessage='download geosite assets',
|
||
)
|
||
self.downloadHelperGeoip = XrayAssetPairDownloadHelper(
|
||
sha256ActionMessage='download geoip sha256',
|
||
assetsActionMessage='download geoip assets',
|
||
)
|
||
|
||
def configureHttpProxy(self, httpProxy: Union[str, None]) -> bool:
|
||
return all(
|
||
[
|
||
self.downloadHelperGeosite.configureHttpProxy(httpProxy),
|
||
self.downloadHelperGeoip.configureHttpProxy(httpProxy),
|
||
]
|
||
)
|
||
|
||
def download(self):
|
||
self.downloadHelperGeosite.download(
|
||
sha256URL=URL_GEOSITE_SHA256,
|
||
assetsURL=URL_GEOSITE,
|
||
filepath=XRAY_ASSET_PATH_GEOSITE,
|
||
)
|
||
self.downloadHelperGeoip.download(
|
||
sha256URL=URL_GEOIP_SHA256,
|
||
assetsURL=URL_GEOIP,
|
||
filepath=XRAY_ASSET_PATH_GEOIP,
|
||
)
|