163 lines
3.5 KiB
Go
163 lines
3.5 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log/slog"
|
|
"net"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
|
|
"forge.cadoles.com/cadoles/go-emlid/reach/discovery"
|
|
socketio "github.com/googollee/go-socket.io"
|
|
"github.com/grandcat/zeroconf"
|
|
"github.com/pkg/errors"
|
|
sloghttp "github.com/samber/slog-http"
|
|
"github.com/wlynxg/anet"
|
|
)
|
|
|
|
func main() {
|
|
ctx := context.Background()
|
|
|
|
server, err := startHTTPServer(ctx)
|
|
if err != nil {
|
|
slog.Error("could not start http server", slog.Any("error", errors.WithStack(err)))
|
|
os.Exit(1)
|
|
}
|
|
|
|
defer server.Close()
|
|
|
|
service, err := startMDNSService(ctx)
|
|
if err != nil {
|
|
slog.Error("could not start mdns service", slog.Any("error", errors.WithStack(err)))
|
|
os.Exit(1)
|
|
}
|
|
|
|
defer service.Shutdown()
|
|
|
|
interrupt := make(chan os.Signal, 1)
|
|
signal.Notify(interrupt, os.Interrupt)
|
|
|
|
slog.Info("Ctrl+C to interrupt")
|
|
|
|
<-interrupt
|
|
}
|
|
|
|
func startHTTPServer(ctx context.Context) (*http.Server, error) {
|
|
mux := http.NewServeMux()
|
|
|
|
sioServer := NewSocketIOServer()
|
|
go func() {
|
|
if err := sioServer.Serve(); err != nil {
|
|
slog.Error("could not serve socketio", slog.Any("error", errors.WithStack(err)))
|
|
}
|
|
}()
|
|
|
|
sioServer.OnEvent("/", "action", func(s socketio.Conn, msg map[string]any) {
|
|
slog.Info("action event", slog.Any("id", s.ID()), slog.Any("message", msg))
|
|
|
|
name, ok := msg["name"]
|
|
if !ok {
|
|
return
|
|
}
|
|
|
|
switch name {
|
|
case "reboot":
|
|
if err := s.Close(); err != nil {
|
|
slog.Error("could not close connection", slog.Any("error", errors.WithStack(err)))
|
|
}
|
|
}
|
|
})
|
|
|
|
mux.Handle("/socket.io/", sioServer)
|
|
mux.HandleFunc("GET /info", GetInfo)
|
|
mux.HandleFunc("GET /configuration", GetConfiguration)
|
|
mux.HandleFunc("POST /configuration/base_mode/base_coordinates", PostJSON)
|
|
|
|
handler := sloghttp.Recovery(mux)
|
|
handler = sloghttp.New(slog.Default())(handler)
|
|
|
|
server := &http.Server{
|
|
Addr: ":8080",
|
|
Handler: handler,
|
|
}
|
|
|
|
go func() {
|
|
defer sioServer.Close()
|
|
|
|
slog.Info("starting http server", slog.Any("address", server.Addr))
|
|
|
|
if err := server.ListenAndServe(); err != nil {
|
|
slog.Error("could not listen and serve http requests", slog.Any("error", errors.WithStack(err)))
|
|
}
|
|
}()
|
|
|
|
return server, nil
|
|
}
|
|
|
|
func startMDNSService(ctx context.Context) (*zeroconf.Server, error) {
|
|
hostname, err := os.Hostname()
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
ifaces, err := anet.Interfaces()
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
ips, err := GetLANIPv4Addrs()
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
info := []string{
|
|
fmt.Sprintf("local_name=%s", hostname),
|
|
"device=FakeReach",
|
|
"manufacturer_data=egoHIABggkMnZWSuoy0KAgAA",
|
|
}
|
|
|
|
slog.Info("announcing mdns service", slog.Any("ips", ips), slog.Any("info", info))
|
|
|
|
server, err := zeroconf.RegisterProxy("Reach", discovery.ReachService, "local.", 8080, hostname, ips, info, ifaces)
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
return server, nil
|
|
}
|
|
|
|
var (
|
|
_, lanA, _ = net.ParseCIDR("10.0.0.0/8")
|
|
_, lanB, _ = net.ParseCIDR("172.16.0.0/12")
|
|
_, lanC, _ = net.ParseCIDR("192.168.0.0/16")
|
|
)
|
|
|
|
func GetLANIPv4Addrs() ([]string, error) {
|
|
ips := make([]string, 0)
|
|
|
|
addrs, err := anet.InterfaceAddrs()
|
|
if err != nil {
|
|
return nil, errors.WithStack(err)
|
|
}
|
|
|
|
for _, address := range addrs {
|
|
if ipnet, ok := address.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
|
|
ipv4 := ipnet.IP.To4()
|
|
if ipv4 == nil {
|
|
continue
|
|
}
|
|
|
|
isLAN := lanA.Contains(ipv4) || lanB.Contains(ipv4) || lanC.Contains(ipv4)
|
|
if !isLAN {
|
|
continue
|
|
}
|
|
|
|
ips = append(ips, ipv4.String())
|
|
}
|
|
}
|
|
|
|
return ips, nil
|
|
}
|