package rcon import ( "fmt" "net" "sync" "github.com/gorcon/rcon" ) // MockRCONServer simulates an RCON server for testing purposes type MockRCONServer struct { listener net.Listener Commands []string Errors []error Messages []string } // Start starts the mock RCON server on a random available port func (m *MockRCONServer) Start() (func() *RCONResults, error) { listener, err := net.Listen("tcp", "127.0.0.1:0") if err != nil { return nil, fmt.Errorf("failed to start mock server: %w", err) } m.listener = listener results := &RCONResults{} done := sync.WaitGroup{} done.Go(func() { for { conn, err := listener.Accept() if err != nil { return } go m.handleConnection(conn, results) } }) return func() *RCONResults { m.stop() done.Wait() return results }, nil } // Stop stops the mock RCON server func (m *MockRCONServer) stop() error { if m.listener != nil { return m.listener.Close() } return nil } // Address returns the address the mock server is listening on func (m *MockRCONServer) Address() string { if m.listener != nil { return m.listener.Addr().String() } return "" } // handleConnection handles individual client connections func (m *MockRCONServer) handleConnection(conn net.Conn, results *RCONResults) { defer conn.Close() for { packet := &rcon.Packet{} if _, err := packet.ReadFrom(conn); err != nil { results.AppendError(err) return } results.AppendMessage(packet.Body()) var respPacket *rcon.Packet switch packet.Type { case rcon.SERVERDATA_AUTH: respPacket = rcon.NewPacket(rcon.SERVERDATA_AUTH_RESPONSE, packet.ID, "") case rcon.SERVERDATA_EXECCOMMAND: respPacket = rcon.NewPacket(rcon.SERVERDATA_RESPONSE_VALUE, packet.ID, "") default: results.AppendError(fmt.Errorf("unknown packet: %v", packet.Type)) return } if _, err := respPacket.WriteTo(conn); err != nil { results.AppendError(err) return } } } type RCONResults struct { mu sync.Mutex Messages []string Errors []error } func (r *RCONResults) AppendError(err error) { r.mu.Lock() defer r.mu.Unlock() r.Errors = append(r.Errors, err) } func (r *RCONResults) AppendMessage(msg string) { r.mu.Lock() defer r.mu.Unlock() r.Messages = append(r.Messages, msg) }