Files
grafana/pkg/services/exploremap/exploremapimpl/service.go
2025-12-01 17:08:56 -04:00

114 lines
3.2 KiB
Go

package exploremapimpl
import (
"context"
"time"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/infra/tracing"
"github.com/grafana/grafana/pkg/services/exploremap"
"github.com/grafana/grafana/pkg/services/exploremap/realtime"
"github.com/grafana/grafana/pkg/services/live"
)
type Service struct {
store store
tracer tracing.Tracer
hub *realtime.OperationHub
}
var _ exploremap.Service = &Service{}
// storeAdapter adapts the internal store interface to the realtime Store interface
type storeAdapter struct {
store store
}
func (s *storeAdapter) Update(ctx context.Context, cmd *exploremap.UpdateExploreMapCommand) (*exploremap.ExploreMapDTO, error) {
return s.store.Update(ctx, cmd)
}
func (s *storeAdapter) Get(ctx context.Context, query *exploremap.GetExploreMapByUIDQuery) (*exploremap.ExploreMapDTO, error) {
// Get returns ExploreMap, but we need ExploreMapDTO
mapData, err := s.store.Get(ctx, query)
if err != nil {
return nil, err
}
return &exploremap.ExploreMapDTO{
UID: mapData.UID,
Title: mapData.Title,
Data: mapData.Data,
CreatedBy: mapData.CreatedBy,
UpdatedBy: mapData.UpdatedBy,
CreatedAt: mapData.CreatedAt,
UpdatedAt: mapData.UpdatedAt,
}, nil
}
func ProvideService(db db.DB, tracer tracing.Tracer, liveService *live.GrafanaLive) exploremap.Service {
store := &sqlStore{
db: db,
}
// Create adapter for realtime hub
adapter := &storeAdapter{store: store}
// Create operation hub for CRDT synchronization
hub := realtime.NewOperationHub(liveService, adapter)
// Register channel handler with Grafana Live
channelHandler := realtime.NewExploreMapChannelHandler(hub)
liveService.GrafanaScope.Features["explore-map"] = channelHandler
// Start background snapshot worker (saves CRDT state to SQL every 30 seconds)
go hub.StartSnapshotWorker(context.Background(), 30*time.Second)
return &Service{
tracer: tracer,
store: store,
hub: hub,
}
}
func (s *Service) Create(ctx context.Context, cmd *exploremap.CreateExploreMapCommand) (*exploremap.ExploreMap, error) {
ctx, span := s.tracer.Start(ctx, "exploremap.Create")
defer span.End()
return s.store.Insert(ctx, cmd)
}
func (s *Service) Update(ctx context.Context, cmd *exploremap.UpdateExploreMapCommand) (*exploremap.ExploreMapDTO, error) {
ctx, span := s.tracer.Start(ctx, "exploremap.Update")
defer span.End()
return s.store.Update(ctx, cmd)
}
func (s *Service) Get(ctx context.Context, q *exploremap.GetExploreMapByUIDQuery) (*exploremap.ExploreMapDTO, error) {
ctx, span := s.tracer.Start(ctx, "exploremap.Get")
defer span.End()
v, err := s.store.Get(ctx, q)
if err != nil {
return nil, err
}
return &exploremap.ExploreMapDTO{
UID: v.UID,
Title: v.Title,
Data: v.Data,
CreatedBy: v.CreatedBy,
UpdatedBy: v.UpdatedBy,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
}, nil
}
func (s *Service) List(ctx context.Context, q *exploremap.GetExploreMapsQuery) (exploremap.ExploreMaps, error) {
ctx, span := s.tracer.Start(ctx, "exploremap.List")
defer span.End()
return s.store.List(ctx, q)
}
func (s *Service) Delete(ctx context.Context, cmd *exploremap.DeleteExploreMapCommand) error {
ctx, span := s.tracer.Start(ctx, "exploremap.Delete")
defer span.End()
return s.store.Delete(ctx, cmd)
}