mirror of
https://github.com/YuzuZensai/Termix.git
synced 2026-09-13 18:58:52 +00:00
194 lines
4.7 KiB
TypeScript
194 lines
4.7 KiB
TypeScript
import type { TransferPlatform } from "./transfer-paths.js";
|
||||
|
|
|
|||
|
|
export type TransferMethodPreference = "auto" | "tar" | "item_sftp";
|
|||
|
|
|
|||
|
|
export interface TransferScanSummary {
|
|||
|
|
fileCount: number;
|
|||
|
|
totalBytes: number;
|
|||
|
|
largestFileBytes: number;
|
|||
|
|
/** Share of total bytes in likely incompressible file types (0–1). */
|
|||
|
|
incompressibleRatio: number;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const INCOMPRESSIBLE_EXT =
|
|||
|
|
/\.(zip|gz|bz2|xz|7z|rar|tar|tgz|jpg|jpeg|png|gif|webp|mp3|mp4|mkv|avi|mov|wmv|iso|dmg|deb|rpm|pdf|db|sqlite|wasm|vmdk|qcow2)$/i;
|
|||
|
|
|
|||
|
|
const GB = 1024 * 1024 * 1024;
|
|||
|
|
const MB = 1024 * 1024;
|
|||
|
|
|
|||
|
|
export function isLikelyIncompressiblePath(path: string): boolean {
|
|||
|
|
return INCOMPRESSIBLE_EXT.test(path);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export function buildTransferScanSummary(
|
|||
|
|
items: Array<{ sourcePath: string; size: number }>,
|
|||
|
|
): TransferScanSummary {
|
|||
|
|
let totalBytes = 0;
|
|||
|
|
let largestFileBytes = 0;
|
|||
|
|
let incompressibleBytes = 0;
|
|||
|
|
|
|||
|
|
for (const item of items) {
|
|||
|
|
totalBytes += item.size;
|
|||
|
|
largestFileBytes = Math.max(largestFileBytes, item.size);
|
|||
|
|
if (isLikelyIncompressiblePath(item.sourcePath)) {
|
|||
|
|
incompressibleBytes += item.size;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
fileCount: items.length,
|
|||
|
|
totalBytes,
|
|||
|
|
largestFileBytes,
|
|||
|
|
incompressibleRatio: totalBytes > 0 ? incompressibleBytes / totalBytes : 0,
|
|||
|
|
};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Choose tar vs per-item SFTP for directory / multi-file transfers.
|
|||
|
|
* Single-file stream transfers bypass this entirely.
|
|||
|
|
*/
|
|||
|
|
export function resolveArchiveTransferMethod(
|
|||
|
|
preference: TransferMethodPreference,
|
|||
|
|
summary: TransferScanSummary,
|
|||
|
|
sourcePlatform: TransferPlatform,
|
|||
|
|
destPlatform: TransferPlatform,
|
|||
|
|
sourceHasTar: boolean,
|
|||
|
|
destHasTar: boolean,
|
|||
|
|
): "tar" | "item_sftp" {
|
|||
|
|
if (sourcePlatform === "windows" || destPlatform === "windows") {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (preference === "item_sftp") {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (preference === "tar") {
|
|||
|
|
return sourceHasTar && destHasTar ? "tar" : "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// auto
|
|||
|
|
if (!sourceHasTar || !destHasTar) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const { fileCount, totalBytes, largestFileBytes, incompressibleRatio } =
|
|||
|
|
summary;
|
|||
|
|
|
|||
|
|
if (fileCount === 0) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount === 1 && largestFileBytes >= 2 * GB) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Multi-item sets with a large file: tar only when data is likely compressible
|
|||
|
|
// (mostly video/zip → per-file SFTP is simpler and avoids pack/unpack time).
|
|||
|
|
if (
|
|||
|
|
fileCount > 1 &&
|
|||
|
|
largestFileBytes >= 2 * GB &&
|
|||
|
|
totalBytes >= 500 * MB &&
|
|||
|
|
incompressibleRatio < 0.7
|
|||
|
|
) {
|
|||
|
|
return "tar";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount === 1 && largestFileBytes >= 5 * GB) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (totalBytes >= 10 * GB && incompressibleRatio >= 0.5) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (incompressibleRatio >= 0.85) {
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount >= 100) {
|
|||
|
|
return "tar";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount >= 20 && totalBytes >= 50 * MB && incompressibleRatio < 0.5) {
|
|||
|
|
return "tar";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount > 5 && incompressibleRatio < 0.7) {
|
|||
|
|
return "tar";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return "item_sftp";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export type ArchiveTransferReasonKey =
|
|||
|
|
| "user_item_sftp"
|
|||
|
|
| "user_tar"
|
|||
|
|
| "tar_unavailable"
|
|||
|
|
| "windows_host"
|
|||
|
|
| "auto_multi_large"
|
|||
|
|
| "auto_single_large_in_archive"
|
|||
|
|
| "auto_many_incompressible"
|
|||
|
|
| "auto_many_files"
|
|||
|
|
| "auto_default";
|
|||
|
|
|
|||
|
|
/** i18n key suffix under transfer.methodReason.* */
|
|||
|
|
export function getArchiveTransferReasonKey(
|
|||
|
|
preference: TransferMethodPreference,
|
|||
|
|
resolvedMethod: "tar" | "item_sftp",
|
|||
|
|
summary: TransferScanSummary,
|
|||
|
|
sourcePlatform: TransferPlatform,
|
|||
|
|
destPlatform: TransferPlatform,
|
|||
|
|
sourceHasTar: boolean,
|
|||
|
|
destHasTar: boolean,
|
|||
|
|
): ArchiveTransferReasonKey {
|
|||
|
|
if (preference === "item_sftp") return "user_item_sftp";
|
|||
|
|
if (preference === "tar") {
|
|||
|
|
return sourceHasTar && destHasTar ? "user_tar" : "tar_unavailable";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (sourcePlatform === "windows" || destPlatform === "windows") {
|
|||
|
|
return "windows_host";
|
|||
|
|
}
|
|||
|
|
if (!sourceHasTar || !destHasTar) {
|
|||
|
|
return "tar_unavailable";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
const { fileCount, totalBytes, largestFileBytes, incompressibleRatio } =
|
|||
|
|
summary;
|
|||
|
|
|
|||
|
|
if (
|
|||
|
|
fileCount > 1 &&
|
|||
|
|
largestFileBytes >= 2 * GB &&
|
|||
|
|
totalBytes >= 500 * MB &&
|
|||
|
|
incompressibleRatio < 0.7
|
|||
|
|
) {
|
|||
|
|
return "auto_multi_large";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (fileCount === 1 && largestFileBytes >= 2 * GB) {
|
|||
|
|
return "auto_single_large_in_archive";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (totalBytes >= 10 * GB && incompressibleRatio >= 0.5) {
|
|||
|
|
return "auto_many_incompressible";
|
|||
|
|
}
|
|||
|
|
if (incompressibleRatio >= 0.85) {
|
|||
|
|
return "auto_many_incompressible";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (
|
|||
|
|
fileCount >= 100 ||
|
|||
|
|
(fileCount >= 20 && totalBytes >= 50 * MB && incompressibleRatio < 0.5) ||
|
|||
|
|
(fileCount > 5 && incompressibleRatio < 0.7)
|
|||
|
|
) {
|
|||
|
|
return "auto_many_files";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (resolvedMethod === "tar") {
|
|||
|
|
return "auto_many_files";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return "auto_default";
|
|||
|
|
}
|