github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/apiserver/facades/client/charms/services/repofactory.go (about) 1 // Copyright 2021 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package services 5 6 import ( 7 "sync" 8 9 "github.com/juju/errors" 10 "github.com/juju/loggo" 11 12 "github.com/juju/juju/charmhub" 13 corecharm "github.com/juju/juju/core/charm" 14 charmrepo "github.com/juju/juju/core/charm/repository" 15 corelogger "github.com/juju/juju/core/logger" 16 ) 17 18 // CharmRepoFactoryConfig encapsulates the information required for creating a 19 // new CharmRepoFactory instance. 20 type CharmRepoFactoryConfig struct { 21 // The logger to use. 22 Logger loggo.Logger 23 24 // An HTTP client that is injected when making Charmhub API calls. 25 CharmhubHTTPClient charmhub.HTTPClient 26 27 StateBackend StateBackend 28 ModelBackend ModelBackend 29 } 30 31 // CharmRepoFactory instantitates charm repositories. It memoizes created 32 // repositories allowing them to be reused by subsequent GetCharmRepository 33 // calls. 34 type CharmRepoFactory struct { 35 logger loggo.Logger 36 charmhubHTTPClient charmhub.HTTPClient 37 stateBackend StateBackend 38 modelBackend ModelBackend 39 40 mu sync.Mutex 41 memoizedRepos map[corecharm.Source]corecharm.Repository 42 } 43 44 // NewCharmRepoFactory returns a new factory instance with the provided configuration. 45 func NewCharmRepoFactory(cfg CharmRepoFactoryConfig) *CharmRepoFactory { 46 return &CharmRepoFactory{ 47 logger: cfg.Logger, 48 charmhubHTTPClient: cfg.CharmhubHTTPClient, 49 stateBackend: cfg.StateBackend, 50 modelBackend: cfg.ModelBackend, 51 memoizedRepos: make(map[corecharm.Source]corecharm.Repository), 52 } 53 } 54 55 // GetCharmRepository returns a suitable corecharm.Repository instance for the 56 // requested source. Lookups are memoized for future requests. 57 func (f *CharmRepoFactory) GetCharmRepository(src corecharm.Source) (corecharm.Repository, error) { 58 f.mu.Lock() 59 defer f.mu.Unlock() 60 61 if repo, isCached := f.memoizedRepos[src]; isCached { 62 return repo, nil 63 } 64 65 var repo corecharm.Repository 66 67 switch src { 68 case corecharm.CharmHub: 69 cfg, err := f.modelBackend.Config() 70 if err != nil { 71 return nil, errors.Trace(err) 72 } 73 chURL, _ := cfg.CharmHubURL() 74 chClient, err := charmhub.NewClient(charmhub.Config{ 75 URL: chURL, 76 HTTPClient: f.charmhubHTTPClient, 77 Logger: f.logger.Child("charmhubrepo"), 78 }) 79 if err != nil { 80 return nil, errors.Trace(err) 81 } 82 83 repo = charmrepo.NewCharmHubRepository( 84 f.logger.ChildWithLabels("charmhubrepo", corelogger.CHARMHUB), 85 chClient, 86 ) 87 default: 88 return nil, errors.NotSupportedf("charm repository for source %q", src) 89 } 90 91 // Memoize for future lookups. 92 f.memoizedRepos[src] = repo 93 return repo, nil 94 }