func (c *PacketLoader) ClearPcap(cb interface{}) {
	startIfaceAgain := false
	if c.InterfaceLoader != nil {
		if !c.loadWasCancelled {
			startIfaceAgain = true
			for _, psrc := range c.psrcs {
				startIfaceAgain = startIfaceAgain && CanRestart(psrc)  
			}
		}
		c.stopLoadIface()
	}
	if !startIfaceAgain {
		c.loadWasCancelled = true
	}
	c.stopTail()
	c.stopLoadPsml()
	c.stopLoadPdml()
	OpsChan <- gowid.RunFunction(func(app gowid.IApp) {
		handleClear(NoneCode, app, cb)
		c.loadWasCancelled = false
		c.RenewPsmlLoader()
		c.RenewPdmlLoader()
		if !startIfaceAgain {
			c.psrcs = c.psrcs[:0]
			c.ifaceFile = ""
			c.PcapPsml = ""
			c.PcapPdml = ""
			c.PcapPcap = ""
			c.displayFilter = ""
		} else {
			c.RenewIfaceLoader()
			if err := c.loadInterfaces(c.psrcs, c.CaptureFilter(), c.DisplayFilter(), c.InterfaceFile(), cb, app); err != nil {
				HandleError(NoneCode, app, err, cb)
			}
		}
	})
}
Clears the currently loaded data. If the loader is currently reading from an
interface, the loading continues after the current data has been discarded. If
the loader is currently reading from a file, the loading *stops*.
Intended to restart iface loader - since a clear will discard all data up to here.
package pcap
import (
	"bufio"
	"context"
	"encoding/xml"
	"fmt"
	"io"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
	"sync/atomic"
	"github.com/gcla/gowid"
	"github.com/gcla/gowid/gwutil"
	"github.com/gcla/termshark/v2"
	"github.com/gcla/termshark/v2/format"
	lru "github.com/hashicorp/golang-lru"
	log "github.com/sirupsen/logrus"
	fsnotify "gopkg.in/fsnotify/fsnotify.v1"
)
var PcapCmds ILoaderCmds
var PcapOpts Options
var OpsChan chan gowid.RunFunction
func init() {
	OpsChan = make(chan gowid.RunFunction, 100)
}
var Goroutinewg *sync.WaitGroup
type RunFn func()
type LoaderState bool
const (
	NotLoading LoaderState = false
	Loading    LoaderState = true
)
func (t LoaderState) String() string {
	if t {
		return "loading"
	} else {
		return "not-loading"
	}
}
type ProcessState int
const (
	NotStarted ProcessState = 0
	Started    ProcessState = 1
	Terminated ProcessState = 2
)
func (p ProcessState) String() string {
	switch p {
	case NotStarted:
		return "NotStarted"
	case Started:
		return "Started"
	case Terminated:
		return "Terminated"
	default:
		return "Unknown"
	}
}
type IBasicCommand interface {
	fmt.Stringer
	Start() error
	Wait() error
	Pid() int
	Kill() error
}
type ITailCommand interface {
	IBasicCommand
	SetStdout(io.Writer)  
	Close() error         
}
type IPcapCommand interface {
	IBasicCommand
	StdoutReader() (io.ReadCloser, error)  
}
type ILoaderCmds interface {
	Iface(ifaces []string, captureFilter string, tmpfile string) IBasicCommand
	Tail(tmpfile string) ITailCommand
	Psml(pcap interface{}, displayFilter string) IPcapCommand
	Pcap(pcap string, displayFilter string) IPcapCommand
	Pdml(pcap string, displayFilter string) IPcapCommand
}
type PacketLoader struct {
	*ParentLoader
}
func (c *PacketLoader) Renew() {
	if c.ParentLoader != nil {
		c.ParentLoader.CloseMain()
	}
	c.ParentLoader = NewPcapLoader(c.ParentLoader.cmds, c.runner, c.ParentLoader.opt)
}
type ParentLoader struct {
	*InterfaceLoader  
	*PsmlLoader
	*PdmlLoader
	cmds ILoaderCmds
	tailStoppedDeliberately bool  
	psrcs         []IPacketSource  
	displayFilter string
	captureFilter string
	ifaceFile string  
	mainCtx      context.Context  
	mainCancelFn context.CancelFunc
	loadWasCancelled bool  
	runner IMainRunner
	opt    Options  
}
type InterfaceLoader struct {
	state LoaderState
	ifaceCtx      context.Context  
	ifaceCancelFn context.CancelFunc
	ifaceCmd IBasicCommand
	sync.Mutex
	totalFifoBytesWritten gwutil.Int64Option
	totalFifoBytesRead    gwutil.Int64Option
	fifoError             error
}
type PsmlLoader struct {
	state LoaderState  
	PcapPsml interface{}  
	psmlStoppedDeliberately_ bool  
	psmlCtx      context.Context  
	psmlCancelFn context.CancelFunc
	tailCtx      context.Context  
	tailCancelFn context.CancelFunc
	startStage2Chan chan struct{}
	PsmlFinishedChan chan struct{}  
	tailCmd ITailCommand
	PsmlCmd IPcapCommand  
	sync.Mutex
	packetAverageLength []averageTracker  
	packetMaxLength     []maxTracker      
	packetPsmlData      [][]string
	packetPsmlColors    []PacketColors
	packetPsmlHeaders   []string
	PacketNumberMap     map[int]int  
	PacketCache *lru.Cache  
	opt Options
}
type PdmlLoader struct {
	state LoaderState  
	PcapPdml string  
	PcapPcap string  
	pdmlStoppedDeliberately_ bool  
	stage2Ctx      context.Context  
	stage2CancelFn context.CancelFunc
	stage2Wg sync.WaitGroup
	startChan chan struct{}
	Stage2FinishedChan chan struct{}  
	PdmlPid int  
	PcapPid int  
	sync.Mutex
	visible                  bool  
	rowCurrentlyLoading      int   
	highestCachedRow         int   
	KillAfterReadingThisMany int   
	opt Options
}
type PacketColors struct {
	FG gowid.IColor
	BG gowid.IColor
}
type Options struct {
	CacheSize      int
	PacketsPerLoad int
}
type iLoaderEnv interface {
	Commands() ILoaderCmds
	MainRun(fn gowid.RunFunction)
	Context() context.Context
}
type iPsmlLoaderEnv interface {
	iLoaderEnv
	iTailCommand
	PsmlStoppedDeliberately() bool
	TailStoppedDeliberately() bool
	LoadWasCancelled() bool
	DisplayFilter() string
	InterfaceFile() string
	PacketSources() []IPacketSource
}
type IMainRunner interface {
	Run(fn gowid.RunFunction)
}
type Runner struct {
	gowid.IApp
}
var _ IMainRunner = (*Runner)(nil)
func (a *Runner) Run(fn gowid.RunFunction) {
	a.IApp.Run(fn)
}
func NewPcapLoader(cmds ILoaderCmds, runner IMainRunner, opts ...Options) *ParentLoader {
	var opt Options
	if len(opts) > 0 {
		opt = opts[0]
	}
	if opt.CacheSize == 0 {
		opt.CacheSize = 32
	}
	if opt.PacketsPerLoad == 0 {
		opt.PacketsPerLoad = 1000  
	} else if opt.PacketsPerLoad < 100 {
		opt.PacketsPerLoad = 100  
	}
	res := &ParentLoader{
		PsmlLoader: &PsmlLoader{},  
		PdmlLoader: &PdmlLoader{
			opt: opt,
		},
		cmds:   cmds,
		runner: runner,
		opt:    opt,
	}
	res.mainCtx, res.mainCancelFn = context.WithCancel(context.Background())
	res.RenewPsmlLoader()
	res.RenewPdmlLoader()
	return res
}
func (c *ParentLoader) RenewPsmlLoader() {
	c.PsmlLoader = &PsmlLoader{
		PcapPsml:            c.PsmlLoader.PcapPsml,
		tailCmd:             c.PsmlLoader.tailCmd,
		PsmlCmd:             c.PsmlLoader.PsmlCmd,
		packetAverageLength: make([]averageTracker, 64),
		packetMaxLength:     make([]maxTracker, 64),
		packetPsmlData:      make([][]string, 0),
		packetPsmlColors:    make([]PacketColors, 0),
		packetPsmlHeaders:   make([]string, 0, 10),
		PacketNumberMap:     make(map[int]int),
		startStage2Chan:     make(chan struct{}),  
		PsmlFinishedChan:    make(chan struct{}),
		opt:                 c.opt,
	}
	packetCache, err := lru.New(c.opt.CacheSize)
	if err != nil {
		log.Fatal(err)
	}
	c.PacketCache = packetCache
}
func (c *ParentLoader) RenewPdmlLoader() {
	c.PdmlLoader = &PdmlLoader{
		PcapPdml:            c.PcapPdml,
		PcapPcap:            c.PcapPcap,
		rowCurrentlyLoading: -1,
		highestCachedRow:    -1,
		opt:                 c.opt,
	}
}
func (c *ParentLoader) RenewIfaceLoader() {
	c.InterfaceLoader = &InterfaceLoader{}
}
func (p *ParentLoader) LoadingAnything() bool {
	return p.PsmlLoader.IsLoading() || p.PdmlLoader.IsLoading() || p.InterfaceLoader.IsLoading()
}
func (p *ParentLoader) InterfaceFile() string {
	return p.ifaceFile
}
func (p *ParentLoader) DisplayFilter() string {
	return p.displayFilter
}
func (p *ParentLoader) CaptureFilter() string {
	return p.captureFilter
}
func (p *ParentLoader) TurnOffPipe() {
	if p.PsmlLoader.PcapPsml != p.PdmlLoader.PcapPdml {
		log.Infof("Switching from interface/fifo mode to file mode")
		p.PsmlLoader.PcapPsml = p.PdmlLoader.PcapPdml
	}
}
func (p *ParentLoader) PacketSources() []IPacketSource {
	return p.psrcs
}
func (p *ParentLoader) PsmlStoppedDeliberately() bool {
	return p.psmlStoppedDeliberately_
}
func (p *ParentLoader) TailStoppedDeliberately() bool {
	return p.tailStoppedDeliberately
}
func (p *ParentLoader) LoadWasCancelled() bool {
	return p.loadWasCancelled
}
func (p *ParentLoader) Commands() ILoaderCmds {
	return p.cmds
}
func (p *ParentLoader) Context() context.Context {
	return p.mainCtx
}
func (p *ParentLoader) MainRun(fn gowid.RunFunction) {
	p.runner.Run(fn)
}
func (c *ParentLoader) CloseMain() {
	c.psmlStoppedDeliberately_ = true
	c.pdmlStoppedDeliberately_ = true
	if c.mainCancelFn != nil {
		c.mainCancelFn()
		c.mainCancelFn = nil
	}
}
func (c *ParentLoader) StopLoadPsmlAndIface(cb interface{}) {
	log.Infof("Requested stop psml + iface")
	c.psmlStoppedDeliberately_ = true
	c.loadWasCancelled = true
	c.stopTail()
	c.stopLoadPsml()
	c.stopLoadIface()
}
func (c *PacketLoader) Reload(filter string, cb interface{}, app gowid.IApp) {
	c.stopTail()
	c.stopLoadPsml()
	c.stopLoadPdml()
	OpsChan <- gowid.RunFunction(func(app gowid.IApp) {
		c.RenewPsmlLoader()
		c.RenewPdmlLoader()
		handleClear(NoneCode, app, cb)
		c.displayFilter = filter
		log.Infof("Applying display filter '%s'", filter)
		c.loadPsmlSync(c.InterfaceLoader, c, cb, app)
	})
}
func (c *PacketLoader) LoadPcap(pcap string, displayFilter string, cb interface{}, app gowid.IApp) {
	log.Infof("Requested pcap file load for '%v'", pcap)
	curDisplayFilter := displayFilter
	if c.Pcap() == pcap && c.DisplayFilter() == curDisplayFilter {
		log.Infof("No operation - same pcap and filter.")
		HandleError(NoneCode, app, fmt.Errorf("Same pcap and filter - nothing to do."), cb)
	} else {
		c.stopTail()
		c.stopLoadPsml()
		c.stopLoadPdml()
		c.stopLoadIface()
		OpsChan <- gowid.RunFunction(func(app gowid.IApp) {
			handleClear(NoneCode, app, cb)
			c.Renew()
			c.psrcs = []IPacketSource{FileSource{Filename: pcap}}
			c.ifaceFile = ""
			c.PcapPsml = pcap
			c.PcapPdml = pcap
			c.PcapPcap = pcap
			c.displayFilter = displayFilter
			handleNewSource(NoneCode, app, cb)
			log.Infof("Starting new pcap file load '%s'", pcap)
			c.loadPsmlSync(nil, c.ParentLoader, cb, app)
		})
	}
}