github.com/lirm/aeron-go@v0.0.0-20230415210743-920325491dc4/archive/recordingevents.go (about)

     1  // Copyright (C) 2021-2022 Talos, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  // http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package archive
    16  
    17  import (
    18  	"bytes"
    19  	"fmt"
    20  
    21  	"github.com/lirm/aeron-go/aeron"
    22  	"github.com/lirm/aeron-go/aeron/atomic"
    23  	"github.com/lirm/aeron-go/aeron/logbuffer"
    24  	"github.com/lirm/aeron-go/aeron/logbuffer/term"
    25  	"github.com/lirm/aeron-go/archive/codecs"
    26  )
    27  
    28  // RecordingEventsAdapter is used to poll for recording events on a subscription.
    29  type RecordingEventsAdapter struct {
    30  	Subscription *aeron.Subscription
    31  	Enabled      bool
    32  	archive      *Archive // link to parent
    33  
    34  	pollFunc              term.FragmentHandler
    35  	handlerWithListeners  FragmentHandlerWithListeners
    36  	reFragmentHandlerFunc FragmentHandlerWithListeners
    37  	buf                   *bytes.Buffer
    38  	marshaller            *codecs.SbeGoMarshaller
    39  }
    40  
    41  // FragmentHandlerWithListeners provides a FragmentHandler with ArchiveListeners
    42  type FragmentHandlerWithListeners func(listeners *ArchiveListeners, buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header)
    43  
    44  // PollWithContext the aeron subscription handler.
    45  // If you pass it a nil handler it will use the builtin and call the Listeners
    46  // If you ask for 0 fragments it will only return one fragment (if available)
    47  func (rea *RecordingEventsAdapter) PollWithContext(handler FragmentHandlerWithListeners, fragmentLimit int) int {
    48  	if rea.pollFunc == nil {
    49  		rea.prealloc()
    50  	}
    51  
    52  	// Update our globals in case they've changed so we use the current state in our callback
    53  	rangeChecking = rea.archive.Options.RangeChecking
    54  
    55  	if handler != nil {
    56  		rea.handlerWithListeners = handler
    57  	} else {
    58  		rea.handlerWithListeners = rea.reFragmentHandlerFunc
    59  	}
    60  	if fragmentLimit == 0 {
    61  		fragmentLimit = 1
    62  	}
    63  	return rea.Subscription.Poll(rea.pollFunc, fragmentLimit)
    64  }
    65  
    66  func (rea *RecordingEventsAdapter) prealloc() {
    67  	rea.pollFunc = func(buf *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) {
    68  		rea.handlerWithListeners(rea.archive.Listeners, buf, offset, length, header)
    69  	}
    70  	rea.reFragmentHandlerFunc = rea.reFragmentHandler
    71  }
    72  
    73  func (rea *RecordingEventsAdapter) reFragmentHandler(listeners *ArchiveListeners, buffer *atomic.Buffer, offset int32, length int32, header *logbuffer.Header) {
    74  	var hdr codecs.SbeGoMessageHeader
    75  
    76  	if rea.buf == nil {
    77  		rea.buf = new(bytes.Buffer)
    78  	}
    79  	buf := rea.buf
    80  	rea.buf.Reset()
    81  	buffer.WriteBytes(rea.buf, offset, length)
    82  
    83  	if rea.marshaller == nil {
    84  		rea.marshaller = codecs.NewSbeGoMarshaller()
    85  	}
    86  	marshaller := rea.marshaller
    87  
    88  	if err := hdr.Decode(marshaller, buf); err != nil {
    89  		// Not much to be done here as we can't correlate
    90  		err2 := fmt.Errorf("reFragmentHandler() failed to decode control message header: %w", err)
    91  		// Call the global error handler, ugly but it's all we've got
    92  		if listeners.ErrorListener != nil {
    93  			listeners.ErrorListener(err2)
    94  		}
    95  	}
    96  
    97  	switch hdr.TemplateId {
    98  	case codecIds.recordingStarted:
    99  		var recordingStarted = new(codecs.RecordingStarted)
   100  		logger.Debugf("Received RecordingStarted: length %d", buf.Len())
   101  		if err := recordingStarted.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil {
   102  			err2 := fmt.Errorf("Decode() of RecordingStarted failed: %w", err)
   103  			if listeners.ErrorListener != nil {
   104  				listeners.ErrorListener(err2)
   105  			}
   106  		} else {
   107  			// logger.Debugf("RecordingStarted: %#v\n", recordingStarted)
   108  			// Call the Listener
   109  			if listeners.RecordingEventStartedListener != nil {
   110  				listeners.RecordingEventStartedListener(recordingStarted)
   111  			}
   112  		}
   113  
   114  	case codecIds.recordingProgress:
   115  		var recordingProgress = new(codecs.RecordingProgress)
   116  		logger.Debugf("Received RecordingProgress: length %d", buf.Len())
   117  		if err := recordingProgress.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil {
   118  			err2 := fmt.Errorf("Decode() of RecordingProgress failed: %w", err)
   119  			if listeners.ErrorListener != nil {
   120  				listeners.ErrorListener(err2)
   121  			}
   122  		} else {
   123  			logger.Debugf("RecordingProgress: %#v", recordingProgress)
   124  			// Call the Listener
   125  			if listeners.RecordingEventProgressListener != nil {
   126  				listeners.RecordingEventProgressListener(recordingProgress)
   127  			}
   128  		}
   129  
   130  	case codecIds.recordingStopped:
   131  		var recordingStopped = new(codecs.RecordingStopped)
   132  		logger.Debugf("Received RecordingStopped: length %d", buf.Len())
   133  		if err := recordingStopped.Decode(marshaller, buf, hdr.Version, hdr.BlockLength, rangeChecking); err != nil {
   134  			err2 := fmt.Errorf("Decode() of RecordingStopped failed: %w", err)
   135  			if listeners.ErrorListener != nil {
   136  				listeners.ErrorListener(err2)
   137  			}
   138  		} else {
   139  			logger.Debugf("RecordingStopped: %#v", recordingStopped)
   140  			// Call the Listener
   141  			if listeners.RecordingEventStoppedListener != nil {
   142  				listeners.RecordingEventStoppedListener(recordingStopped)
   143  			}
   144  		}
   145  
   146  	default:
   147  		logger.Errorf("Insert decoder for type: %d", hdr.TemplateId)
   148  	}
   149  }