mirror of
https://github.com/XTLS/Xray-core.git
synced 2026-10-13 11:05:46 +00:00
92 lines
1.8 KiB
Go
92 lines
1.8 KiB
Go
package websocket
|
|
|
|
import (
|
|
"context"
|
|
"io"
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/coder/websocket"
|
|
"github.com/xtls/xray-core/common/buf"
|
|
)
|
|
|
|
var _ buf.Writer = (*connection)(nil)
|
|
|
|
type connection struct {
|
|
net.Conn
|
|
reader io.Reader
|
|
remoteAddr net.Addr
|
|
localAddr net.Addr
|
|
}
|
|
|
|
func NewConnection(conn *websocket.Conn, remoteAddr net.Addr, extraReader io.Reader, heartbeatPeriod uint32) *connection {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
c := &connection{Conn: websocket.NetConn(ctx, conn, websocket.MessageBinary), reader: extraReader, remoteAddr: remoteAddr}
|
|
if remoteAddr == nil {
|
|
c.remoteAddr = c.Conn.RemoteAddr()
|
|
}
|
|
c.Conn = &cancelConn{Conn: c.Conn, cancel: cancel}
|
|
if heartbeatPeriod != 0 {
|
|
go func() {
|
|
ticker := time.NewTicker(time.Duration(heartbeatPeriod) * time.Second)
|
|
defer ticker.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-ticker.C:
|
|
pingCtx, stop := context.WithTimeout(ctx, time.Duration(heartbeatPeriod)*time.Second)
|
|
err := conn.Ping(pingCtx)
|
|
stop()
|
|
if err != nil {
|
|
c.Close()
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
return c
|
|
}
|
|
|
|
type cancelConn struct {
|
|
net.Conn
|
|
cancel context.CancelFunc
|
|
}
|
|
|
|
func (c *cancelConn) Close() error {
|
|
defer c.cancel()
|
|
return c.Conn.Close()
|
|
}
|
|
|
|
func (c *connection) Read(b []byte) (int, error) {
|
|
if c.reader != nil {
|
|
n, err := c.reader.Read(b)
|
|
if err == io.EOF {
|
|
c.reader = nil
|
|
if n > 0 {
|
|
return n, nil
|
|
}
|
|
} else {
|
|
return n, err
|
|
}
|
|
}
|
|
return c.Conn.Read(b)
|
|
}
|
|
|
|
func (c *connection) LocalAddr() net.Addr {
|
|
if c.localAddr != nil {
|
|
return c.localAddr
|
|
}
|
|
return c.Conn.LocalAddr()
|
|
}
|
|
|
|
func (c *connection) RemoteAddr() net.Addr { return c.remoteAddr }
|
|
|
|
func (c *connection) WriteMultiBuffer(mb buf.MultiBuffer) error {
|
|
mb = buf.Compact(mb)
|
|
mb, err := buf.WriteMultiBuffer(c, mb)
|
|
buf.ReleaseMulti(mb)
|
|
return err
|
|
}
|