Initial commit: GPIO monitoring server
This commit is contained in:
139
cmd/server/main.go
Normal file
139
cmd/server/main.go
Normal file
@@ -0,0 +1,139 @@
|
||||
// cmd/server/main.go
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"gpio-monitor/internal/adapter"
|
||||
)
|
||||
|
||||
// API обработчики HTTP
|
||||
type API struct {
|
||||
buf *adapter.RingBuffer
|
||||
}
|
||||
|
||||
func (a *API) HandleLatest(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
latest, ok := a.buf.GetLatest()
|
||||
if !ok {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"error": "no data yet",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// Явное преобразование в []int для читаемого JSON
|
||||
lastN := a.buf.GetLast(10)
|
||||
historyInts := make([]int, len(lastN))
|
||||
for i, v := range lastN {
|
||||
historyInts[i] = int(v)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"latest_byte": latest,
|
||||
"latest_hex": fmt.Sprintf("0x%02x", latest),
|
||||
"latest_char": string(rune(latest)),
|
||||
"history": historyInts, // теперь будет [1,2,3,...]
|
||||
"stats": a.buf.Stats(),
|
||||
})
|
||||
}
|
||||
|
||||
func (a *API) HandleNibbles(w http.ResponseWriter, r *http.Request) {
|
||||
// Для 4-битной шины — показываем последние 16 полубайт
|
||||
data := a.buf.GetLast(16)
|
||||
|
||||
nibbles := make([]map[string]interface{}, len(data))
|
||||
for i, b := range data {
|
||||
nibbles[i] = map[string]interface{}{
|
||||
"index": i,
|
||||
"value": int(b),
|
||||
"hex": fmt.Sprintf("0x%02x", b),
|
||||
"bin": fmt.Sprintf("%04b", b), // 4 бита
|
||||
"bin_full": fmt.Sprintf("%08b", b), // полный байт
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"nibbles": nibbles,
|
||||
"count": len(nibbles),
|
||||
})
|
||||
}
|
||||
|
||||
func (a *API) HandleHistory(w http.ResponseWriter, r *http.Request) {
|
||||
// Можно добавить параметр ?n=100
|
||||
n := 100
|
||||
data := a.buf.GetLast(n)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"bytes": data,
|
||||
"count": len(data),
|
||||
})
|
||||
}
|
||||
|
||||
// CORS middleware для удобства разработки
|
||||
func corsMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
|
||||
w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
|
||||
|
||||
if r.Method == "OPTIONS" {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
return
|
||||
}
|
||||
|
||||
next(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
// Инициализация
|
||||
updates := make(chan byte, 256)
|
||||
buf := adapter.NewRingBuffer(1024 * 10) // 10KB буфер
|
||||
|
||||
// Запускаем чтение stdin в фоне
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
reader := adapter.NewStdinReader(updates)
|
||||
if err := reader.Start(ctx, buf); err != nil {
|
||||
log.Fatal("Ошибка запуска читателя stdin:", err)
|
||||
}
|
||||
|
||||
// Инициализация API
|
||||
api := &API{buf: buf}
|
||||
|
||||
// HTTP маршруты (каждый только ОДИН раз!)
|
||||
http.HandleFunc("/api/latest", corsMiddleware(api.HandleLatest))
|
||||
http.HandleFunc("/api/history", corsMiddleware(api.HandleHistory))
|
||||
http.HandleFunc("/api/nibbles", corsMiddleware(api.HandleNibbles))
|
||||
|
||||
// Статические файлы для веб-интерфейса
|
||||
fs := http.FileServer(http.Dir("web"))
|
||||
http.Handle("/", fs)
|
||||
|
||||
// Запуск сервера
|
||||
log.Println("=== GPIO Monitor Server ===")
|
||||
log.Println("Сервер запущен на http://localhost:8080")
|
||||
log.Println("API endpoints:")
|
||||
log.Println(" GET /api/latest - последний байт + история")
|
||||
log.Println(" GET /api/history - последние 100 байт")
|
||||
log.Println(" GET /api/nibbles - 4-битное представление")
|
||||
log.Println("Ожидание данных из stdin...")
|
||||
log.Println("")
|
||||
|
||||
if err := http.ListenAndServe(":8080", nil); err != nil {
|
||||
log.Fatal("Ошибка сервера:", err)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user