1package client
2
3import (
4	"fmt"
5
6	"github.com/splitio/go-split-commons/v3/dtos"
7	"github.com/splitio/go-split-commons/v3/storage"
8	"github.com/splitio/go-toolkit/v4/logging"
9)
10
11// SplitManager provides information of the currently stored splits
12type SplitManager struct {
13	splitStorage  storage.SplitStorageConsumer
14	validator     inputValidation
15	logger        logging.LoggerInterface
16	factory       *SplitFactory
17	initTelemetry storage.TelemetryConfigProducer
18}
19
20// SplitView is a partial representation of a currently stored split
21type SplitView struct {
22	Name         string            `json:"name"`
23	TrafficType  string            `json:"trafficType"`
24	Killed       bool              `json:"killed"`
25	Treatments   []string          `json:"treatments"`
26	ChangeNumber int64             `json:"changeNumber"`
27	Configs      map[string]string `json:"configs"`
28}
29
30func newSplitView(splitDto *dtos.SplitDTO) *SplitView {
31	treatments := make([]string, 0)
32	for _, condition := range splitDto.Conditions {
33		for _, partition := range condition.Partitions {
34			treatments = append(treatments, partition.Treatment)
35		}
36	}
37	return &SplitView{
38		ChangeNumber: splitDto.ChangeNumber,
39		Killed:       splitDto.Killed,
40		Name:         splitDto.Name,
41		TrafficType:  splitDto.TrafficTypeName,
42		Treatments:   treatments,
43		Configs:      splitDto.Configurations,
44	}
45}
46
47// SplitNames returns a list with the name of all the currently stored splits
48func (m *SplitManager) SplitNames() []string {
49	if m.isDestroyed() {
50		m.logger.Error("Client has already been destroyed - no calls possible")
51		return []string{}
52	}
53
54	if !m.isReady() {
55		m.logger.Warning("SplitNames: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method")
56		m.initTelemetry.RecordNonReadyUsage()
57	}
58
59	return m.splitStorage.SplitNames()
60}
61
62// Splits returns a list of a partial view of every currently stored split
63func (m *SplitManager) Splits() []SplitView {
64	if m.isDestroyed() {
65		m.logger.Error("Client has already been destroyed - no calls possible")
66		return []SplitView{}
67	}
68
69	if !m.isReady() {
70		m.logger.Warning("Splits: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method")
71		m.initTelemetry.RecordNonReadyUsage()
72	}
73
74	splitViews := make([]SplitView, 0)
75	splits := m.splitStorage.All()
76	for _, split := range splits {
77		splitViews = append(splitViews, *newSplitView(&split))
78	}
79	return splitViews
80}
81
82// Split returns a partial view of a particular split
83func (m *SplitManager) Split(feature string) *SplitView {
84	if m.isDestroyed() {
85		m.logger.Error("Client has already been destroyed - no calls possible")
86		return nil
87	}
88
89	if !m.isReady() {
90		m.logger.Warning("Split: the SDK is not ready, results may be incorrect. Make sure to wait for SDK readiness before using this method")
91		m.initTelemetry.RecordNonReadyUsage()
92	}
93
94	err := m.validator.ValidateManagerInputs(feature)
95	if err != nil {
96		m.logger.Error(err.Error())
97		return nil
98	}
99
100	split := m.splitStorage.Split(feature)
101	if split != nil {
102		return newSplitView(split)
103	}
104	m.logger.Error(fmt.Sprintf("Split: you passed %s that does not exist in this environment, please double check what Splits exist in the web console.", feature))
105	return nil
106}
107
108// BlockUntilReady Calls BlockUntilReady on factory to block manager on readiness
109func (m *SplitManager) BlockUntilReady(timer int) error {
110	return m.factory.BlockUntilReady(timer)
111}
112
113func (m *SplitManager) isDestroyed() bool {
114	return m.factory.IsDestroyed()
115}
116
117func (m *SplitManager) isReady() bool {
118	return m.factory.IsReady()
119}
120