Update dependencies (#1841)
This commit is contained in:
118
vendor/go.mau.fi/whatsmeow/client.go
vendored
118
vendor/go.mau.fi/whatsmeow/client.go
vendored
@@ -10,7 +10,6 @@ package whatsmeow
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -52,6 +51,7 @@ type Client struct {
|
||||
|
||||
socket *socket.NoiseSocket
|
||||
socketLock sync.RWMutex
|
||||
socketWait chan struct{}
|
||||
|
||||
isLoggedIn uint32
|
||||
expectedDisconnectVal uint32
|
||||
@@ -88,6 +88,11 @@ type Client struct {
|
||||
messageRetries map[string]int
|
||||
messageRetriesLock sync.Mutex
|
||||
|
||||
appStateKeyRequests map[string]time.Time
|
||||
appStateKeyRequestsLock sync.RWMutex
|
||||
|
||||
messageSendLock sync.Mutex
|
||||
|
||||
privacySettingsCache atomic.Value
|
||||
|
||||
groupParticipantsCache map[types.JID][]types.JID
|
||||
@@ -99,22 +104,21 @@ type Client struct {
|
||||
recentMessagesList [recentMessagesSize]recentMessageKey
|
||||
recentMessagesPtr int
|
||||
recentMessagesLock sync.RWMutex
|
||||
|
||||
sessionRecreateHistory map[types.JID]time.Time
|
||||
sessionRecreateHistoryLock sync.Mutex
|
||||
// GetMessageForRetry is used to find the source message for handling retry receipts
|
||||
// when the message is not found in the recently sent message cache.
|
||||
GetMessageForRetry func(to types.JID, id types.MessageID) *waProto.Message
|
||||
GetMessageForRetry func(requester, to types.JID, id types.MessageID) *waProto.Message
|
||||
// PreRetryCallback is called before a retry receipt is accepted.
|
||||
// If it returns false, the accepting will be cancelled and the retry receipt will be ignored.
|
||||
PreRetryCallback func(receipt *events.Receipt, retryCount int, msg *waProto.Message) bool
|
||||
PreRetryCallback func(receipt *events.Receipt, id types.MessageID, retryCount int, msg *waProto.Message) bool
|
||||
|
||||
// Should untrusted identity errors be handled automatically? If true, the stored identity and existing signal
|
||||
// sessions will be removed on untrusted identity errors, and an events.IdentityChange will be dispatched.
|
||||
// If false, decrypting a message from untrusted devices will fail.
|
||||
AutoTrustIdentity bool
|
||||
|
||||
DebugDecodeBeforeSend bool
|
||||
OneMessageAtATime bool
|
||||
messageSendLock sync.Mutex
|
||||
|
||||
uniqueID string
|
||||
idCounter uint32
|
||||
|
||||
@@ -162,14 +166,17 @@ func NewClient(deviceStore *store.Device, log waLog.Logger) *Client {
|
||||
messageRetries: make(map[string]int),
|
||||
handlerQueue: make(chan *waBinary.Node, handlerQueueSize),
|
||||
appStateProc: appstate.NewProcessor(deviceStore, log.Sub("AppState")),
|
||||
socketWait: make(chan struct{}),
|
||||
|
||||
historySyncNotifications: make(chan *waProto.HistorySyncNotification, 32),
|
||||
|
||||
groupParticipantsCache: make(map[types.JID][]types.JID),
|
||||
userDevicesCache: make(map[types.JID][]types.JID),
|
||||
|
||||
recentMessagesMap: make(map[recentMessageKey]*waProto.Message, recentMessagesSize),
|
||||
GetMessageForRetry: func(to types.JID, id types.MessageID) *waProto.Message { return nil },
|
||||
recentMessagesMap: make(map[recentMessageKey]*waProto.Message, recentMessagesSize),
|
||||
sessionRecreateHistory: make(map[types.JID]time.Time),
|
||||
GetMessageForRetry: func(requester, to types.JID, id types.MessageID) *waProto.Message { return nil },
|
||||
appStateKeyRequests: make(map[string]time.Time),
|
||||
|
||||
EnableAutoReconnect: true,
|
||||
AutoTrustIdentity: true,
|
||||
@@ -226,6 +233,37 @@ func (cli *Client) SetProxy(proxy socket.Proxy) {
|
||||
cli.http.Transport.(*http.Transport).Proxy = proxy
|
||||
}
|
||||
|
||||
func (cli *Client) getSocketWaitChan() <-chan struct{} {
|
||||
cli.socketLock.RLock()
|
||||
ch := cli.socketWait
|
||||
cli.socketLock.RUnlock()
|
||||
return ch
|
||||
}
|
||||
|
||||
func (cli *Client) closeSocketWaitChan() {
|
||||
cli.socketLock.Lock()
|
||||
close(cli.socketWait)
|
||||
cli.socketWait = make(chan struct{})
|
||||
cli.socketLock.Unlock()
|
||||
}
|
||||
|
||||
func (cli *Client) WaitForConnection(timeout time.Duration) bool {
|
||||
timeoutChan := time.After(timeout)
|
||||
cli.socketLock.RLock()
|
||||
for cli.socket == nil || !cli.socket.IsConnected() || !cli.IsLoggedIn() {
|
||||
ch := cli.socketWait
|
||||
cli.socketLock.RUnlock()
|
||||
select {
|
||||
case <-ch:
|
||||
case <-timeoutChan:
|
||||
return false
|
||||
}
|
||||
cli.socketLock.RLock()
|
||||
}
|
||||
cli.socketLock.RUnlock()
|
||||
return true
|
||||
}
|
||||
|
||||
// Connect connects the client to the WhatsApp web websocket. After connection, it will either
|
||||
// authenticate if there's data in the device store, or emit a QREvent to set up a new link.
|
||||
func (cli *Client) Connect() error {
|
||||
@@ -322,6 +360,9 @@ func (cli *Client) IsConnected() bool {
|
||||
}
|
||||
|
||||
// Disconnect disconnects from the WhatsApp web websocket.
|
||||
//
|
||||
// This will not emit any events, the Disconnected event is only used when the
|
||||
// connection is closed by the server or a network error.
|
||||
func (cli *Client) Disconnect() {
|
||||
if cli.socket == nil {
|
||||
return
|
||||
@@ -336,6 +377,7 @@ func (cli *Client) unlockedDisconnect() {
|
||||
if cli.socket != nil {
|
||||
cli.socket.Stop(true)
|
||||
cli.socket = nil
|
||||
cli.clearResponseWaiters(xmlStreamEndNode)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +385,9 @@ func (cli *Client) unlockedDisconnect() {
|
||||
//
|
||||
// If the logout request fails, the disconnection and local data deletion will not happen either.
|
||||
// If an error is returned, but you want to force disconnect/clear data, call Client.Disconnect() and Client.Store.Delete() manually.
|
||||
//
|
||||
// Note that this will not emit any events. The LoggedOut event is only used for external logouts
|
||||
// (triggered by the user from the main device or by WhatsApp servers).
|
||||
func (cli *Client) Logout() error {
|
||||
if cli.Store.ID == nil {
|
||||
return ErrNotLoggedIn
|
||||
@@ -491,7 +536,7 @@ func (cli *Client) handlerQueueLoop(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *Client) sendNodeDebug(node waBinary.Node) ([]byte, error) {
|
||||
func (cli *Client) sendNodeAndGetData(node waBinary.Node) ([]byte, error) {
|
||||
cli.socketLock.RLock()
|
||||
sock := cli.socket
|
||||
cli.socketLock.RUnlock()
|
||||
@@ -503,22 +548,13 @@ func (cli *Client) sendNodeDebug(node waBinary.Node) ([]byte, error) {
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to marshal node: %w", err)
|
||||
}
|
||||
if cli.DebugDecodeBeforeSend {
|
||||
var decoded *waBinary.Node
|
||||
decoded, err = waBinary.Unmarshal(payload[1:])
|
||||
if err != nil {
|
||||
cli.Log.Infof("Malformed payload: %s", base64.URLEncoding.EncodeToString(payload))
|
||||
return nil, fmt.Errorf("failed to decode the binary we just produced: %w", err)
|
||||
}
|
||||
node = *decoded
|
||||
}
|
||||
|
||||
cli.sendLog.Debugf("%s", node.XMLString())
|
||||
return payload, sock.SendFrame(payload)
|
||||
}
|
||||
|
||||
func (cli *Client) sendNode(node waBinary.Node) error {
|
||||
_, err := cli.sendNodeDebug(node)
|
||||
_, err := cli.sendNodeAndGetData(node)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -535,3 +571,45 @@ func (cli *Client) dispatchEvent(evt interface{}) {
|
||||
handler.fn(evt)
|
||||
}
|
||||
}
|
||||
|
||||
// ParseWebMessage parses a WebMessageInfo object into *events.Message to match what real-time messages have.
|
||||
//
|
||||
// The chat JID can be found in the Conversation data:
|
||||
// chatJID, err := types.ParseJID(conv.GetId())
|
||||
// for _, historyMsg := range conv.GetMessages() {
|
||||
// evt, err := cli.ParseWebMessage(chatJID, historyMsg.GetMessage())
|
||||
// yourNormalEventHandler(evt)
|
||||
// }
|
||||
func (cli *Client) ParseWebMessage(chatJID types.JID, webMsg *waProto.WebMessageInfo) (*events.Message, error) {
|
||||
info := types.MessageInfo{
|
||||
MessageSource: types.MessageSource{
|
||||
Chat: chatJID,
|
||||
IsFromMe: webMsg.GetKey().GetFromMe(),
|
||||
IsGroup: chatJID.Server == types.GroupServer,
|
||||
},
|
||||
ID: webMsg.GetKey().GetId(),
|
||||
PushName: webMsg.GetPushName(),
|
||||
Timestamp: time.Unix(int64(webMsg.GetMessageTimestamp()), 0),
|
||||
}
|
||||
var err error
|
||||
if info.IsFromMe {
|
||||
info.Sender = cli.Store.ID.ToNonAD()
|
||||
} else if chatJID.Server == types.DefaultUserServer {
|
||||
info.Sender = chatJID
|
||||
} else if webMsg.GetParticipant() != "" {
|
||||
info.Sender, err = types.ParseJID(webMsg.GetParticipant())
|
||||
} else if webMsg.GetKey().GetParticipant() != "" {
|
||||
info.Sender, err = types.ParseJID(webMsg.GetKey().GetParticipant())
|
||||
} else {
|
||||
return nil, fmt.Errorf("couldn't find sender of message %s", info.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse sender of message %s: %v", info.ID, err)
|
||||
}
|
||||
evt := &events.Message{
|
||||
RawMessage: webMsg.GetMessage(),
|
||||
Info: info,
|
||||
}
|
||||
evt.UnwrapRaw()
|
||||
return evt, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user