mattermost-community-enterp.../vendor/github.com/splitio/go-split-commons/v7/engine/engine.go
Claude ec1f89217a Merge: Complete Mattermost Server with Community Enterprise
Full Mattermost server source with integrated Community Enterprise features.
Includes vendor directory for offline/air-gapped builds.

Structure:
- enterprise-impl/: Enterprise feature implementations
- enterprise-community/: Init files that register implementations
- enterprise/: Bridge imports (community_imports.go)
- vendor/: All dependencies for offline builds

Build (online):
  go build ./cmd/mattermost

Build (offline/air-gapped):
  go build -mod=vendor ./cmd/mattermost

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 23:59:07 +09:00

74 lines
2.2 KiB
Go

package engine
import (
"fmt"
"math"
"github.com/splitio/go-split-commons/v7/engine/evaluator/impressionlabels"
"github.com/splitio/go-split-commons/v7/engine/grammar"
"github.com/splitio/go-split-commons/v7/engine/grammar/constants"
"github.com/splitio/go-split-commons/v7/engine/hash"
"github.com/splitio/go-toolkit/v5/hasher"
"github.com/splitio/go-toolkit/v5/logging"
)
// Engine struct is responsible for checking if any of the conditions of the feature flag matches,
// performing traffic allocation, calculating the bucket and returning the appropriate treatment
type Engine struct {
logger logging.LoggerInterface
}
// DoEvaluation performs the main evaluation against each condition
func (e *Engine) DoEvaluation(
split *grammar.Split,
key string,
bucketingKey string,
attributes map[string]interface{},
) (*string, string) {
inRollOut := false
for _, cond := range split.Conditions() {
if !inRollOut && cond.ConditionType() == grammar.ConditionTypeRollout {
if split.TrafficAllocation() < 100 {
bucket := e.calculateBucket(split.Algo(), bucketingKey, split.TrafficAllocationSeed())
if bucket > split.TrafficAllocation() {
e.logger.Debug(fmt.Sprintf(
"Traffic allocation exceeded for feature %s and key %s."+
" Returning default treatment", split.Name(), key,
))
defaultTreatment := split.DefaultTreatment()
return &defaultTreatment, impressionlabels.NotInSplit
}
inRollOut = true
}
}
if cond.Matches(key, &bucketingKey, attributes) {
bucket := e.calculateBucket(split.Algo(), bucketingKey, split.Seed())
treatment := cond.CalculateTreatment(bucket)
return treatment, cond.Label()
}
}
return nil, impressionlabels.NoConditionMatched
}
func (e *Engine) calculateBucket(algo int, bucketingKey string, seed int64) int {
var hashedKey uint32
switch algo {
case constants.SplitAlgoMurmur:
hashedKey = hasher.Sum32WithSeed([]byte(bucketingKey), uint32(seed))
case constants.SplitAlgoLegacy:
fallthrough
default:
hashedKey = hash.Legacy([]byte(bucketingKey), uint32(seed))
}
return int(math.Abs(float64(hashedKey%100)) + 1)
}
// NewEngine instantiates and returns a new engine
func NewEngine(logger logging.LoggerInterface) *Engine {
return &Engine{logger: logger}
}