Search code examples
gogo-gin

golang: serving net.Conn using a gin router


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.