// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package main

import (
	"fmt"
	"io"
	"net"
	"os"
)

// gRPC byte prefix (see RPCGRPC in agent/pool/conn.go).
const bytePrefix byte = 8

func main() {
	if len(os.Args) != 2 {
		log("usage: %s host:port", os.Args[0])
		os.Exit(1)
	}
	serverAddr := os.Args[1]

	lis, err := net.Listen("tcp", "127.0.0.1:0")
	if err != nil {
		log("failed to start listener: %v", err)
		os.Exit(1)
	}
	defer lis.Close()

	fmt.Println("Proxying connections to Consul's internal gRPC server")
	fmt.Printf("Use this address: %s\n", lis.Addr())

	for {
		conn, err := lis.Accept()
		if err != nil {
			log("failed to accept connection: %v", err)
			continue
		}

		go func(conn net.Conn) {
			if err := handleClient(serverAddr, conn); err != nil {
				log(err.Error())
			}
		}(conn)
	}
}

func handleClient(serverAddr string, clientConn net.Conn) error {
	defer clientConn.Close()

	serverConn, err := net.Dial("tcp", serverAddr)
	if err != nil {
		return fmt.Errorf("failed to dial server connection: %w", err)
	}
	defer serverConn.Close()

	if _, err := serverConn.Write([]byte{bytePrefix}); err != nil {
		return fmt.Errorf("failed to write byte prefix: %v", err)
	}

	errCh := make(chan error, 1)

	go func() {
		_, err := io.Copy(serverConn, clientConn)
		errCh <- err
	}()

	go func() {
		_, err := io.Copy(clientConn, serverConn)
		errCh <- err
	}()

	return <-errCh
}

func log(message string, args ...interface{}) {
	fmt.Fprintf(os.Stderr, message+"\n", args...)
}
