package main import ( "bytes" "flag" "log" "net" "os" "path/filepath" "google.golang.org/grpc" "gopkg.in/yaml.v3" statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1" "github.com/bergabruh/stats-gateway/internal/auth" "github.com/bergabruh/stats-gateway/internal/service" "github.com/bergabruh/stats-gateway/internal/storage" "github.com/bergabruh/stats-gateway/internal/tunnel" ) func main() { addr := flag.String("addr", "127.0.0.1:50051", "listen address") dbPath := flag.String("db", "/var/lib/stats-gateway/stats.db", "sqlite path") cfgDir := flag.String("config-dir", "/etc/stats-gateway", "config dir (jwt.key, tunnel.yaml, revoked.txt)") flag.Parse() st, err := storage.Open(*dbPath) if err != nil { log.Fatalf("storage: %v", err) } defer st.Close() secret, err := os.ReadFile(filepath.Join(*cfgDir, "jwt.key")) if err != nil { log.Fatalf("read jwt.key: %v", err) } secret = bytes.TrimSpace(secret) cfgBytes, err := os.ReadFile(filepath.Join(*cfgDir, "tunnel.yaml")) if err != nil { log.Fatalf("read tunnel.yaml: %v", err) } var tunnelCfg struct { Egress tunnel.EgressConfig `yaml:"egress"` } if err := yaml.Unmarshal(cfgBytes, &tunnelCfg); err != nil { log.Fatalf("parse tunnel.yaml: %v", err) } revoked, err := auth.LoadRevokedFile(filepath.Join(*cfgDir, "revoked.txt")) if err != nil { log.Fatalf("load revoked: %v", err) } verifier := auth.NewVerifier(secret, revoked) handler := tunnel.NewHandler(tunnelCfg.Egress) lis, err := net.Listen("tcp", *addr) if err != nil { log.Fatalf("listen: %v", err) } srv := grpc.NewServer() statsv1.RegisterSpeedStatusServer(srv, service.New(st, verifier, handler)) log.Printf("stats-gateway listening on %s (egress=%d targets, rate=%.0fmbps)", *addr, len(tunnelCfg.Egress.Allowed), tunnelCfg.Egress.RateMbps) if err := srv.Serve(lis); err != nil { log.Fatalf("serve: %v", err) } }