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)
 | |
| 
 | |
| 	}
 | |
| 
 | |
| }
 | 
