mirror of
https://git.sanhost.net/sanasol/hytale-f2p
synced 2026-02-26 12:51:47 -03:00
Fixed binary file corruption when downloading through proxy by using PassThrough stream to preserve data integrity while tracking download progress.
103 lines
2.8 KiB
JavaScript
103 lines
2.8 KiB
JavaScript
const crypto = require('crypto');
|
|
const axios = require('axios');
|
|
const https = require('https');
|
|
const { PassThrough } = require('stream');
|
|
|
|
const PROXY_URL = process.env.HF2P_PROXY_URL || 'your_proxy_url_here';
|
|
const SECRET_KEY = process.env.HF2P_SECRET_KEY || 'your_secret_key_here_for_jwt';
|
|
|
|
function generateToken() {
|
|
const timestamp = Date.now().toString();
|
|
const hash = crypto
|
|
.createHmac('sha256', SECRET_KEY)
|
|
.update(timestamp)
|
|
.digest('hex');
|
|
return `${timestamp}:${hash}`;
|
|
}
|
|
|
|
async function proxyRequest(url, options = {}) {
|
|
const token = generateToken();
|
|
const urlObj = new URL(url);
|
|
const targetUrl = `${urlObj.protocol}//${urlObj.host}`;
|
|
|
|
const config = {
|
|
method: options.method || 'GET',
|
|
url: `${PROXY_URL}/proxy${urlObj.pathname}${urlObj.search}`,
|
|
headers: {
|
|
'X-Auth-Token': token,
|
|
'X-Target-URL': targetUrl,
|
|
...(options.headers || {})
|
|
},
|
|
timeout: options.timeout || 30000,
|
|
responseType: options.responseType
|
|
};
|
|
|
|
return axios(config);
|
|
}
|
|
|
|
function getProxyDownloadStream(url, onData) {
|
|
return new Promise((resolve, reject) => {
|
|
const token = generateToken();
|
|
const urlObj = new URL(url);
|
|
const targetUrl = `${urlObj.protocol}//${urlObj.host}`;
|
|
|
|
const proxyUrl = new URL(PROXY_URL);
|
|
const requestPath = `/proxy${urlObj.pathname}${urlObj.search}`;
|
|
|
|
const options = {
|
|
hostname: proxyUrl.hostname,
|
|
port: proxyUrl.port || (proxyUrl.protocol === 'https:' ? 443 : 80),
|
|
path: requestPath,
|
|
method: 'GET',
|
|
headers: {
|
|
'X-Auth-Token': token,
|
|
'X-Target-URL': targetUrl
|
|
}
|
|
};
|
|
|
|
const protocol = proxyUrl.protocol === 'https:' ? https : require('http');
|
|
|
|
const handleResponse = (response) => {
|
|
if (response.statusCode === 302 || response.statusCode === 301) {
|
|
const redirectUrl = response.headers.location;
|
|
if (redirectUrl.startsWith('http')) {
|
|
getProxyDownloadStream(redirectUrl, onData).then(resolve).catch(reject);
|
|
} else {
|
|
reject(new Error(`Invalid redirect: ${redirectUrl}`));
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (response.statusCode !== 200) {
|
|
reject(new Error(`HTTP ${response.statusCode}`));
|
|
return;
|
|
}
|
|
|
|
if (onData) {
|
|
const totalSize = parseInt(response.headers['content-length'], 10);
|
|
let downloaded = 0;
|
|
|
|
const passThrough = new PassThrough();
|
|
|
|
response.on('data', (chunk) => {
|
|
downloaded += chunk.length;
|
|
onData(chunk, downloaded, totalSize);
|
|
});
|
|
|
|
response.pipe(passThrough);
|
|
resolve(passThrough);
|
|
} else {
|
|
resolve(response);
|
|
}
|
|
};
|
|
|
|
protocol.get(options, handleResponse).on('error', reject);
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
proxyRequest,
|
|
getProxyDownloadStream,
|
|
generateToken
|
|
};
|