golanggohlsrtmpwebrtcmedia-serverobs-studiortcprtmp-proxyrtmp-serverrtprtsprtsp-proxyrtsp-relayrtsp-serversrtstreamingwebrtc-proxy
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
115 lines
2.3 KiB
115 lines
2.3 KiB
// Package websocket provides WebSocket connectivity. |
|
package websocket |
|
|
|
import ( |
|
"encoding/json" |
|
"fmt" |
|
"net" |
|
"net/http" |
|
"time" |
|
|
|
"github.com/gorilla/websocket" |
|
) |
|
|
|
var ( |
|
pingInterval = 30 * time.Second |
|
pingTimeout = 5 * time.Second |
|
writeTimeout = 2 * time.Second |
|
) |
|
|
|
var upgrader = websocket.Upgrader{ |
|
CheckOrigin: func(_ *http.Request) bool { |
|
return true |
|
}, |
|
} |
|
|
|
// ServerConn is a server-side WebSocket connection with |
|
// automatic, periodic ping-pong |
|
type ServerConn struct { |
|
wc *websocket.Conn |
|
|
|
// in |
|
terminate chan struct{} |
|
write chan []byte |
|
|
|
// out |
|
writeErr chan error |
|
} |
|
|
|
// NewServerConn allocates a ServerConn. |
|
func NewServerConn(w http.ResponseWriter, req *http.Request) (*ServerConn, error) { |
|
wc, err := upgrader.Upgrade(w, req, nil) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
c := &ServerConn{ |
|
wc: wc, |
|
terminate: make(chan struct{}), |
|
write: make(chan []byte), |
|
writeErr: make(chan error), |
|
} |
|
|
|
go c.run() |
|
|
|
return c, nil |
|
} |
|
|
|
// Close closes a ServerConn. |
|
func (c *ServerConn) Close() { |
|
c.wc.Close() //nolint:errcheck |
|
close(c.terminate) |
|
} |
|
|
|
// RemoteAddr returns the remote address. |
|
func (c *ServerConn) RemoteAddr() net.Addr { |
|
return c.wc.RemoteAddr() |
|
} |
|
|
|
func (c *ServerConn) run() { |
|
c.wc.SetReadDeadline(time.Now().Add(pingInterval + pingTimeout)) //nolint:errcheck |
|
|
|
c.wc.SetPongHandler(func(string) error { |
|
c.wc.SetReadDeadline(time.Now().Add(pingInterval + pingTimeout)) //nolint:errcheck |
|
return nil |
|
}) |
|
|
|
pingTicker := time.NewTicker(pingInterval) |
|
defer pingTicker.Stop() |
|
|
|
for { |
|
select { |
|
case byts := <-c.write: |
|
c.wc.SetWriteDeadline(time.Now().Add(writeTimeout)) //nolint:errcheck |
|
err := c.wc.WriteMessage(websocket.TextMessage, byts) |
|
c.writeErr <- err |
|
|
|
case <-pingTicker.C: |
|
c.wc.SetWriteDeadline(time.Now().Add(writeTimeout)) //nolint:errcheck |
|
c.wc.WriteMessage(websocket.PingMessage, nil) //nolint:errcheck |
|
|
|
case <-c.terminate: |
|
return |
|
} |
|
} |
|
} |
|
|
|
// ReadJSON reads a JSON object. |
|
func (c *ServerConn) ReadJSON(in interface{}) error { |
|
return c.wc.ReadJSON(in) |
|
} |
|
|
|
// WriteJSON writes a JSON object. |
|
func (c *ServerConn) WriteJSON(in interface{}) error { |
|
byts, err := json.Marshal(in) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
select { |
|
case c.write <- byts: |
|
return <-c.writeErr |
|
case <-c.terminate: |
|
return fmt.Errorf("terminated") |
|
} |
|
}
|
|
|