Update dependencies. Closes #9
This commit is contained in:
145
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
145
vendor/github.com/Rhymen/go-whatsapp/conn.go
generated
vendored
@ -6,9 +6,6 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
"github.com/gorilla/websocket"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"os"
|
||||
@ -16,6 +13,10 @@ import (
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/Rhymen/go-whatsapp/binary"
|
||||
"github.com/Rhymen/go-whatsapp/crypto/cbc"
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
type metric byte
|
||||
@ -79,6 +80,8 @@ It holds all necessary information to make the package work internally.
|
||||
*/
|
||||
type Conn struct {
|
||||
wsConn *websocket.Conn
|
||||
wsConnOK bool
|
||||
wsConnMutex sync.RWMutex
|
||||
session *Session
|
||||
listener map[string]chan string
|
||||
listenerMutex sync.RWMutex
|
||||
@ -104,20 +107,9 @@ Creates a new connection with a given timeout. The websocket connection to the W
|
||||
The goroutine for handling incoming messages is started
|
||||
*/
|
||||
func NewConn(timeout time.Duration) (*Conn, error) {
|
||||
dialer := &websocket.Dialer{
|
||||
ReadBufferSize: 25 * 1024 * 1024,
|
||||
WriteBufferSize: 10 * 1024 * 1024,
|
||||
HandshakeTimeout: timeout,
|
||||
}
|
||||
|
||||
headers := http.Header{"Origin": []string{"https://web.whatsapp.com"}}
|
||||
wsConn, _, err := dialer.Dial("wss://w3.web.whatsapp.com/ws", headers)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("couldn't dial whatsapp web websocket: %v", err)
|
||||
}
|
||||
|
||||
wac := &Conn{
|
||||
wsConn: wsConn,
|
||||
wsConn: nil, // will be set in connect()
|
||||
wsConnMutex: sync.RWMutex{},
|
||||
listener: make(map[string]chan string),
|
||||
listenerMutex: sync.RWMutex{},
|
||||
writeChan: make(chan wsMsg),
|
||||
@ -130,6 +122,10 @@ func NewConn(timeout time.Duration) (*Conn, error) {
|
||||
shortClientName: "go-whatsapp",
|
||||
}
|
||||
|
||||
if err := wac.connect(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go wac.readPump()
|
||||
go wac.writePump()
|
||||
go wac.keepAlive(20000, 90000)
|
||||
@ -137,6 +133,80 @@ func NewConn(timeout time.Duration) (*Conn, error) {
|
||||
return wac, nil
|
||||
}
|
||||
|
||||
func (wac *Conn) isConnected() bool {
|
||||
wac.wsConnMutex.RLock()
|
||||
defer wac.wsConnMutex.RUnlock()
|
||||
if wac.wsConn == nil {
|
||||
return false
|
||||
}
|
||||
if wac.wsConnOK {
|
||||
return true
|
||||
}
|
||||
|
||||
// just send a keepalive to test the connection
|
||||
wac.sendKeepAlive()
|
||||
|
||||
// this method is expected to be called by loops. So we can just return false
|
||||
return false
|
||||
}
|
||||
|
||||
// connect should be guarded with wsConnMutex
|
||||
func (wac *Conn) connect() error {
|
||||
dialer := &websocket.Dialer{
|
||||
ReadBufferSize: 25 * 1024 * 1024,
|
||||
WriteBufferSize: 10 * 1024 * 1024,
|
||||
HandshakeTimeout: wac.msgTimeout,
|
||||
}
|
||||
|
||||
headers := http.Header{"Origin": []string{"https://web.whatsapp.com"}}
|
||||
wsConn, _, err := dialer.Dial("wss://w3.web.whatsapp.com/ws", headers)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't dial whatsapp web websocket: %v", err)
|
||||
}
|
||||
|
||||
wsConn.SetCloseHandler(func(code int, text string) error {
|
||||
fmt.Fprintf(os.Stderr, "websocket connection closed(%d, %s)\n", code, text)
|
||||
|
||||
// from default CloseHandler
|
||||
message := websocket.FormatCloseMessage(code, "")
|
||||
wsConn.WriteControl(websocket.CloseMessage, message, time.Now().Add(time.Second))
|
||||
|
||||
// our close handling
|
||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
|
||||
fmt.Println("Trigger reconnect")
|
||||
go wac.reconnect()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
wac.wsConn = wsConn
|
||||
wac.wsConnOK = true
|
||||
return nil
|
||||
}
|
||||
|
||||
// reconnect should be run as go routine
|
||||
func (wac *Conn) reconnect() {
|
||||
wac.wsConnMutex.Lock()
|
||||
wac.wsConn.Close()
|
||||
wac.wsConn = nil
|
||||
wac.wsConnOK = false
|
||||
wac.wsConnMutex.Unlock()
|
||||
|
||||
// wait up to 60 seconds and then reconnect. As writePump should send immediately, it might
|
||||
// reconnect as well. So we check its existance before reconnecting
|
||||
for !wac.isConnected() {
|
||||
time.Sleep(time.Duration(rand.Intn(60)) * time.Second)
|
||||
|
||||
wac.wsConnMutex.Lock()
|
||||
if wac.wsConn == nil {
|
||||
if err := wac.connect(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not reconnect to websocket: %v\n", err)
|
||||
}
|
||||
}
|
||||
wac.wsConnMutex.Unlock()
|
||||
}
|
||||
}
|
||||
|
||||
func (wac *Conn) write(data []interface{}) (<-chan string, error) {
|
||||
d, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
@ -201,11 +271,15 @@ func (wac *Conn) readPump() {
|
||||
for {
|
||||
msgType, msg, err := wac.wsConn.ReadMessage()
|
||||
if err != nil {
|
||||
wac.wsConnOK = false
|
||||
if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) {
|
||||
wac.handle(fmt.Errorf("unexpected websocket close: %v", err))
|
||||
}
|
||||
break
|
||||
// sleep for a second and retry reading the next message
|
||||
time.Sleep(time.Second)
|
||||
continue
|
||||
}
|
||||
wac.wsConnOK = true
|
||||
|
||||
data := strings.SplitN(string(msg), ",", 2)
|
||||
|
||||
@ -249,18 +323,43 @@ func (wac *Conn) readPump() {
|
||||
|
||||
func (wac *Conn) writePump() {
|
||||
for msg := range wac.writeChan {
|
||||
if err := wac.wsConn.WriteMessage(msg.messageType, msg.data); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error writing to socket: %v", err)
|
||||
for !wac.isConnected() {
|
||||
// reconnect to send the message ASAP
|
||||
wac.wsConnMutex.Lock()
|
||||
if wac.wsConn == nil {
|
||||
if err := wac.connect(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "could not reconnect to websocket: %v\n", err)
|
||||
}
|
||||
}
|
||||
wac.wsConnMutex.Unlock()
|
||||
if !wac.isConnected() {
|
||||
// reconnecting failed. Sleep for a while and try again afterwards
|
||||
time.Sleep(time.Duration(rand.Intn(5)) * time.Second)
|
||||
}
|
||||
}
|
||||
if err := wac.wsConn.WriteMessage(msg.messageType, msg.data); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "error writing to socket: %v\n", err)
|
||||
wac.wsConnOK = false
|
||||
// add message to channel again to no loose it
|
||||
go func() {
|
||||
wac.writeChan <- msg
|
||||
}()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (wac *Conn) sendKeepAlive() {
|
||||
// whatever issues might be there allow sending this message
|
||||
wac.wsConnOK = true
|
||||
wac.writeChan <- wsMsg{
|
||||
messageType: websocket.TextMessage,
|
||||
data: []byte("?,,"),
|
||||
}
|
||||
}
|
||||
|
||||
func (wac *Conn) keepAlive(minIntervalMs int, maxIntervalMs int) {
|
||||
for {
|
||||
wac.writeChan <- wsMsg{
|
||||
messageType: websocket.TextMessage,
|
||||
data: []byte("?,,"),
|
||||
}
|
||||
wac.sendKeepAlive()
|
||||
interval := rand.Intn(maxIntervalMs-minIntervalMs) + minIntervalMs
|
||||
<-time.After(time.Duration(interval) * time.Millisecond)
|
||||
}
|
||||
|
Reference in New Issue
Block a user