feat: write protocol acknowledgements from go gateway
This commit is contained in:
@@ -21,11 +21,14 @@ type FrameExtractor func([]byte) (frames [][]byte, remainder []byte, err error)
|
||||
|
||||
type FrameParser func(raw []byte, receivedAtMS int64, sourceEndpoint string) (envelope.FrameEnvelope, error)
|
||||
|
||||
type FrameResponder func(raw []byte, env envelope.FrameEnvelope) (response []byte, ok bool, err error)
|
||||
|
||||
type TCPProtocol struct {
|
||||
Protocol envelope.Protocol
|
||||
Addr string
|
||||
Extract FrameExtractor
|
||||
Parse FrameParser
|
||||
Respond FrameResponder
|
||||
}
|
||||
|
||||
type TCPServer struct {
|
||||
@@ -153,7 +156,7 @@ func (s *TCPServer) handleConnection(ctx context.Context, conn net.Conn) {
|
||||
}
|
||||
pending = remainder
|
||||
for _, frame := range frames {
|
||||
s.handleFrame(ctx, frame, source)
|
||||
s.handleFrame(ctx, conn, frame, source)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
@@ -174,7 +177,7 @@ func (s *TCPServer) handleConnection(ctx context.Context, conn net.Conn) {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TCPServer) handleFrame(ctx context.Context, raw []byte, source string) {
|
||||
func (s *TCPServer) handleFrame(ctx context.Context, conn net.Conn, raw []byte, source string) {
|
||||
receivedAtMS := time.Now().UnixMilli()
|
||||
env, err := s.protocol.Parse(raw, receivedAtMS, source)
|
||||
if err != nil {
|
||||
@@ -213,6 +216,21 @@ func (s *TCPServer) handleFrame(ctx context.Context, raw []byte, source string)
|
||||
s.logger.Error("publish unified failed", "protocol", s.protocol.Protocol, "event_id", env.StableEventID(), "error", err)
|
||||
return
|
||||
}
|
||||
if s.protocol.Respond == nil {
|
||||
return
|
||||
}
|
||||
response, ok, err := s.protocol.Respond(raw, env)
|
||||
if err != nil {
|
||||
s.logger.Warn("build protocol response failed", "protocol", s.protocol.Protocol, "event_id", env.StableEventID(), "error", err)
|
||||
return
|
||||
}
|
||||
if !ok || len(response) == 0 {
|
||||
return
|
||||
}
|
||||
_ = conn.SetWriteDeadline(time.Now().Add(5 * time.Second))
|
||||
if _, err := conn.Write(response); err != nil {
|
||||
s.logger.Warn("write protocol response failed", "protocol", s.protocol.Protocol, "event_id", env.StableEventID(), "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p TCPProtocol) String() string {
|
||||
|
||||
@@ -3,6 +3,7 @@ package gateway
|
||||
import (
|
||||
"context"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"log/slog"
|
||||
"net"
|
||||
"testing"
|
||||
@@ -73,6 +74,37 @@ func TestTCPServerPublishesBadFrameOnlyToRaw(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTCPServerWritesProtocolResponseAfterPublish(t *testing.T) {
|
||||
frame := buildGBFrame(0x07, 0xfe, "LNBSCB3D4R1234567", nil)
|
||||
sink := &recordingSink{}
|
||||
server := newTestServer(t, TCPProtocol{
|
||||
Protocol: envelope.ProtocolGB32960,
|
||||
Addr: ":0",
|
||||
Extract: gb32960.ExtractFrames,
|
||||
Parse: gb32960.ParseFrame,
|
||||
Respond: func(_ []byte, env envelope.FrameEnvelope) ([]byte, bool, error) {
|
||||
if len(sink.unified) != 1 || sink.unified[0].EventID != env.EventID {
|
||||
t.Fatalf("response built before publish: raw=%d unified=%d", len(sink.raw), len(sink.unified))
|
||||
}
|
||||
return []byte("ACK"), true, nil
|
||||
},
|
||||
}, sink)
|
||||
|
||||
client, done := runPipe(t, server)
|
||||
if _, err := client.Write(frame); err != nil {
|
||||
t.Fatalf("client.Write() error = %v", err)
|
||||
}
|
||||
buf := make([]byte, 3)
|
||||
if _, err := io.ReadFull(client, buf); err != nil {
|
||||
t.Fatalf("read response error = %v", err)
|
||||
}
|
||||
if string(buf) != "ACK" {
|
||||
t.Fatalf("response = %q", string(buf))
|
||||
}
|
||||
_ = client.Close()
|
||||
<-done
|
||||
}
|
||||
|
||||
func newTestServer(t *testing.T, protocol TCPProtocol, sink *recordingSink) *TCPServer {
|
||||
t.Helper()
|
||||
server, err := NewTCPServer(TCPServerConfig{
|
||||
|
||||
Reference in New Issue
Block a user