package dcache import ( "crypto/sha256" "encoding/hex" "encoding/json" "sort" "strconv" "time" ) // SearchKeyInput is the canonical cache identity for a search. Callers pass // already-normalised filter fields (long time_range, sorted domains optional). type SearchKeyInput struct { Queries []string Sources []string K int Hour time.Time CallerClass string IncludeDomains []string ExcludeDomains []string IncludeDomainsMode string TimeRange string StartDate string EndDate string Topic string ExactMatch bool MinScore float64 } func SearchKey(query string, sources []string, k int, hour time.Time, callerClass string) string { return EncodeSearchKey(SearchKeyInput{ Queries: []string{query}, Sources: sources, K: k, Hour: hour, CallerClass: callerClass, }) } func EncodeSearchKey(in SearchKeyInput) string { if in.CallerClass == "" { in.CallerClass = ClassFleet } src := append([]string(nil), in.Sources...) sort.Strings(src) qs := make([]string, len(in.Queries)) for i, q := range in.Queries { qs[i] = NormalizeQuestion(q) } topic := in.Topic if topic == "" { topic = "general" } m := map[string]any{ "caller_class": in.CallerClass, "exact_match": in.ExactMatch, "hour": in.Hour.UTC().Format("2006-01-02T15"), "k": in.K, "min_score": strconv.FormatFloat(in.MinScore, 'f', -1, 64), "queries": qs, "sources": src, "topic": topic, } if inc := sortedUnique(in.IncludeDomains); len(inc) > 0 { m["include_domains"] = inc mode := in.IncludeDomainsMode if mode == "" { mode = "restrict" } m["include_domains_mode"] = mode } if exc := sortedUnique(in.ExcludeDomains); len(exc) > 0 { m["exclude_domains"] = exc } if in.TimeRange != "" { m["time_range"] = in.TimeRange } if in.StartDate != "" { m["start_date"] = in.StartDate } if in.EndDate != "" { m["end_date"] = in.EndDate } b, _ := json.Marshal(m) sum := sha256.Sum256(b) return hex.EncodeToString(sum[:]) } func sortedUnique(in []string) []string { if len(in) == 0 { return nil } out := append([]string(nil), in...) sort.Strings(out) n := 0 for _, s := range out { if s == "" { continue } if n > 0 && out[n-1] == s { continue } out[n] = s n++ } return out[:n] }