feat: add registry config, image upload/download, and OCI format support

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)
This commit is contained in:
loveuer
2025-11-10 16:28:58 +08:00
parent 29088a6b54
commit 9780a2b028
35 changed files with 3065 additions and 91 deletions

76
pkg/tool/must.go Normal file
View File

@@ -0,0 +1,76 @@
package tool
import (
"context"
"log"
"reflect"
"runtime"
"sync"
)
func Must(errs ...error) {
for _, err := range errs {
if err != nil {
log.Panic(err.Error())
}
}
}
func MustWithData[T any](data T, err error) T {
Must(err)
return data
}
func MustStop(ctx context.Context, stopFns ...func(ctx context.Context) error) {
getFunctionName := func(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
if len(stopFns) == 0 {
return
}
ok := make(chan struct{})
wg := &sync.WaitGroup{}
for _, fn := range stopFns {
if fn != nil {
wg.Add(1)
go func(c context.Context) {
defer func() {
wg.Done()
log.Printf("stop func[%s] done", getFunctionName(fn))
}()
if err := fn(c); err != nil {
log.Printf("stop function failed, err = %s", err.Error())
}
}(ctx)
}
}
go func() {
select {
case <-ctx.Done():
log.Fatal("stop function timeout, force down")
case _, _ = <-ok:
log.Printf("shutdown gracefully...")
return
}
}()
wg.Wait()
close(ok)
}
func IgnoreError[T any](item T, err error) T {
if err != nil {
log.Printf("[W] !!! ignore error: %s", err.Error())
}
return item
}