golang: serving net.Conn using a gin router

Issue

I have a function that handles an incoming TCP connection:

func Handle(conn net.Conn) error {
    // ...
}

Also, I have an initialized gin router with implemented handles:

router := gin.New()
router.GET(...)
router.POST(...)

The router.Run(addr) call will start a separate HTTP server on the addr.

Is there any way to handle incoming connections inside the Handle function using this router without running a separate HTTP server?

Solution

Create a net.Listener implementation that accepts connections by receiving on a channel:

type listener struct {
    ch   chan net.Conn
    addr net.Addr
}

// newListener creates a channel listener. The addr argument
// is the listener's network address.
func newListener(addr net.Addr) *listener {
    return &listener{
        ch:   make(chan net.Conn),
        addr: addr,
    }
}

func (l *listener) Accept() (net.Conn, error) {
    c, ok := <-l.ch
    if !ok {
        return nil, errors.New("closed")
    }
    return c, nil
}

func (l *listener) Close() error { return nil }

func (l *listener) Addr() net.Addr { return l.addr }

Handle connections by sending to the channel:

func (l *listener) Handle(c net.Conn) error {
    l.ch <- c
    return nil
}

Here’s how to tie it all together:

  • Create the listener:

      s := newListener(someAddr)
    
  • Configure the Gin engine as usual.

      router := gin.New()
      router.GET(...)
      router.POST(...)
    
  • Run the net/http server in a goroutine using the channel listener and the Gin engine:

      err := http.Serve(s, router)
      if err != nil {
          // handle error
      }
    
  • In your dispatching code, call the s.Handle(c) to pass the connection to the net/http server and then on to the Gin engine.

Answered By – Zombo

Answer Checked By – Pedro (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.