优化离线包体积

This commit is contained in:
user123456
2025-06-18 14:55:35 +08:00
parent 29ceeef45b
commit 252dc319c6
2 changed files with 126 additions and 18 deletions

View File

@@ -171,8 +171,9 @@ func NewImageStreamer(config *ImageStreamerConfig) *ImageStreamer {
// StreamOptions 下载选项
type StreamOptions struct {
Platform string
Compression bool
Platform string
Compression bool
UseCompressedLayers bool // 是否保存原始压缩层默认true
}
// StreamImageToWriter 流式下载镜像到Writer
@@ -336,12 +337,24 @@ func (is *ImageStreamer) streamDockerFormatWithReturn(ctx context.Context, tarWr
return err
}
uncompressedSize, err := partial.UncompressedSize(layer)
if err != nil {
return err
var layerSize int64
var layerReader io.ReadCloser
// 根据配置选择使用压缩层或未压缩层
if options != nil && options.UseCompressedLayers {
layerSize, err = layer.Size()
if err != nil {
return err
}
layerReader, err = layer.Compressed()
} else {
layerSize, err = partial.UncompressedSize(layer)
if err != nil {
return err
}
layerReader, err = layer.Uncompressed()
}
layerReader, err := layer.Uncompressed()
if err != nil {
return err
}
@@ -349,7 +362,7 @@ func (is *ImageStreamer) streamDockerFormatWithReturn(ctx context.Context, tarWr
layerTarHeader := &tar.Header{
Name: layerDir + "/layer.tar",
Size: uncompressedSize,
Size: layerSize,
Mode: 0644,
}
@@ -628,6 +641,7 @@ func handleDirectImageDownload(c *gin.Context) {
imageRef := strings.ReplaceAll(imageParam, "_", "/")
platform := c.Query("platform")
tag := c.DefaultQuery("tag", "")
useCompressed := c.DefaultQuery("compressed", "true") == "true"
if tag != "" && !strings.Contains(imageRef, ":") && !strings.Contains(imageRef, "@") {
imageRef = imageRef + ":" + tag
@@ -653,8 +667,9 @@ func handleDirectImageDownload(c *gin.Context) {
}
options := &StreamOptions{
Platform: platform,
Compression: false,
Platform: platform,
Compression: false,
UseCompressedLayers: useCompressed,
}
ctx := c.Request.Context()
@@ -670,8 +685,9 @@ func handleDirectImageDownload(c *gin.Context) {
// handleSimpleBatchDownload 处理批量下载
func handleSimpleBatchDownload(c *gin.Context) {
var req struct {
Images []string `json:"images" binding:"required"`
Platform string `json:"platform"`
Images []string `json:"images" binding:"required"`
Platform string `json:"platform"`
UseCompressedLayers *bool `json:"useCompressedLayers"`
}
if err := c.ShouldBindJSON(&req); err != nil {
@@ -710,9 +726,15 @@ func handleSimpleBatchDownload(c *gin.Context) {
return
}
useCompressed := true // 默认启用原始压缩层
if req.UseCompressedLayers != nil {
useCompressed = *req.UseCompressedLayers
}
options := &StreamOptions{
Platform: req.Platform,
Compression: false,
Platform: req.Platform,
Compression: false,
UseCompressedLayers: useCompressed,
}
ctx := c.Request.Context()

View File

@@ -399,6 +399,67 @@
100% { transform: rotate(360deg); }
}
/* 切换开关样式 */
.switch-container {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1.5rem;
}
.switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
}
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--muted);
transition: 0.2s;
border-radius: 24px;
border: 1px solid var(--border);
}
.slider:before {
position: absolute;
content: "";
height: 18px;
width: 18px;
left: 2px;
bottom: 2px;
background-color: white;
transition: 0.2s;
border-radius: 50%;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
input:checked + .slider {
background-color: var(--primary);
}
input:checked + .slider:before {
transform: translateX(26px);
}
.switch-label {
font-weight: 500;
color: var(--foreground);
cursor: pointer;
}
.hidden {
display: none;
}
@@ -559,6 +620,14 @@
</div>
</div>
<div class="switch-container">
<label class="switch">
<input type="checkbox" id="compressedToggle" checked>
<span class="slider"></span>
</label>
<label for="compressedToggle" class="switch-label">使用压缩层(减小包体积)</label>
</div>
<button type="submit" class="btn btn-primary btn-full" id="downloadBtn">
<span id="downloadText">立即下载</span>
<span id="downloadLoading" class="loading hidden"></span>
@@ -595,6 +664,14 @@
</div>
</div>
<div class="switch-container">
<label class="switch">
<input type="checkbox" id="batchCompressedToggle" checked>
<span class="slider"></span>
</label>
<label for="batchCompressedToggle" class="switch-label">使用压缩层(减小包体积)</label>
</div>
<button type="submit" class="btn btn-primary btn-full" id="batchDownloadBtn">
<span id="batchDownloadText">开始下载</span>
<span id="batchDownloadLoading" class="loading hidden"></span>
@@ -651,12 +728,18 @@
}
}
function buildDownloadUrl(imageName, platform = '') {
function buildDownloadUrl(imageName, platform = '', useCompressed = true) {
const encodedImage = imageName.replace(/\//g, '_');
let url = `/api/image/download/${encodedImage}`;
const params = new URLSearchParams();
if (platform && platform.trim()) {
url += `?platform=${encodeURIComponent(platform.trim())}`;
params.append('platform', platform.trim());
}
params.append('compressed', useCompressed.toString());
if (params.toString()) {
url += '?' + params.toString();
}
return url;
@@ -672,11 +755,12 @@
}
const platform = document.getElementById('platformInput').value.trim();
const useCompressed = document.getElementById('compressedToggle').checked;
hideStatus('singleStatus');
setButtonLoading('downloadBtn', 'downloadText', 'downloadLoading', true);
const downloadUrl = buildDownloadUrl(imageName, platform);
const downloadUrl = buildDownloadUrl(imageName, platform, useCompressed);
const link = document.createElement('a');
link.href = downloadUrl;
@@ -711,9 +795,11 @@
}
const platform = document.getElementById('batchPlatformInput').value.trim();
const useCompressed = document.getElementById('batchCompressedToggle').checked;
const options = {
images: images
images: images,
useCompressedLayers: useCompressed
};
if (platform) {