Корректировка данных в логах

This commit is contained in:
Maxim
2026-06-18 14:40:59 +03:00
parent 9bbcd67065
commit 18d005c933
4 changed files with 370 additions and 150 deletions

View File

@@ -219,95 +219,163 @@ func (a *API) HandleLogEvents(w http.ResponseWriter, r *http.Request) {
}
// HandleLogData - чтение данных из конкретного bin файла
// HandleLogData - чтение данных из конкретного bin файла с пагинацией
func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
if filename == "" {
http.Error(w, "отсутствует параметр file", 400)
return
}
filename := r.URL.Query().Get("file")
if filename == "" {
http.Error(w, "отсутствует параметр file", 400)
return
}
// Защита от path traversal
filename = filepath.Base(filename)
dataDir, err := logger.GetDataLogsDir()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
// Параметры пагинации
page := 1
if p := r.URL.Query().Get("page"); p != "" {
if parsed, err := strconv.Atoi(p); err == nil && parsed > 0 {
page = parsed
}
}
filePath := filepath.Join(dataDir, filename)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
http.Error(w, "файл не найден", 404)
return
}
pageSize := 100
if ps := r.URL.Query().Get("page_size"); ps != "" {
if parsed, err := strconv.Atoi(ps); err == nil && parsed > 0 {
pageSize = parsed
}
}
// Читаем бинарный файл
f, err := os.Open(filePath)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
defer f.Close()
// Защита от path traversal
filename = filepath.Base(filename)
dataDir, err := logger.GetDataLogsDir()
if err != nil {
http.Error(w, err.Error(), 500)
return
}
filePath := filepath.Join(dataDir, filename)
if _, err := os.Stat(filePath); os.IsNotExist(err) {
http.Error(w, "файл не найден", 404)
return
}
// Читаем бинарный файл
f, err := os.Open(filePath)
if err != nil {
http.Error(w, err.Error(), 500)
return
}
defer f.Close()
type Sample struct {
Timestamp int64 `json:"ts"`
Time string `json:"time"`
Value byte `json:"value"`
Count byte `json:"count"`
Strength byte `json:"strength"`
StrengthName string `json:"strength_name"`
Amplitude byte `json:"amplitude"` // Старшие 2 бита (0-3)
Signal byte `json:"signal"` // Младшие 6 бит (0-63)
StrengthName string `json:"strength_name"`
}
var samples []Sample
// Сначала читаем все сэмплы
var allSamples []Sample
buf := make([]byte, 9) // 8 байт timestamp + 1 байт value
for {
n, err := f.Read(buf)
if err == io.EOF {
break
}
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if n < 9 {
continue
}
for {
n, err := f.Read(buf)
if err == io.EOF {
break
}
if err != nil {
http.Error(w, err.Error(), 500)
return
}
if n < 9 {
continue
}
ts := int64(binary.LittleEndian.Uint64(buf[0:8]))
ts := int64(binary.LittleEndian.Uint64(buf[0:8]))
value := buf[8]
data := logger.ParseGPIO(value)
amplitude := (value >> 6) & 0x3
signal := value & 0x3F
samples = append(samples, Sample{
allSamples = append(allSamples, Sample{
Timestamp: ts,
Time: time.UnixMicro(ts).Format("02.01.2006 15:04:05"),
Time: time.UnixMicro(ts).Format("02.01.2006 15:04:05"),
Value: value,
Count: data.Count,
Strength: data.Strength,
StrengthName: logger.GetStrengthName(data.Strength),
Amplitude: (value >> 6) & 0x3, // Старшие 2 бита (0-3) - АМПЛИТУДА
Signal: value & 0x3F, // Младшие 6 бит (0-63) - СИГНАЛ
Amplitude: amplitude,
Signal: signal,
StrengthName: logger.GetStrengthName(amplitude),
})
}
}
// Ограничиваем количество точек для производительности
if len(samples) > 10000 {
step := len(samples) / 10000
var filtered []Sample
for i := 0; i < len(samples); i += step {
filtered = append(filtered, samples[i])
}
samples = filtered
}
total := len(allSamples)
totalPages := (total + pageSize - 1) / pageSize
if totalPages == 0 {
totalPages = 1
}
writeJSON(w, map[string]any{
"filename": filename,
"total": len(samples),
"samples": samples,
})
// Корректируем номер страницы
if page > totalPages {
page = totalPages
}
if page < 1 {
page = 1
}
// Страница 1 = самые новые записи (с конца файла)
// Новые записи в конце файла, поэтому начинаем с конца
start := total - page*pageSize
if start < 0 {
start = 0
}
end := start + pageSize
if end > total {
end = total
}
// Получаем сэмплы для текущей страницы
var pageSamples []Sample
if start < total && start >= 0 {
pageSamples = allSamples[start:end]
} else {
pageSamples = []Sample{}
}
// Разворачиваем, чтобы новые были сверху
var reversedSamples []Sample
for i := len(pageSamples) - 1; i >= 0; i-- {
reversedSamples = append(reversedSamples, pageSamples[i])
}
// Считаем статистику (без суммы объектов)
amplitudeOver0 := 0
signalOver10 := 0
for _, s := range allSamples {
if s.Amplitude > 0 {
amplitudeOver0++
}
if s.Signal > 10 {
signalOver10++
}
}
writeJSON(w, map[string]any{
"filename": filename,
"total": total,
"page": page,
"page_size": pageSize,
"total_pages": totalPages,
"has_previous": page > 1,
"has_next": page < totalPages,
"start_index": start + 1,
"end_index": end,
"samples": reversedSamples,
"stats": map[string]any{
"total_points": total,
"amplitude_over_0": amplitudeOver0,
"signal_over_10": signalOver10,
},
"order": "newest_first",
})
}
func (a *API) HandleHealth(w http.ResponseWriter, r *http.Request) {