mirror of
https://github.com/42wim/matterbridge.git
synced 2024-11-23 11:12:02 -08:00
184 lines
4.3 KiB
Go
184 lines
4.3 KiB
Go
package whatsapp
|
|
|
|
import (
|
|
"github.com/Rhymen/go-whatsapp/binary"
|
|
"github.com/Rhymen/go-whatsapp/binary/proto"
|
|
"log"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
type MessageOffsetInfo struct {
|
|
FirstMessageId string
|
|
FirstMessageOwner bool
|
|
}
|
|
|
|
func decodeMessages(n *binary.Node) []*proto.WebMessageInfo {
|
|
|
|
var messages = make([]*proto.WebMessageInfo, 0)
|
|
|
|
if n == nil || n.Attributes == nil || n.Content == nil {
|
|
return messages
|
|
}
|
|
|
|
for _, msg := range n.Content.([]interface{}) {
|
|
switch msg.(type) {
|
|
case *proto.WebMessageInfo:
|
|
messages = append(messages, msg.(*proto.WebMessageInfo))
|
|
default:
|
|
log.Println("decodeMessages: Non WebMessage encountered")
|
|
}
|
|
}
|
|
|
|
return messages
|
|
}
|
|
|
|
// LoadChatMessages is useful to "scroll" messages, loading by count at a time
|
|
// if handlers == nil the func will use default handlers
|
|
// if after == true LoadChatMessages will load messages after the specified messageId, otherwise it will return
|
|
// message before the messageId
|
|
func (wac *Conn) LoadChatMessages(jid string, count int, messageId string, owner bool, after bool, handlers ...Handler) error {
|
|
if count <= 0 {
|
|
return nil
|
|
}
|
|
|
|
if handlers == nil {
|
|
handlers = wac.handler
|
|
}
|
|
|
|
kind := "before"
|
|
if after {
|
|
kind = "after"
|
|
}
|
|
|
|
node, err := wac.query("message", jid, messageId, kind,
|
|
strconv.FormatBool(owner), "", count, 0)
|
|
|
|
if err != nil {
|
|
wac.handleWithCustomHandlers(err, handlers)
|
|
return err
|
|
}
|
|
|
|
for _, msg := range decodeMessages(node) {
|
|
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
|
wac.handleWithCustomHandlers(msg, handlers)
|
|
}
|
|
return nil
|
|
|
|
}
|
|
|
|
// LoadFullChatHistory loads full chat history for the given jid
|
|
// chunkSize = how many messages to load with one query; if handlers == nil the func will use default handlers;
|
|
// pauseBetweenQueries = how much time to sleep between queries
|
|
func (wac *Conn) LoadFullChatHistory(jid string, chunkSize int,
|
|
pauseBetweenQueries time.Duration, handlers ...Handler) {
|
|
if chunkSize <= 0 {
|
|
return
|
|
}
|
|
|
|
if handlers == nil {
|
|
handlers = wac.handler
|
|
}
|
|
|
|
beforeMsg := ""
|
|
beforeMsgIsOwner := true
|
|
|
|
for {
|
|
node, err := wac.query("message", jid, beforeMsg, "before",
|
|
strconv.FormatBool(beforeMsgIsOwner), "", chunkSize, 0)
|
|
|
|
if err != nil {
|
|
wac.handleWithCustomHandlers(err, handlers)
|
|
} else {
|
|
|
|
msgs := decodeMessages(node)
|
|
for _, msg := range msgs {
|
|
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
|
wac.handleWithCustomHandlers(msg, handlers)
|
|
}
|
|
|
|
if len(msgs) == 0 {
|
|
break
|
|
}
|
|
|
|
beforeMsg = *msgs[0].Key.Id
|
|
beforeMsgIsOwner = msgs[0].Key.FromMe != nil && *msgs[0].Key.FromMe
|
|
}
|
|
|
|
<-time.After(pauseBetweenQueries)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// LoadFullChatHistoryAfter loads all messages after the specified messageId
|
|
// useful to "catch up" with the message history after some specified message
|
|
func (wac *Conn) LoadFullChatHistoryAfter(jid string, messageId string, chunkSize int,
|
|
pauseBetweenQueries time.Duration, handlers ...Handler) {
|
|
|
|
if chunkSize <= 0 {
|
|
return
|
|
}
|
|
|
|
if handlers == nil {
|
|
handlers = wac.handler
|
|
}
|
|
|
|
msgOwner := true
|
|
prevNotFound := false
|
|
|
|
for {
|
|
node, err := wac.query("message", jid, messageId, "after",
|
|
strconv.FormatBool(msgOwner), "", chunkSize, 0)
|
|
|
|
if err != nil {
|
|
|
|
// Whatsapp will return 404 status when there is wrong owner flag on the requested message id
|
|
if err == ErrServerRespondedWith404 {
|
|
|
|
// this will detect two consecutive "not found" errors.
|
|
// this is done to prevent infinite loop when wrong message id supplied
|
|
if prevNotFound {
|
|
log.Println("LoadFullChatHistoryAfter: could not retrieve any messages, wrong message id?")
|
|
return
|
|
}
|
|
prevNotFound = true
|
|
|
|
// try to reverse the owner flag and retry
|
|
if msgOwner {
|
|
// reverse initial msgOwner value and retry
|
|
msgOwner = false
|
|
|
|
<-time.After(time.Second)
|
|
continue
|
|
}
|
|
|
|
}
|
|
|
|
// if the error isn't a 404 error, pass it to the error handler
|
|
wac.handleWithCustomHandlers(err, handlers)
|
|
} else {
|
|
|
|
msgs := decodeMessages(node)
|
|
for _, msg := range msgs {
|
|
wac.handleWithCustomHandlers(ParseProtoMessage(msg), handlers)
|
|
wac.handleWithCustomHandlers(msg, handlers)
|
|
}
|
|
|
|
if len(msgs) != chunkSize {
|
|
break
|
|
}
|
|
|
|
messageId = *msgs[0].Key.Id
|
|
msgOwner = msgs[0].Key.FromMe != nil && *msgs[0].Key.FromMe
|
|
}
|
|
|
|
// message was found
|
|
prevNotFound = false
|
|
|
|
<-time.After(pauseBetweenQueries)
|
|
|
|
}
|
|
|
|
}
|