Skip to content

feat: add register app store api in sync #192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions api/app_management/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,31 @@ paths:
"500":
$ref: "#/components/responses/ResponseInternalServerError"

# the endpoint is newer version of POST /appstore for the demand of @ETWang1991
# the old api is dependent by CasaOS. So we can't remove it.
# a good idea is /v3/app-management/appstore. But it is hard to implement in ZimaOS
# So I had to add the endpoint here.
/appstore/sync:
post:
summary: Register an app store in Sync.
description: |
(TODO)
operationId: registerAppStoreSync
tags:
- AppStore methods
parameters:
- $ref: "#/components/parameters/AppStoreURL"
responses:
"200":
$ref: "#/components/responses/AppStoreRegisterOK"
"400":
$ref: "#/components/responses/ResponseBadRequest"
"409":
$ref: "#/components/responses/ResponseConflict"
"500":
$ref: "#/components/responses/ResponseInternalServerError"


/appstore:
get:
summary: Get the list of registered app stores
Expand Down
50 changes: 38 additions & 12 deletions route/v2/appstore.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,36 +30,62 @@ func (a *AppManagement) AppStoreList(ctx echo.Context) error {
})
}

// the method should be deprecated
// but it be used by CasaOS
func (a *AppManagement) RegisterAppStore(ctx echo.Context, params codegen.RegisterAppStoreParams) error {
if params.Url == nil || *params.Url == "" {
message := "appstore url is required"
return ctx.JSON(http.StatusBadRequest, codegen.ResponseBadRequest{Message: &message})
}

isExist := lo.ContainsBy(service.MyService.AppStoreManagement().AppStoreList(), func(appstore codegen.AppStoreMetadata) bool {
return appstore.URL != nil && strings.EqualFold(*appstore.URL, *params.Url)
backgroundCtx := common.WithProperties(context.Background(), PropertiesFromQueryParams(ctx))

if err := service.MyService.AppStoreManagement().RegisterAppStore(backgroundCtx, *params.Url); err != nil {
message := err.Error()

if err != nil {
switch err {
case service.ErrAppStoreSourceExists:
return ctx.JSON(http.StatusConflict, codegen.ResponseConflict{Message: &message})
case service.ErrNotAppStore:
return ctx.JSON(http.StatusBadRequest, codegen.ResponseBadRequest{Message: &message})
default:
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{Message: &message})
}
}
}

logFilepath := filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s", config.AppInfo.LogSaveName, config.AppInfo.LogFileExt))
message := fmt.Sprintf("trying to register app store asynchronously - see %s for any errors.", logFilepath)
return ctx.JSON(http.StatusOK, codegen.AppStoreRegisterOK{
Message: &message,
})
}

if isExist {
message := "appstore is already registered"
return ctx.JSON(http.StatusConflict, codegen.ResponseConflict{Message: &message})
func (a *AppManagement) RegisterAppStoreSync(ctx echo.Context, params codegen.RegisterAppStoreSyncParams) error {
if params.Url == nil || *params.Url == "" {
message := "appstore url is required"
return ctx.JSON(http.StatusBadRequest, codegen.ResponseBadRequest{Message: &message})
}

backgroundCtx := common.WithProperties(context.Background(), PropertiesFromQueryParams(ctx))

if err := service.MyService.AppStoreManagement().RegisterAppStore(backgroundCtx, *params.Url); err != nil {
err := service.MyService.AppStoreManagement().RegisterAppStoreSync(backgroundCtx, *params.Url)
if err != nil {
message := err.Error()
if err == service.ErrNotAppStore {

switch err {
case service.ErrAppStoreSourceExists:
return ctx.JSON(http.StatusConflict, codegen.ResponseConflict{Message: &message})
case service.ErrNotAppStore:
return ctx.JSON(http.StatusBadRequest, codegen.ResponseBadRequest{Message: &message})
default:
return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{Message: &message})
}

return ctx.JSON(http.StatusInternalServerError, codegen.ResponseInternalServerError{Message: &message})
}

logFilepath := filepath.Join(config.AppInfo.LogPath, fmt.Sprintf("%s.%s", config.AppInfo.LogSaveName, config.AppInfo.LogFileExt))
message := fmt.Sprintf("trying to register app store asynchronously - see %s for any errors.", logFilepath)
return ctx.JSON(http.StatusOK, codegen.AppStoreRegisterOK{
Message: &message,
Message: utils.Ptr("app store is registered."),
})
}

Expand Down
71 changes: 66 additions & 5 deletions service/appstore_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@ import (
"go.uber.org/zap"
)

var ErrAppStoreSourceExists = fmt.Errorf("appstore source already exists")

type AppStoreManagement struct {
isAppUpgradable gcache.Cache
defaultAppStore AppStore
isAppUpgrading sync.Map
onAppStoreRegister []func(string) error
onAppStoreUnregister []func(string) error

isAppUpgradable gcache.Cache
isAppUpgrading sync.Map
defaultAppStore AppStore
}

func (a *AppStoreManagement) AppStoreList() []codegen.AppStoreMetadata {
Expand Down Expand Up @@ -99,7 +100,7 @@ func (a *AppStoreManagement) RegisterAppStore(ctx context.Context, appstoreURL s
// check if appstore already exists
for _, url := range config.ServerInfo.AppStoreList {
if strings.EqualFold(url, appstoreURL) {
return nil
return ErrAppStoreSourceExists
}
}

Expand Down Expand Up @@ -158,6 +159,66 @@ func (a *AppStoreManagement) RegisterAppStore(ctx context.Context, appstoreURL s
return nil
}

// TODO: refactor the function and above function
func (a *AppStoreManagement) RegisterAppStoreSync(ctx context.Context, appstoreURL string, callbacks ...func(*codegen.AppStoreMetadata)) error {
// check if appstore already exists
for _, url := range config.ServerInfo.AppStoreList {
if strings.EqualFold(url, appstoreURL) {
return ErrAppStoreSourceExists
}
}

appstore, err := AppStoreByURL(appstoreURL)
if err != nil {
return err
}

go PublishEventWrapper(ctx, common.EventTypeAppStoreRegisterBegin, nil)

defer PublishEventWrapper(ctx, common.EventTypeAppStoreRegisterEnd, nil)

defer func() {
if err == nil {
return
}

PublishEventWrapper(ctx, common.EventTypeAppStoreRegisterError, map[string]string{
common.PropertyTypeMessage.Name: err.Error(),
})
}()

if err = appstore.UpdateCatalog(); err != nil {
logger.Error("failed to update appstore catalog", zap.Error(err), zap.String("appstoreURL", appstoreURL))

return err
}

// if everything is good, add to the list
config.ServerInfo.AppStoreList = append(config.ServerInfo.AppStoreList, appstoreURL)

if err = config.SaveSetup(); err != nil {
logger.Error("failed to save appstore list", zap.Error(err), zap.String("appstoreURL", appstoreURL))
return err
}

for _, fn := range a.onAppStoreRegister {
if err := fn(appstoreURL); err != nil {
logger.Error("failed to run onAppStoreRegister", zap.Error(err), zap.String("appstoreURL", appstoreURL))
}
}

appStoreMetadata := &codegen.AppStoreMetadata{
ID: utils.Ptr(len(config.ServerInfo.AppStoreList) - 1),
URL: &appstoreURL,
}

for _, callback := range callbacks {
callback(appStoreMetadata)
}

return nil
}

func (a *AppStoreManagement) UnregisterAppStore(appStoreID uint) error {
if appStoreID >= uint(len(config.ServerInfo.AppStoreList)) {
return fmt.Errorf("appstore id %d out of range", appStoreID)
Expand Down
Loading