package transport
import (
"bytes"
"io"
"net"
"net/http"
"nhooyr.io/websocket"
"github.com/gotd/td/internal/mtproxy/obfuscated2"
"github.com/gotd/td/internal/proto/codec"
"github.com/gotd/td/internal/tdsync"
"github.com/gotd/td/internal/wsutil"
)
type wsListener struct {
addr net .Addr
ch chan *wsServerConn
closed *tdsync .Ready
}
func WebsocketListener (addr net .Addr ) (net .Listener , http .Handler ) {
l := wsListener {
addr : addr ,
ch : make (chan *wsServerConn , 1 ),
closed : tdsync .NewReady (),
}
return l , l
}
func (l wsListener ) ServeHTTP (w http .ResponseWriter , r *http .Request ) {
wsConn , err := websocket .Accept (w , r , &websocket .AcceptOptions {
Subprotocols : []string {"binary" },
})
if err != nil {
w .WriteHeader (400 )
return
}
defer func () {
_ = wsConn .Close (websocket .StatusNormalClosure , "Close" )
}()
conn := wsutil .NetConn (wsConn )
rw , md , err := obfuscated2 .Accept (conn , nil )
if err != nil {
w .WriteHeader (400 )
return
}
var tag *bytes .Reader
if md .Protocol [0 ] == codec .AbridgedClientStart [0 ] {
tag = bytes .NewReader (md .Protocol [:1 ])
} else {
tag = bytes .NewReader (md .Protocol [:])
}
accepted := &wsServerConn {
closed : *tdsync .NewReady (),
reader : io .MultiReader (tag , rw ),
writer : rw ,
Conn : conn ,
}
reqCtx := r .Context ().Done ()
closed := l .closed .Ready ()
select {
case <- reqCtx :
return
case <- closed :
return
case l .ch <- accepted :
}
select {
case <- reqCtx :
return
case <- closed :
return
case <- accepted .closed .Ready ():
}
}
func (l wsListener ) Accept () (net .Conn , error ) {
r := l .closed .Ready ()
for {
select {
case <- r :
return nil , net .ErrClosed
case conn := <- l .ch :
return conn , nil
}
}
}
func (l wsListener ) Close () error {
l .closed .Signal ()
return nil
}
func (l wsListener ) Addr () net .Addr {
return l .addr
}
type wsServerConn struct {
closed tdsync .Ready
reader io .Reader
writer io .Writer
net .Conn
}
func (c *wsServerConn ) Read (p []byte ) (int , error ) {
return c .reader .Read (p )
}
func (c *wsServerConn ) Write (p []byte ) (int , error ) {
return c .writer .Write (p )
}
func (c *wsServerConn ) Close () error {
c .closed .Signal ()
return nil
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .