Доработка документации

This commit is contained in:
Maxim
2026-07-17 15:57:05 +03:00
parent 5b403d7ee4
commit 9fa3d172a8
22 changed files with 1371 additions and 481 deletions

View File

@@ -1,3 +1,7 @@
// gpio-monitor-server — HTTP-сервер мониторинга GPIO-шины Raspberry Pi.
// Читает поток байт из FIFO pipe, хранит их в кольцевом буфере и бинарных
// почасовых логах, отдаёт JSON API и встроенный веб-дашборд на :8080.
// Конфигурация — только флагами командной строки (см. main или docs/operations.md).
package main
import (
@@ -28,6 +32,8 @@ import (
//go:embed web/dist web/css web/fonts web/*.html web/*.png
var webFiles embed.FS
// API — состояние HTTP-хендлеров: кольцевой буфер, время старта сервера
// и монитор звука. Спецификация ответов — docs/api.md.
type API struct {
buf *adapter.RingBuffer
startTime time.Time
@@ -39,7 +45,8 @@ func writeJSON(w http.ResponseWriter, v any) {
json.NewEncoder(w).Encode(v)
}
// HandleLogFiles - список доступных лог-файлов
// HandleLogFiles отдаёт список бинарных лог-файлов gpio-*.bin,
// отсортированный по времени изменения (новые первыми).
func (a *API) HandleLogFiles(w http.ResponseWriter, r *http.Request) {
dataDir, err := logger.GetDataLogsDir()
if err != nil {
@@ -105,7 +112,8 @@ func (a *API) HandleLogFiles(w http.ResponseWriter, r *http.Request) {
writeJSON(w, result)
}
// HandleLogEvents - чтение событий с пагинацией
// HandleLogEvents отдаёт события из events_human.log с пагинацией
// (page, page_size; страница 1 — самые новые).
func (a *API) HandleLogEvents(w http.ResponseWriter, r *http.Request) {
// Параметры пагинации
page := 1
@@ -220,7 +228,9 @@ func (a *API) HandleLogEvents(w http.ResponseWriter, r *http.Request) {
}
// HandleLogData - чтение данных из конкретного bin файла с пагинацией
// HandleLogData отдаёт сэмплы одного .bin-файла (параметр file) с пагинацией
// (page, page_size; страница 1 — самые новые). Формат записи — 9 байт,
// см. docs/data-formats.md. Файл читается в память целиком.
func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
filename := r.URL.Query().Get("file")
if filename == "" {
@@ -400,6 +410,8 @@ func (a *API) HandleLogData(w http.ResponseWriter, r *http.Request) {
})
}
// HandleHealth отдаёт статус сервера: связь с pipe (пороги 15 с и 3 с),
// uptime, статистику буфера и уровень звука.
func (a *API) HandleHealth(w http.ResponseWriter, r *http.Request) {
latest, ok := a.buf.GetLatest()
idle := time.Since(a.buf.LastWriteTime())
@@ -429,6 +441,7 @@ func (a *API) HandleHealth(w http.ResponseWriter, r *http.Request) {
})
}
// HandleLatest отдаёт последний байт и до 10 предыдущих (от старых к новым).
func (a *API) HandleLatest(w http.ResponseWriter, r *http.Request) {
latest, ok := a.buf.GetLatest()
if !ok {
@@ -442,6 +455,7 @@ func (a *API) HandleLatest(w http.ResponseWriter, r *http.Request) {
})
}
// HandleHistory отдаёт до 300 последних байт для графика (от старых к новым).
func (a *API) HandleHistory(w http.ResponseWriter, r *http.Request) {
raw := a.buf.GetLast(300)
@@ -455,6 +469,9 @@ func (a *API) HandleHistory(w http.ResponseWriter, r *http.Request) {
})
}
// HandleStream отдаёт статус видеопотока камеры. Внимание: доступность
// проверяется по захардкоженному localhost:1984 без учёта флага -camera-url
// (известное поведение, docs/tech-debt.md).
func (a *API) HandleStream(w http.ResponseWriter, r *http.Request) {
// Проверяем доступность MJPEG потока в go2rtc
resp, err := http.Get("http://localhost:1984/api/streams?src=cam_mjpeg")
@@ -470,7 +487,8 @@ func (a *API) HandleStream(w http.ResponseWriter, r *http.Request) {
})
}
// Прокси для MJPEG потока — просто ретранслирует готовый поток из go2rtc
// handleCamProxy — НЕ ИСПОЛЬЗУЕТСЯ: роутер вызывает handleCamProxyWithURL,
// этот вариант с захардкоженным URL остался как мёртвый код (docs/tech-debt.md).
func handleCamProxy(w http.ResponseWriter, r *http.Request) {
log.Printf("[cam] запрос от %s", r.RemoteAddr)
@@ -519,6 +537,8 @@ func handleCamProxy(w http.ResponseWriter, r *http.Request) {
}
}
// cors разрешает кросс-доменные GET-запросы с любых источников
// (рассчитано на доверенную локальную сеть).
func cors(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
@@ -703,7 +723,8 @@ func main() {
log.Fatal(http.ListenAndServe(*serverPort, nil))
}
// handleCamProxyWithURL проксирует MJPEG поток с указанным URL
// handleCamProxyWithURL проксирует MJPEG-поток с cameraURL (флаг -camera-url),
// ретранслируя заголовки и сбрасывая буфер после каждого чанка 32 КБ.
func handleCamProxyWithURL(w http.ResponseWriter, r *http.Request, cameraURL string) {
log.Printf("[cam] запрос от %s к %s", r.RemoteAddr, cameraURL)

View File

@@ -1,37 +1,56 @@
# GPIO Monitor Web Interface
Веб-интерфейс для мониторинга GPIO и видеопотока с камеры.
Веб-интерфейс дашборда GPIO Monitor: мониторинг в реальном времени, просмотр исторических логов, видеопоток камеры. Подробная документация фронтенда — [docs/frontend.md](../../../docs/frontend.md).
## Требования
- Node.js 20.x или выше
- npm 10.x или выше
- Go 1.21
Node.js нужен **только для компиляции TypeScript** — в рантайме фронтенд не имеет зависимостей и раздаётся Go-сервером из встроенных файлов.
### 1. Установка Node.js и npm на Raspberry Pi
#### Добавление официального репозитория NodeSource
```curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -```
#### Установка Node.js и npm
```sudo apt install -y nodejs```
#### Проверка установки
```node --version # v20.20.2```
```npm --version # 10.8.2```
### 2.Инициализация npm проекта
#### Переход в директорию с веб-файлами
```cd ~/temp/golang/cmd/server/web```
#### Инициализация package.json
```npm init -y```
#### Установка TypeScript и типов Node.js
```npm install -D typescript @types/node```
## Установка Node.js на Raspberry Pi
```bash
chmod +x node_modules/.bin/tsc
```
# Официальный репозиторий NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs
# Проверка
node --version # v20.x
npm --version # 10.x
```
## Сборка
`package.json` и `tsconfig.json` уже в репозитории — инициализировать проект не нужно, только установить зависимости:
```bash
cd cmd/server/web
npm install # однократно
npm run build # tsc: js/*.ts → dist/*.js
npm run watch # пересборка при изменениях
npm run clean # удалить dist/
```
Проще из корня проекта: `make build-frontend` (сам выполнит `npm install` при необходимости).
> **Важно:** каталог `dist/` не хранится в git, но обязателен для сборки Go-сервера (`go:embed`). Всегда собирайте фронтенд до `go build` — подробности в [docs/development.md](../../../docs/development.md#порядок-сборки).
## Структура
```
web/
├── js/ # TypeScript-исходники (10 модулей, см. docs/frontend.md)
├── dist/ # Скомпилированный JS (генерируется tsc)
├── css/ # Стили
├── fonts/ # Шрифты
├── index.html # Редирект на дашборд
├── dashboard.html # Мониторинг в реальном времени
├── logs.html # Просмотр исторических логов
├── favicon.png
├── package.json
└── tsconfig.json
```
Карта модулей `js/`, взаимодействие с API и цикл разработки — [docs/frontend.md](../../../docs/frontend.md). Спецификация API сервера — [docs/api.md](../../../docs/api.md).