feat: add go tcp gateway runtime
This commit is contained in:
@@ -1,8 +1,134 @@
|
||||
package main
|
||||
|
||||
import "lingniu-vehicle-ingest/go/vehicle-gateway/internal/observability"
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/signal"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/envelope"
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/eventbus"
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/gateway"
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/observability"
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/protocol/gb32960"
|
||||
"lingniu-vehicle-ingest/go/vehicle-gateway/internal/protocol/jt808"
|
||||
)
|
||||
|
||||
func main() {
|
||||
logger := observability.NewLogger("vehicle-gateway")
|
||||
logger.Info("vehicle gateway scaffold started")
|
||||
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
||||
defer stop()
|
||||
|
||||
sink, err := buildSink(logger)
|
||||
if err != nil {
|
||||
logger.Error("build sink failed", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer sink.Close()
|
||||
|
||||
protocols := []gateway.TCPProtocol{
|
||||
{
|
||||
Protocol: envelope.ProtocolGB32960,
|
||||
Addr: env("GB32960_TCP_ADDR", ":32960"),
|
||||
Extract: gb32960.ExtractFrames,
|
||||
Parse: gb32960.ParseFrame,
|
||||
},
|
||||
{
|
||||
Protocol: envelope.ProtocolJT808,
|
||||
Addr: env("JT808_TCP_ADDR", ":808"),
|
||||
Extract: jt808.ExtractFrames,
|
||||
Parse: jt808.ParseFrame,
|
||||
},
|
||||
}
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errs := make(chan error, len(protocols))
|
||||
for _, protocol := range protocols {
|
||||
server, err := gateway.NewTCPServer(gateway.TCPServerConfig{
|
||||
Protocol: protocol,
|
||||
Sink: sink,
|
||||
Logger: logger,
|
||||
ReadBufferSize: envInt("TCP_READ_BUFFER_BYTES", 64*1024),
|
||||
IdleTimeout: time.Duration(envInt("TCP_IDLE_TIMEOUT_SECONDS", 180)) * time.Second,
|
||||
MaxConnections: envInt("TCP_MAX_CONNECTIONS", 20_000),
|
||||
})
|
||||
if err != nil {
|
||||
logger.Error("build tcp server failed", "protocol", protocol.Protocol, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
if err := server.ListenAndServe(ctx); err != nil {
|
||||
errs <- err
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
logger.Info("vehicle gateway started")
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
case err := <-errs:
|
||||
logger.Error("vehicle gateway listener failed", "error", err)
|
||||
stop()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func buildSink(logger *slog.Logger) (eventbus.Sink, error) {
|
||||
brokers := splitCSV(os.Getenv("KAFKA_BROKERS"))
|
||||
if len(brokers) == 0 {
|
||||
logger.Warn("KAFKA_BROKERS is empty; using log sink")
|
||||
return eventbus.NewLogSink(logger), nil
|
||||
}
|
||||
return eventbus.NewKafkaSink(eventbus.KafkaConfig{
|
||||
Brokers: brokers,
|
||||
RawTopics: map[envelope.Protocol]string{
|
||||
envelope.ProtocolGB32960: env("KAFKA_TOPIC_GB32960_RAW", "vehicle.raw.gb32960.v1"),
|
||||
envelope.ProtocolJT808: env("KAFKA_TOPIC_JT808_RAW", "vehicle.raw.jt808.v1"),
|
||||
envelope.ProtocolYutongMQTT: env("KAFKA_TOPIC_YUTONG_MQTT_RAW", "vehicle.raw.yutong-mqtt.v1"),
|
||||
},
|
||||
UnifiedTopic: env("KAFKA_TOPIC_UNIFIED", "vehicle.event.unified.v1"),
|
||||
})
|
||||
}
|
||||
|
||||
func env(key string, fallback string) string {
|
||||
value := strings.TrimSpace(os.Getenv(key))
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func envInt(key string, fallback int) int {
|
||||
value := strings.TrimSpace(os.Getenv(key))
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
var out int
|
||||
for _, r := range value {
|
||||
if r < '0' || r > '9' {
|
||||
return fallback
|
||||
}
|
||||
out = out*10 + int(r-'0')
|
||||
}
|
||||
if out <= 0 {
|
||||
return fallback
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func splitCSV(value string) []string {
|
||||
var out []string
|
||||
for _, item := range strings.Split(value, ",") {
|
||||
item = strings.TrimSpace(item)
|
||||
if item != "" {
|
||||
out = append(out, item)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user