-
Notifications
You must be signed in to change notification settings - Fork 411
/
Copy pathsearchalg.go
132 lines (106 loc) · 3.69 KB
/
searchalg.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
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2019-2022 Graham Clark. All rights reserved. Use of this source
// code is governed by the MIT license that can be found in the LICENSE
// file.
// Package ui contains user-interface functions and helpers for termshark.
package ui
import (
"fmt"
"time"
"github.com/gcla/gowid"
"github.com/gcla/termshark/v2"
"github.com/gcla/termshark/v2/pkg/pcap"
"github.com/gcla/termshark/v2/widgets/search"
)
//======================================================================
// PacketSearcher coordinates a packet search and communicates results back from the
// search implementations via resultChan.
type PacketSearcher struct {
resultChan chan search.IntermediateResult
}
var _ search.IAlgorithm = (*PacketSearcher)(nil)
//======================================================================
// SearchPackets looks for the given search term in the currently loaded packets. It
// is written generically, with the specifics of the packet details to be searched provided
// by a set of callbacks. These give the search algorithm the starting position, the mechanics
// of the search, and so on. An instance of a search can return a matching position, or a
// value indicating that the algorithm needs to wait until packet data is available (e.g.
// if PDML data needs to be searched but is not currently loaded). If a match is found, the
// callbacks also determine how to update the UI to represent the match.
func (w *PacketSearcher) SearchPackets(term search.INeedle, cbs search.ICallbacks, app gowid.IApp) {
if packetListView == nil {
cbs.OnError(fmt.Errorf("No packets to search"), app)
return
}
cbs.Reset(app)
currentPos, err := cbs.StartingPosition()
startPos := currentPos
// currentPacket will be 1-based
if err != nil {
cbs.OnError(err, app)
return
}
stopCurrentSearch = cbs
progressOwner = SearchOwns
searchStop.RemoveOnClick(gowid.CallbackID{
Name: "searchstop",
})
searchStop.OnClick(gowid.MakeWidgetCallback("searchstop", func(app gowid.IApp, _ gowid.IWidget) {
cbs.RequestStop(app)
}))
tickInterval := time.Duration(200) * time.Millisecond
tick := time.NewTicker(tickInterval)
resumeAt := -1
var resAt interface{}
// Computationally bound searching goroutine - may have to terminate if it runs out of
// packets to search while they're loaded
termshark.TrackedGo(func() {
cbs.SearchPacketsFrom(currentPos, startPos, term, app)
}, Goroutinewg)
// This goroutine exists so that at a regular interval, I can update progress. I want
// the main searching goroutine to be doing the computation and not having to cooperate
// with a timer interrupt
termshark.TrackedGo(func() {
res := search.Result{}
defer func() {
stopCurrentSearch = nil
cbs.SearchPacketsResult(res, app)
}()
Loop:
for {
select {
case <-tick.C:
cbs.OnTick(app)
if resumeAt != -1 {
termshark.TrackedGo(func() {
cbs.SearchPacketsFrom(resAt, startPos, term, app)
}, Goroutinewg)
resumeAt = -1
}
case sres := <-w.resultChan:
if sres.ResumeAt == nil {
// Search is finished
res = sres.Res
break Loop
} else {
resumeAt = sres.ResumeAt.PacketNumber()
resAt = sres.ResumeAt
// go to 0-based for cache lookup
resumeAtZeroBased := resumeAt - 1
app.Run(gowid.RunFunction(func(app gowid.IApp) {
pktsPerLoad := Loader.PacketsPerLoad()
CacheRequests = append(CacheRequests, pcap.LoadPcapSlice{
Row: (resumeAtZeroBased / pktsPerLoad) * pktsPerLoad,
CancelCurrent: true,
})
CacheRequestsChan <- struct{}{}
}))
}
}
}
}, Goroutinewg)
}
//======================================================================
// Local Variables:
// mode: Go
// fill-column: 110
// End: