go-xmpp/websocket_transport.go
2019-10-28 16:38:10 +01:00

78 lines
1.8 KiB
Go

package xmpp
import (
"context"
"errors"
"net"
"strings"
"time"
"nhooyr.io/websocket"
)
const pingTimeout = time.Duration(5) * time.Second
var ServerDoesNotSupportXmppOverWebsocket = errors.New("The websocket server does not support the xmpp subprotocol")
type WebsocketTransport struct {
Config TransportConfiguration
wsConn *websocket.Conn
netConn net.Conn
ctx context.Context
}
func (t *WebsocketTransport) Connect() error {
t.ctx = context.Background()
if t.Config.ConnectTimeout > 0 {
ctx, cancel := context.WithTimeout(t.ctx, time.Duration(t.Config.ConnectTimeout)*time.Second)
t.ctx = ctx
defer cancel()
}
wsConn, response, err := websocket.Dial(t.ctx, t.Config.Address, &websocket.DialOptions{
Subprotocols: []string{"xmpp"},
})
if err != nil {
return NewConnError(err, true)
}
if response.Header.Get("Sec-WebSocket-Protocol") != "xmpp" {
return ServerDoesNotSupportXmppOverWebsocket
}
t.wsConn = wsConn
t.netConn = websocket.NetConn(t.ctx, t.wsConn, websocket.MessageText)
return nil
}
func (t WebsocketTransport) StartTLS(domain string) error {
return TLSNotSupported
}
func (t WebsocketTransport) DoesStartTLS() bool {
return false
}
func (t WebsocketTransport) IsSecure() bool {
return strings.HasPrefix(t.Config.Address, "wss:")
}
func (t WebsocketTransport) Ping() error {
ctx, cancel := context.WithTimeout(context.Background(), pingTimeout)
defer cancel()
// Note that we do not use wsConn.Ping(), because not all websocket servers
// (ejabberd for example) implement ping frames
return t.wsConn.Write(ctx, websocket.MessageText, []byte(" "))
}
func (t WebsocketTransport) Read(p []byte) (n int, err error) {
return t.netConn.Read(p)
}
func (t WebsocketTransport) Write(p []byte) (n int, err error) {
return t.netConn.Write(p)
}
func (t WebsocketTransport) Close() error {
return t.netConn.Close()
}