Backend: - Add registry_address configuration API (GET/POST) - Add tar image upload with OCI and Docker format support - Add image download with streaming optimization - Fix blob download using c.Send (Fiber v3 SendStream bug) - Add registry_address prefix stripping for all OCI v2 endpoints - Add AGENTS.md for project documentation Frontend: - Add settings store with Snackbar notifications - Add image upload dialog with progress bar - Add download state tracking with multi-stage feedback - Replace alert() with MUI Snackbar messages - Display image names without registry_address prefix 🤖 Generated with [Qoder](https://qoder.com)
85 lines
2.5 KiB
Go
85 lines
2.5 KiB
Go
package registry
|
|
|
|
import (
|
|
"context"
|
|
|
|
"gitea.loveuer.com/loveuer/cluster/internal/model"
|
|
"gitea.loveuer.com/loveuer/cluster/pkg/resp"
|
|
"gitea.loveuer.com/loveuer/cluster/pkg/store"
|
|
"github.com/gofiber/fiber/v3"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
// RegistryImageList returns the list of images/repositories
|
|
func RegistryImageList(ctx context.Context, db *gorm.DB, store store.Store) fiber.Handler {
|
|
return func(c fiber.Ctx) error {
|
|
// Get current registry_address setting
|
|
var registryConfig model.RegistryConfig
|
|
registryAddress := ""
|
|
if err := db.Where("key = ?", "registry_address").First(®istryConfig).Error; err == nil {
|
|
registryAddress = registryConfig.Value
|
|
}
|
|
if registryAddress == "" {
|
|
registryAddress = "localhost:9119"
|
|
}
|
|
|
|
var repositories []model.Repository
|
|
|
|
// Query all repositories from the database
|
|
if err := db.Find(&repositories).Error; err != nil {
|
|
return resp.R500(c, "", nil, err)
|
|
}
|
|
|
|
// Convert to the expected format for the frontend
|
|
var result []map[string]interface{}
|
|
for _, repo := range repositories {
|
|
// Get all tags for this repository
|
|
var tags []model.Tag
|
|
if err := db.Where("repository = ?", repo.Name).Find(&tags).Error; err != nil {
|
|
continue // Skip this repository if we can't get tags
|
|
}
|
|
|
|
// If no tags, skip this repository
|
|
if len(tags) == 0 {
|
|
continue
|
|
}
|
|
|
|
// Calculate total size of all blobs for this repository
|
|
var totalSize int64
|
|
var sizeResult struct {
|
|
Total int64
|
|
}
|
|
err := db.Model(&model.Blob{}).
|
|
Where("repository = ?", repo.Name).
|
|
Select("COALESCE(SUM(size), 0) as total").
|
|
Scan(&sizeResult).Error
|
|
if err == nil {
|
|
totalSize = sizeResult.Total
|
|
}
|
|
|
|
// Format updated_at to second precision
|
|
uploadTime := repo.UpdatedAt.Format("2006-01-02 15:04:05")
|
|
|
|
// Create an entry for each tag with full image name
|
|
// Dynamically prepend registry_address to the repository name
|
|
for _, tag := range tags {
|
|
fullRepoName := registryAddress + "/" + repo.Name
|
|
fullImageName := fullRepoName + ":" + tag.Tag
|
|
repoMap := map[string]interface{}{
|
|
"id": repo.ID,
|
|
"name": fullImageName, // Full image name: registry_address/repo:tag
|
|
"repository": repo.Name, // Original repository name (without registry_address)
|
|
"tag": tag.Tag, // Tag name
|
|
"upload_time": uploadTime,
|
|
"size": totalSize,
|
|
}
|
|
result = append(result, repoMap)
|
|
}
|
|
}
|
|
|
|
return resp.R200(c, map[string]interface{}{
|
|
"images": result,
|
|
})
|
|
}
|
|
}
|