mirror of
https://github.com/skinnyrad/Lora-Scanner.git
synced 2026-11-03 20:32:44 +01:00
76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
// Package api wires the HTTP surface: /api/* JSON + WebSocket, everything
|
|
// else falls through to the embedded single-page app.
|
|
package api
|
|
|
|
import (
|
|
"io/fs"
|
|
"net/http"
|
|
"path"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/skinnyrad/Lora-Scanner/internal/frames"
|
|
"github.com/skinnyrad/Lora-Scanner/internal/gateway"
|
|
"github.com/skinnyrad/Lora-Scanner/internal/hub"
|
|
"github.com/skinnyrad/Lora-Scanner/internal/serial"
|
|
)
|
|
|
|
type Server struct {
|
|
Serial *serial.Manager
|
|
Hub *hub.Hub
|
|
Frames *frames.Store
|
|
Config *gateway.Config
|
|
Scraper *gateway.Scraper
|
|
UI fs.FS // contents of dist/, rooted at index.html
|
|
}
|
|
|
|
func (s *Server) Router() *gin.Engine {
|
|
r := gin.New()
|
|
r.Use(gin.Logger(), gin.Recovery())
|
|
|
|
api := r.Group("/api")
|
|
api.GET("/ports", s.ports)
|
|
api.GET("/transceivers", s.transceiversList)
|
|
api.POST("/transceivers", s.transceiverAdd)
|
|
api.DELETE("/transceivers/:id", s.transceiverRemove)
|
|
api.POST("/transceivers/:id/transmit", s.transceiverTransmit)
|
|
api.GET("/transceivers/:id/beacon", s.beaconGet)
|
|
api.POST("/transceivers/:id/beacon", s.beaconStart)
|
|
api.DELETE("/transceivers/:id/beacon", s.beaconStop)
|
|
api.GET("/gateways", s.gatewaysGet)
|
|
api.POST("/gateways", s.gatewayAdd)
|
|
api.DELETE("/gateways/:ip", s.gatewayRemove)
|
|
api.GET("/gateways/status", s.gatewaysStatus)
|
|
api.GET("/gateways/poll", s.pollGet)
|
|
api.PUT("/gateways/poll", s.pollPut)
|
|
api.GET("/frames", s.framesGet)
|
|
api.DELETE("/frames", s.framesClear)
|
|
api.GET("/frames.csv", s.framesCSV)
|
|
api.GET("/devices", s.devicesGet)
|
|
api.GET("/ws", s.ws)
|
|
|
|
r.NoRoute(s.noRoute)
|
|
return r
|
|
}
|
|
|
|
func (s *Server) noRoute(c *gin.Context) {
|
|
p := c.Request.URL.Path
|
|
if p == "/api" || strings.HasPrefix(p, "/api/") {
|
|
c.JSON(http.StatusNotFound, gin.H{"error": "not found"})
|
|
return
|
|
}
|
|
name := strings.TrimPrefix(path.Clean(p), "/")
|
|
if name != "" {
|
|
if info, err := fs.Stat(s.UI, name); err == nil && !info.IsDir() {
|
|
c.FileFromFS(name, http.FS(s.UI))
|
|
return
|
|
}
|
|
}
|
|
index, err := fs.ReadFile(s.UI, "index.html")
|
|
if err != nil {
|
|
c.String(http.StatusServiceUnavailable, "frontend not built: run `make web`")
|
|
return
|
|
}
|
|
c.Data(http.StatusOK, "text/html; charset=utf-8", index)
|
|
}
|