package app import ( "context" "sort" "sync" "forge.cadoles.com/arcad/edge/pkg/app" "forge.cadoles.com/arcad/edge/pkg/bundle" appModule "forge.cadoles.com/arcad/edge/pkg/module/app" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/logger" ) type ResolveAppURLFunc func(context.Context, *app.Manifest, string) (string, error) type AppRepository struct { resolveAppURL ResolveAppURLFunc bundles []string mutex sync.RWMutex } // Get implements app.Repository func (r *AppRepository) Get(ctx context.Context, id app.ID) (*app.Manifest, error) { r.mutex.RLock() defer r.mutex.RUnlock() manifest, err := r.findManifest(ctx, id) if err != nil { return nil, errors.WithStack(err) } return manifest, nil } // GetURL implements app.Repository func (r *AppRepository) GetURL(ctx context.Context, id app.ID, from string) (string, error) { r.mutex.RLock() defer r.mutex.RUnlock() manifest, err := r.findManifest(ctx, id) if err != nil { return "", errors.WithStack(err) } url, err := r.resolveAppURL(ctx, manifest, from) if err != nil { return "", errors.WithStack(err) } return url, nil } // List implements app.Repository func (r *AppRepository) List(ctx context.Context) ([]*app.Manifest, error) { r.mutex.RLock() defer r.mutex.RUnlock() manifests := make([]*app.Manifest, 0) for _, path := range r.bundles { bundleCtx := logger.With(ctx, logger.F("path", path)) bundle, err := bundle.FromPath(path) if err != nil { logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err))) continue } manifest, err := app.LoadManifest(bundle) if err != nil { logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err))) continue } manifests = append(manifests, manifest) } sort.Sort(ByID(manifests)) return manifests, nil } func (r *AppRepository) Update(resolveAppURL ResolveAppURLFunc, bundles []string) { r.mutex.Lock() defer r.mutex.Unlock() r.resolveAppURL = resolveAppURL r.bundles = bundles } func (r *AppRepository) findManifest(ctx context.Context, id app.ID) (*app.Manifest, error) { for _, path := range r.bundles { bundleCtx := logger.With(ctx, logger.F("path", path)) bundle, err := bundle.FromPath(path) if err != nil { logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err))) continue } manifest, err := app.LoadManifest(bundle) if err != nil { logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err))) continue } if manifest.ID != id { continue } return manifest, nil } return nil, errors.WithStack(appModule.ErrNotFound) } func NewAppRepository() *AppRepository { return &AppRepository{ resolveAppURL: func(ctx context.Context, m *app.Manifest, from string) (string, error) { return "", errors.New("unavailable") }, bundles: []string{}, } } var _ appModule.Repository = &AppRepository{} type ByID []*app.Manifest func (a ByID) Len() int { return len(a) } func (a ByID) Swap(i, j int) { a[i], a[j] = a[j], a[i] } func (a ByID) Less(i, j int) bool { return a[i].ID > a[j].ID }