in pcap-cli/internal/transformer/translator_worker.go [542:614]
func (w *pcapTranslatorWorker) Run(ctx context.Context) (buffer interface{}) {
defer func() {
if r := recover(); r != nil {
transformerLogger.Printf("%s @translator | panic: %s\n%s\n",
*w.loggerPrefix, r, string(debug.Stack()))
buffer = nil
}
}()
// fail open:
// - if there aren't any filters, continue with translation.
// fail fast:
// - do not translate any layers before enforcing filters.
if w.filters != nil && !w.shouldTranslate(ctx) {
return nil
}
var _buffer fmt.Stringer = nil
select {
case <-ctx.Done():
_buffer = nil
default:
_buffer = w.translator.next(ctx, w.iface, w.serial, w.packet)
}
if _buffer == nil {
transformerLogger.Printf("%s @translator | failed", *w.loggerPrefix)
buffer = nil
return nil
}
translations := make(chan fmt.Stringer, packetLayerTranslatorsSize)
var wg sync.WaitGroup
// number of layers to be translated
packetLayers := w.pkt(ctx).Layers()
wg.Add(len(packetLayers))
go func(wg *sync.WaitGroup) {
wg.Wait()
close(translations)
}(&wg)
// O(N); N is the number of layers available in the packet
// this is a faster implementation as there is no layer discovery;
// layers are translated on-demand based on the packet's contents.
for i, l := range packetLayers {
// translate layers concurrently:
// - layers must know nothing about each other
go w.translate(ctx, i, l, translations, &wg)
}
for translation := range translations {
// translations are `nil` if layer is not available
if translation != nil {
// see: https://github.com/Jeffail/gabs?tab=readme-ov-file#merge-two-containers
_buffer, _ = w.translator.merge(ctx, _buffer, translation)
}
}
select {
case <-ctx.Done():
// skip `finalize` deliver translation as-is
transformerLogger.Printf("%s @translator | incomplete", *w.loggerPrefix)
default:
// `finalize` is the only method that is allowed to work across layers
_buffer, _ = w.translator.finalize(ctx, w.ifaces, w.iface, w.serial, w.packet, w.conntrack, _buffer)
}
buffer = &_buffer
return &_buffer
}