-
Notifications
You must be signed in to change notification settings - Fork 15
/
investigation.go
65 lines (56 loc) · 1.34 KB
/
investigation.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package gumshoe
import (
"fmt"
"sync"
"time"
)
type investigation struct {
sync.RWMutex
ongoing sync.WaitGroup
processed map[string]bool
findings []Finding
startedAt time.Time
}
// Run begins the investigation with the initial finding(s) provided
func Run(fs ...Finding) []Finding {
if fs == nil || len(fs) == 0 {
return []Finding{}
}
return investigate(fs...).findings
}
// investigate is a wrapper around the recursive processFindings func
func investigate(fs ...Finding) *investigation {
i := &investigation{
ongoing: sync.WaitGroup{},
processed: make(map[string]bool),
findings: []Finding{},
startedAt: time.Now(),
}
i.processFindings(fs...)
i.ongoing.Wait() // wait for all go routines to finish
return i
}
func (i *investigation) processFindings(fs ...Finding) {
for _, f := range fs {
if !i.isProcessed(f) {
i.markProcessed(f)
i.ongoing.Add(1)
go func(ff Finding) {
defer i.ongoing.Done()
i.processFindings(ff.Investigate()...)
}(f)
}
}
}
func (i *investigation) markProcessed(f Finding) {
i.Lock()
defer i.Unlock()
i.findings = append(i.findings, f)
i.processed[fmt.Sprintf("%s-%s", f.GetTypeName(), f.GetID())] = true
}
func (i *investigation) isProcessed(f Finding) bool {
i.RLock()
defer i.RUnlock()
_, ok := i.processed[fmt.Sprintf("%s-%s", f.GetTypeName(), f.GetID())]
return ok
}