Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

112 Zeilen
2.1KB

  1. package events
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "errors"
  6. "io"
  7. "os"
  8. "time"
  9. "sdr-visual-suite/internal/detector"
  10. )
  11. const (
  12. defaultLimit = 200
  13. maxLimit = 2000
  14. readChunk = 64 * 1024
  15. )
  16. // ReadRecent reads the newest events from a JSONL file.
  17. // If since is non-zero, older events (by End time) are skipped.
  18. func ReadRecent(path string, limit int, since time.Time) ([]detector.Event, error) {
  19. if limit <= 0 {
  20. limit = defaultLimit
  21. }
  22. if limit > maxLimit {
  23. limit = maxLimit
  24. }
  25. file, err := os.Open(path)
  26. if err != nil {
  27. if errors.Is(err, os.ErrNotExist) {
  28. return nil, nil
  29. }
  30. return nil, err
  31. }
  32. defer file.Close()
  33. info, err := file.Stat()
  34. if err != nil {
  35. return nil, err
  36. }
  37. if info.Size() == 0 {
  38. return nil, nil
  39. }
  40. lines, err := readLinesReverse(file, info.Size(), limit)
  41. if err != nil {
  42. return nil, err
  43. }
  44. events := make([]detector.Event, 0, len(lines))
  45. for _, line := range lines {
  46. var ev detector.Event
  47. if err := json.Unmarshal([]byte(line), &ev); err != nil {
  48. continue
  49. }
  50. if !since.IsZero() && ev.End.Before(since) {
  51. break
  52. }
  53. events = append(events, ev)
  54. }
  55. for i, j := 0, len(events)-1; i < j; i, j = i+1, j-1 {
  56. events[i], events[j] = events[j], events[i]
  57. }
  58. return events, nil
  59. }
  60. func readLinesReverse(file *os.File, size int64, limit int) ([]string, error) {
  61. pos := size
  62. remainder := []byte{}
  63. lines := make([]string, 0, limit)
  64. for pos > 0 && len(lines) < limit {
  65. chunkSize := int64(readChunk)
  66. if chunkSize > pos {
  67. chunkSize = pos
  68. }
  69. pos -= chunkSize
  70. buf := make([]byte, chunkSize)
  71. n, err := file.ReadAt(buf, pos)
  72. if err != nil && !errors.Is(err, io.EOF) {
  73. return nil, err
  74. }
  75. buf = buf[:n]
  76. data := append(buf, remainder...)
  77. i := len(data)
  78. for i > 0 && len(lines) < limit {
  79. j := bytes.LastIndexByte(data[:i], '\n')
  80. if j == -1 {
  81. break
  82. }
  83. line := bytes.TrimSpace(data[j+1 : i])
  84. if len(line) > 0 {
  85. lines = append(lines, string(line))
  86. }
  87. i = j
  88. }
  89. remainder = data[:i]
  90. }
  91. if len(lines) < limit {
  92. line := bytes.TrimSpace(remainder)
  93. if len(line) > 0 {
  94. lines = append(lines, string(line))
  95. }
  96. }
  97. return lines, nil
  98. }