package net import ( "errors" "net" "net/http" "time" "golang.org/x/net/websocket" ) var ErrWebsocketListenerClosed = errors.New("websocket listener closed") const ( FrpWebsocketPath = "/~!frp" ) type WebsocketListener struct { ln net.Listener acceptCh chan net.Conn server *http.Server } // NewWebsocketListener to handle websocket connections // ln: tcp listener for websocket connections func NewWebsocketListener(ln net.Listener) (wl *WebsocketListener) { wl = &WebsocketListener{ acceptCh: make(chan net.Conn), } muxer := http.NewServeMux() muxer.Handle(FrpWebsocketPath, websocket.Handler(func(c *websocket.Conn) { notifyCh := make(chan struct{}) conn := WrapCloseNotifyConn(c, func() { close(notifyCh) }) wl.acceptCh <- conn <-notifyCh })) wl.server = &http.Server{ Addr: ln.Addr().String(), Handler: muxer, ReadHeaderTimeout: 60 * time.Second, } go func() { _ = wl.server.Serve(ln) }() return } func (p *WebsocketListener) Accept() (net.Conn, error) { c, ok := <-p.acceptCh if !ok { return nil, ErrWebsocketListenerClosed } return c, nil } func (p *WebsocketListener) Close() error { return p.server.Close() } func (p *WebsocketListener) Addr() net.Addr { return p.ln.Addr() }