github.com/avenga/couper@v1.12.2/config/configload/endpoint_sequence.go (about) 1 package configload 2 3 import ( 4 "sort" 5 6 "github.com/hashicorp/hcl/v2" 7 "github.com/hashicorp/hcl/v2/hclsyntax" 8 9 "github.com/avenga/couper/config" 10 "github.com/avenga/couper/config/body" 11 srvpkg "github.com/avenga/couper/config/runtime/server" 12 "github.com/avenga/couper/config/sequence" 13 "github.com/avenga/couper/eval/variables" 14 ) 15 16 // buildSequences collects possible dependencies from 'backend_responses' variable. 17 func buildSequences(names map[string]*hclsyntax.Body, endpoint *config.Endpoint) (err error) { 18 sequences := map[string]*sequence.Item{} 19 20 defer func() { 21 if rc := recover(); rc != nil { 22 err = rc.(error) 23 } 24 }() 25 26 var sortedNames sort.StringSlice 27 for name := range names { 28 sortedNames = append(sortedNames, name) 29 } 30 sortedNames.Sort() 31 32 for _, name := range sortedNames { 33 b := names[name] 34 refs := responseReferences(b) 35 36 if len(refs) == 0 { 37 continue 38 } 39 40 seq, exist := sequences[name] 41 if !exist { 42 seq = &sequence.Item{Name: name, BodyRange: getRange(b)} 43 sequences[name] = seq 44 } 45 46 for _, r := range refs { 47 ref, ok := sequences[r] 48 if !ok { 49 ref = &sequence.Item{Name: r, BodyRange: getRange(b)} 50 sequences[r] = ref 51 } 52 // Do not add ourselves 53 // Use case: modify response headers with current response 54 if seq != ref { 55 seq.Add(ref) 56 } 57 } 58 } 59 60 sortedSequences := srvpkg.SortDefault(sequences) 61 for _, name := range sortedSequences { 62 s := sequences[name] 63 if !s.HasParent() { 64 endpoint.Sequences = append(endpoint.Sequences, s) 65 } 66 } 67 68 return err 69 } 70 71 func responseReferences(b *hclsyntax.Body) []string { 72 var result []string 73 unique := map[string]struct{}{} 74 75 for _, expr := range body.CollectExpressions(b) { 76 for _, traversal := range expr.Variables() { 77 if traversal.RootName() != variables.BackendResponses || len(traversal) < 2 { 78 continue 79 } 80 81 tr, ok := traversal[1].(hcl.TraverseAttr) 82 if !ok { 83 continue 84 } 85 86 if _, ok = unique[tr.Name]; !ok { 87 unique[tr.Name] = struct{}{} 88 result = append(result, tr.Name) 89 } 90 } 91 } 92 93 return result 94 }