chore: release v0.23.2
This commit is contained in:
@@ -9121,6 +9121,49 @@ func (a *App) GetLogFilePath() string {
|
||||
return applog.Path()
|
||||
}
|
||||
|
||||
// TailLogFile returns the END of the diagnostic log — the last maxBytes, cut
|
||||
// back to a line boundary so the first line is never a fragment.
|
||||
//
|
||||
// The tail, not the file: it rotates at 10 MB, and the live viewer polls this
|
||||
// every second. Shipping megabytes across the Wails bridge on a timer would cost
|
||||
// more than the whole rest of the UI.
|
||||
func (a *App) TailLogFile(maxBytes int) (string, error) {
|
||||
p := applog.Path()
|
||||
if p == "" {
|
||||
return "", fmt.Errorf("log file not initialised")
|
||||
}
|
||||
if maxBytes <= 0 || maxBytes > 4*1024*1024 {
|
||||
maxBytes = 256 * 1024
|
||||
}
|
||||
f, err := os.Open(p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
fi, err := f.Stat()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
start := int64(0)
|
||||
if fi.Size() > int64(maxBytes) {
|
||||
start = fi.Size() - int64(maxBytes)
|
||||
}
|
||||
if _, err := f.Seek(start, io.SeekStart); err != nil {
|
||||
return "", err
|
||||
}
|
||||
buf, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
s := string(buf)
|
||||
if start > 0 {
|
||||
if i := strings.IndexByte(s, '\n'); i >= 0 {
|
||||
s = s[i+1:]
|
||||
}
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// UILog lets the frontend write to the same diagnostic log as the backend.
|
||||
//
|
||||
// Frontend-only logic (entry-strip auto-fill, debounce ordering, which field the
|
||||
@@ -11377,13 +11420,18 @@ func (a *App) consumeUDPEvents() {
|
||||
// after the configured duration. De-duped per call in the Flex backend.
|
||||
if a.catFlexDecodeSpots && a.cat != nil {
|
||||
now := time.Now()
|
||||
if t, seen := lastDecodeSpot[ev.DecodeCall]; seen && now.Sub(t) < decodeSpotWindow {
|
||||
// Key by call AND 100 kHz slot, not by call alone: with two
|
||||
// receivers running (50.313 and 50.400, say) a station heard on
|
||||
// both is two legitimate spots on two panadapters, and a
|
||||
// call-only key threw the second away.
|
||||
key := fmt.Sprintf("%s@%d", ev.DecodeCall, ev.DecodeFreqHz/100_000)
|
||||
if t, seen := lastDecodeSpot[key]; seen && now.Sub(t) < decodeSpotWindow {
|
||||
continue // spotted this call very recently — don't re-hammer the radio
|
||||
}
|
||||
if len(lastDecodeSpot) > 4000 {
|
||||
lastDecodeSpot = map[string]time.Time{} // bound memory on long sessions
|
||||
}
|
||||
lastDecodeSpot[ev.DecodeCall] = now
|
||||
lastDecodeSpot[key] = now
|
||||
secs := a.catFlexDecodeSecs
|
||||
if secs <= 0 {
|
||||
secs = 120
|
||||
|
||||
Reference in New Issue
Block a user