gongxiangp2/lib/chunk-upload-config.ts
chenpei 4e89b57798 feat(upload): optimize upload UI and performance
- Expand batch upload list area and optimize preview image layout
- Improve upload speed tracking and display (server-side & client-side)
- Reduce network detection log noise
- Optimize Docker build process (caching, env validation)
- Add shadow environment deployment support
2026-01-28 15:07:50 +08:00

183 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 分片上传配置
* 统一使用50MB大分片,提升上传效率
*
* 策略:
* - 统一使用50MB分片(内网公网一致)
* - 请求数减少80%(1GB文件从100个减少到20个)
* - TCP利用率更高(单个分片传输时间更长)
*
* 优势:
* - 减少网络开销(请求数少)
* - 提升传输效率(TCP慢启动影响更小)
* - 降低服务器压力(并发处理更少)
*/
import { getNetworkStatus, initializeNetwork } from './network'
/**
* 获取最优分片大小(统一50MB)
* @returns 分片大小(字节)
*/
export async function getOptimalChunkSize(): Promise<number> {
// 统一使用50MB分片(内网公网一致)
// 优势:
// 1. 减少请求数(1GB文件从100个减少到20个)
// 2. TCP利用率更高(单个分片传输时间更长)
// 3. 降低网络开销
const chunkSize = 50 * 1024 * 1024 // 50MB
console.log(`[ChunkConfig] 使用 50MB 分片(统一配置)`)
return chunkSize
}
/**
* 同步获取分片大小(统一50MB)
* @returns 分片大小(字节)
*/
export function getChunkSizeSync(): number {
const chunkSize = 50 * 1024 * 1024 // 50MB
console.log(`[ChunkConfig] 使用 50MB 分片(同步)`)
return chunkSize
}
/**
* 获取超时时间(根据分片大小动态调整)
* 假设最低速度 300KB/s,加上100%缓冲(更保守)
* @param chunkSize 分片大小(字节)
* @returns 超时时间(毫秒)
*/
export function getChunkTimeout(chunkSize: number): number {
const minSpeed = 300 * 1024 // 300KB/s(更保守的最低速度)
const baseTimeout = (chunkSize / minSpeed) * 1000
// 加上100%缓冲,确保不会轻易超时
const timeout = Math.ceil(baseTimeout * 2)
// 最小5分钟,最大10分钟(50MB分片在300KB/s下需要约5.5分钟)
return Math.max(300000, Math.min(600000, timeout))
}
/**
* 获取分片大小的可读字符串
* @param chunkSize 分片大小(字节)
* @returns 可读字符串(如 "10MB")
*/
export function formatChunkSize(chunkSize: number): string {
return `${(chunkSize / 1024 / 1024).toFixed(0)}MB`
}
/**
* 获取最优并发数(根据网络环境和系统负载动态调整)
*
* 动态调整策略(1~3并发):
* - 内网用户:2-3并发
* - 公网用户:2并发
* - 原因:现在已配置 proxyClientMaxBodySize = 100MB,可以处理 50MB 分片
*
* @returns 并发数(1-3)
*/
export async function getOptimalConcurrency(): Promise<number> {
// 获取当前网络状态
let network = getNetworkStatus()
// 如果还没检测过,先初始化网络检测
if (!network.lastChecked) {
try {
network = await initializeNetwork()
} catch (error) {
console.warn('[ChunkConfig] 网络检测失败,使用默认并发数(2):', error)
return 2
}
}
// 基础并发数
let concurrency: number
if (network.isInternal) {
// 内网用户:3并发
concurrency = 3
} else {
// 公网用户:2并发
concurrency = 2
}
// 确保在1-3范围内
concurrency = Math.max(1, Math.min(3, concurrency))
console.log(`[ChunkConfig] 检测到${network.isInternal ? '内网' : '公网'}访问,使用 ${concurrency} 个并发(1~3范围)`)
return concurrency
}
/**
* 同步获取并发数(如果网络状态已缓存)
* 如果未检测过,返回默认值(2并发)
* @returns 并发数(1-3)
*/
export function getConcurrencySync(): number {
const network = getNetworkStatus()
// 如果还没检测过,返回保守值(2并发)
if (!network.lastChecked) {
console.warn('[ChunkConfig] 网络状态未检测,使用默认并发数(2)')
return 2
}
// 同步版本:使用固定策略(不依赖异步检测)
let concurrency: number
if (network.isInternal) {
concurrency = 3 // 内网:3并发
} else {
concurrency = 2 // 公网:2并发
}
// 确保在1-3范围内
concurrency = Math.max(1, Math.min(3, concurrency))
return concurrency
}
/**
* 根据实际上传速度动态调整并发数
*
* 调整策略:
* - 速度 > 5MB/s:降低并发(避免浪费资源)
* - 速度 2-5MB/s:保持当前并发
* - 速度 < 2MB/s:增加并发(最高3)
*
* @param currentConcurrency 当前并发数
* @param currentSpeed 当前上传速度(字节/秒)
* @returns 调整后的并发数(1-3)
*/
export function adjustConcurrencyBySpeed(currentConcurrency: number, currentSpeed: number): number {
const speedMBps = currentSpeed / (1024 * 1024)
let newConcurrency = currentConcurrency
if (speedMBps > 5) {
// 速度很快,降低并发(节省资源)
newConcurrency = Math.max(1, currentConcurrency - 1)
} else if (speedMBps < 2 && currentConcurrency < 3) {
// 速度慢,增加并发(最多3,避免服务器过载)
newConcurrency = Math.min(3, currentConcurrency + 1)
}
if (newConcurrency !== currentConcurrency) {
console.log(`[ChunkConfig] 动态调整并发: ${currentConcurrency} → ${newConcurrency} (当前速度: ${speedMBps.toFixed(2)}MB/s)`)
}
return newConcurrency
}
/**
* 获取并发数的可读字符串
* @param concurrency 并发数
* @returns 可读字符串(如 "2个并发")
*/
export function formatConcurrency(concurrency: number): string {
return `${concurrency}个并发`
}