The open and composable observability and data visualization platform. Visualize metrics, logs, and traces from multiple sources like Prometheus, Loki, Elasticsearch, InfluxDB, Postgres and many more.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
grafana/pkg/plugins/manager/loader/assetpath/assetpath.go

137 lines
4.1 KiB

package assetpath
import (
"fmt"
"net/url"
"path"
"path/filepath"
"strings"
"github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/plugins/config"
"github.com/grafana/grafana/pkg/plugins/manager/fakes"
"github.com/grafana/grafana/pkg/plugins/pluginassets"
"github.com/grafana/grafana/pkg/plugins/pluginscdn"
)
// Service provides methods for constructing asset paths for plugins.
// It supports core plugins, external plugins stored on the local filesystem, and external plugins stored
// on the plugins CDN, and it will switch to the correct implementation depending on the plugin and the config.
type Service struct {
cdn *pluginscdn.Service
cfg *config.PluginManagementCfg
assetProvider pluginassets.Provider
}
func ProvideService(cfg *config.PluginManagementCfg, cdn *pluginscdn.Service, assetProvider pluginassets.Provider) *Service {
return &Service{cfg: cfg, cdn: cdn, assetProvider: assetProvider}
}
func DefaultService(cfg *config.PluginManagementCfg) *Service {
return &Service{cfg: cfg, cdn: pluginscdn.ProvideService(cfg), assetProvider: fakes.NewFakeAssetProvider()}
}
// Base returns the base path for the specified plugin.
func (s *Service) Base(n pluginassets.PluginInfo) (string, error) {
if s.cfg.Features.PluginAssetProvider {
return s.assetProvider.AssetPath(n)
}
if n.Class == plugins.ClassCDN {
return n.FS.Base(), nil
}
if s.cdn.PluginSupported(n.JsonData.ID) {
return s.cdn.AssetURL(n.JsonData.ID, n.JsonData.Info.Version, "")
}
if n.Parent != nil {
relPath, err := n.Parent.FS.Rel(n.FS.Base())
if err != nil {
return "", err
}
if s.cdn.PluginSupported(n.Parent.JsonData.ID) {
return s.cdn.AssetURL(n.Parent.JsonData.ID, n.Parent.JsonData.Info.Version, relPath)
}
}
return path.Join("public/plugins", n.JsonData.ID), nil
}
// Module returns the module.js path for the specified plugin.
func (s *Service) Module(n pluginassets.PluginInfo) (string, error) {
if s.cfg.Features.PluginAssetProvider {
return s.assetProvider.Module(n)
}
if n.Class == plugins.ClassCore && filepath.Base(n.FS.Base()) != "dist" {
return path.Join("core:plugin", filepath.Base(n.FS.Base())), nil
}
return s.RelativeURL(n, "module.js")
}
// RelativeURL returns the relative URL for an arbitrary plugin asset.
func (s *Service) RelativeURL(n pluginassets.PluginInfo, pathStr string) (string, error) {
if s.cfg.Features.PluginAssetProvider {
return s.assetProvider.AssetPath(n, pathStr)
}
if n.Class == plugins.ClassCDN {
return pluginscdn.JoinPath(n.FS.Base(), pathStr)
}
if s.cdn.PluginSupported(n.JsonData.ID) {
return s.cdn.NewCDNURLConstructor(n.JsonData.ID, n.JsonData.Info.Version).StringPath(pathStr)
}
if n.Parent != nil {
if s.cdn.PluginSupported(n.Parent.JsonData.ID) {
relPath, err := n.Parent.FS.Rel(n.FS.Base())
if err != nil {
return "", err
}
return s.cdn.AssetURL(n.Parent.JsonData.ID, n.Parent.JsonData.Info.Version, path.Join(relPath, pathStr))
}
}
// Local
u, err := url.Parse(pathStr)
if err != nil {
return "", fmt.Errorf("url parse: %w", err)
}
if u.IsAbs() {
return pathStr, nil
}
baseURL, err := s.Base(n)
if err != nil {
return "", err
}
// has already been prefixed with base path
if strings.HasPrefix(pathStr, baseURL) {
return pathStr, nil
}
return path.Join(baseURL, pathStr), nil
}
// DefaultLogoPath returns the default logo path for the specified plugin type.
func (s *Service) DefaultLogoPath(pluginType plugins.Type) string {
return path.Join("public/img", fmt.Sprintf("icn-%s.svg", string(pluginType)))
}
func (s *Service) GetTranslations(n pluginassets.PluginInfo) (map[string]string, error) {
pathToTranslations, err := s.RelativeURL(n, "locales")
if err != nil {
return nil, fmt.Errorf("get locales: %w", err)
}
// loop through all the languages specified in the plugin.json and add them to the list
translations := map[string]string{}
for _, language := range n.JsonData.Languages {
file := fmt.Sprintf("%s.json", n.JsonData.ID)
translations[language], err = url.JoinPath(pathToTranslations, language, file)
if err != nil {
return nil, fmt.Errorf("join path: %w", err)
}
}
return translations, nil
}