Remove cache

This commit is contained in:
Tulir Asokan 2023-06-30 13:31:25 +03:00
parent 5e5344742e
commit 82ddf46de7
12 changed files with 11 additions and 641 deletions

66
libgm/cache/cache.go vendored
View file

@ -1,66 +0,0 @@
package cache
import (
"encoding/json"
"fmt"
"log"
"os"
"strconv"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type Cache struct {
Conversations Conversations `json:"conversations"`
Settings Settings `json:"sim,omitempty"`
}
func LoadCache(path string) Cache {
data, readErr := os.ReadFile(path)
if readErr != nil {
log.Fatal(readErr)
}
var cache Cache
err := json.Unmarshal(data, &cache)
if err != nil {
log.Fatal(err)
}
return cache
}
func (c *Cache) OrderMapToInterface() map[string]interface{} {
convIdMapStringInterface := make(map[string]interface{})
for key, value := range c.Conversations.Order {
convIdMapStringInterface[strconv.Itoa(key)] = value
}
return convIdMapStringInterface
}
func (c *Cache) SetSettings(settings *binary.Settings) {
c.Settings = Settings{
CarrierName: settings.Data.SimData.CarrierName,
HexHash: settings.Data.SimData.HexHash,
Version: settings.Version,
}
}
func (c *Cache) SetMessages(messages *binary.FetchMessagesResponse) {
for _, msg := range messages.Messages {
convo, ok := c.Conversations.Conversations[msg.ConversationId]
if !ok {
// handle error, such as creating a new conversation or returning
fmt.Printf("Could not find conversation with id %s", msg.ConversationId)
return
} else {
convo.UpdateMessage(msg)
}
}
}
func (c *Cache) SetConversations(conversations *binary.Conversations) {
for order, conv := range conversations.Conversations {
convertedConv := NewConversation(c, conv)
c.Conversations.Order[order] = conv.ConversationId
c.Conversations.Conversations[conv.ConversationId] = convertedConv
}
}

View file

@ -1,290 +0,0 @@
package cache
import (
"fmt"
"log"
"sort"
"go.mau.fi/mautrix-gmessages/libgm/binary"
)
type SmallInfo struct {
Type int64 `json:"type,omitempty"`
Number string `json:"number,omitempty"`
ParticipantId string `json:"participantId,omitempty"`
}
type Participant struct {
SmallInfo *SmallInfo `json:"smallInfo,omitempty"`
HexHash string `json:"hexHash,omitempty"`
IsMe bool `json:"isMe,omitempty"`
Bs int64 `json:"bs,omitempty"`
DisplayName string `json:"displayName,omitempty"`
}
type ImagePixels struct {
Width int64 `json:"width,omitempty"`
Height int64 `json:"height,omitempty"`
}
type ImageMessage struct {
SomeNumber int64 `json:"someNumber"`
ImageId string `json:"imageId"`
ImageName string `json:"imageName"`
Size int64 `json:"size"`
Pixels ImagePixels `json:"pixels"`
ImageBuffer []byte `json:"imageBuffer"`
DecryptionKey []byte `json:"decryptionKey"`
}
type TextMessage struct {
Content string `json:"content"`
}
type IsFromMe struct {
FromMe bool `json:"fromMe"`
}
type MessageData struct {
OrderInternal string `json:"orderInternal"`
TextData *TextMessage `json:"textData,omitempty"`
ImageData *ImageMessage `json:"imageData,omitempty"`
}
type MessageStatus struct {
Code int64 `json:"code,omitempty"`
ErrMsg string `json:"errMsg,omitempty"`
MsgType string `json:"msgType,omitempty"`
}
type Message struct {
cache *Cache
MessageId string `json:"messageId"`
From IsFromMe `json:"from"`
MessageStatus MessageStatus `json:"details"`
Timestamp int64 `json:"timestamp"`
ConvId string `json:"convId"`
ParticipantId string `json:"participantId"`
MessageData []MessageData `json:"messageData"`
MessageType string `json:"messageType"`
}
func (m *Message) FromMe() bool {
conv, _ := m.cache.Conversations.GetConversation(m.ConvId)
return m.ParticipantId == conv.SelfParticipantId
}
type LatestMessage struct {
Content string `json:"content,omitempty"`
FromMe bool `json:"fromMe,omitempty"`
DisplayName string `json:"displayName,omitempty"`
MessageId string `json:"messageId,omitempty"`
}
type Conversation struct {
cache *Cache
MessageOrder map[int]string `json:"messageOrder"`
Messages map[string]Message `json:"messages"`
ConversationId string `json:"conversationId"`
DisplayName string `json:"displayName"`
LatestMessage LatestMessage `json:"latestMessage"`
IsGroupChat bool `json:"isGroupChat,omitempty"`
Timestamp int64 `json:"timestamp"`
Status int64 `json:"status"`
HexHash string `json:"hexHash"`
Type int64 `json:"type"`
SelfParticipantId string `json:"selfParticipantId,omitempty"`
Participants []Participant `json:"participants"`
ParticipantIds []string `json:"participantIds,omitempty"` // excluded self id
}
type Conversations struct {
cache *Cache
/*
{0: "1", 1: "4"}
order -> conversationId
index 0 = first conversation in order
*/
Order map[int]string `json:"order"`
/*
Map conversations by conversationId
*/
Conversations map[string]*Conversation `json:"conversations"`
}
func (c *Conversations) SetCache(cache *Cache) {
c.cache = cache
}
func (c *Conversations) DeleteConversation(convId string) {
delete(c.Conversations, convId)
}
func (c *Conversations) UpdateConversation(conversation *binary.Conversation) *Conversation {
newConversation := NewConversation(c.cache, conversation)
c.Conversations[conversation.ConversationId] = newConversation
return newConversation
}
func (c *Conversation) GetMessage(msgId string) (Message, error) {
message, foundMsg := c.Messages[msgId]
if !foundMsg {
return Message{}, fmt.Errorf("could not find that message cached")
}
return message, nil
}
func (c *Conversation) Delete() {
c.cache.Conversations.DeleteConversation(c.ConversationId)
}
func (c *Conversation) UpdateMessage(msg *binary.Message) Message {
newMsg := NewMessage(c.cache, msg)
if c.Messages == nil {
log.Println("c.messages was nil so created new map")
c.Messages = make(map[string]Message)
}
c.Messages[msg.MessageId] = newMsg
return newMsg
}
func (c *Conversations) GetConversationByOrder(order int) (*Conversation, error) {
convId, ok := c.Order[order]
if !ok {
return &Conversation{}, fmt.Errorf("could not find a conversation that occupies that order")
}
conversation, foundConvo := c.Conversations[convId]
if !foundConvo {
return &Conversation{}, fmt.Errorf("could not find that conversation cached, oddly enough it seems to be cached in the order map though... investigate further")
}
return conversation, nil
}
func (c *Conversation) GetOrderSlice() []string {
keys := make([]string, 0, len(c.Messages))
for k := range c.Messages {
keys = append(keys, k)
}
sort.Slice(keys, func(i, j int) bool {
return c.Messages[keys[i]].Timestamp < c.Messages[keys[j]].Timestamp
})
return keys
}
func (c *Conversations) GetOrderSlice() []int {
s := make([]int, 0)
for i := range c.Order {
s = append(s, i)
}
return s
}
func (c *Conversations) GetConversation(convId string) (*Conversation, error) {
convo, ok := c.Conversations[convId]
if !ok {
// handle error, such as creating a new conversation or returning
return &Conversation{}, fmt.Errorf("could not find conversation cached")
} else {
return convo, nil
}
}
func NewConversation(cache *Cache, conv *binary.Conversation) *Conversation {
currConv, convErr := cache.Conversations.GetConversation(conv.ConversationId)
participants := ParseParticipants(conv.Participants)
newConversation := Conversation{
cache: cache,
ConversationId: conv.ConversationId,
DisplayName: conv.Name,
Timestamp: conv.TimestampMs,
Status: conv.Status,
HexHash: conv.HashHex,
Type: conv.Type,
Participants: participants,
ParticipantIds: conv.OtherParticipants,
SelfParticipantId: conv.SelfParticipantId,
}
if conv.LatestMessage != nil {
newConversation.LatestMessage = LatestMessage{
Content: conv.LatestMessage.Content,
FromMe: conv.LatestMessage.FromMe,
DisplayName: conv.LatestMessage.DisplayName,
MessageId: conv.MessageId,
}
}
if convErr == nil {
newConversation.MessageOrder = currConv.MessageOrder
newConversation.Messages = currConv.Messages
} else {
newConversation.MessageOrder = make(map[int]string)
newConversation.Messages = make(map[string]Message)
}
return &newConversation
}
func ParseParticipants(participants []*binary.Participant) []Participant {
partSlice := make([]Participant, 0)
for _, p := range participants {
partSlice = append(partSlice, Participant{
SmallInfo: &SmallInfo{
Type: p.SmallInfo.Type,
Number: p.SmallInfo.Number,
ParticipantId: p.SmallInfo.ParticipantId,
},
HexHash: p.HashHex,
IsMe: p.IsMe,
Bs: p.Bs,
DisplayName: p.DisplayName,
})
}
return partSlice
}
func NewMessage(cache *Cache, message *binary.Message) Message {
msg := Message{
cache: cache,
MessageId: message.MessageId,
ConvId: message.ConversationId,
From: IsFromMe{
FromMe: message.From.FromMe,
},
Timestamp: message.Timestamp,
ParticipantId: message.ParticipantId,
MessageType: message.Type.String(),
MessageStatus: MessageStatus{
Code: message.MessageStatus.Code,
ErrMsg: message.MessageStatus.ErrMsg,
MsgType: message.MessageStatus.MsgStatus,
},
MessageData: make([]MessageData, 0),
}
for _, data := range message.MessageInfo {
msgData := MessageData{
OrderInternal: data.OrderInternal,
}
switch d := data.Data.(type) {
case *binary.MessageInfo_ImageContent:
msgData.ImageData = &ImageMessage{
SomeNumber: d.ImageContent.SomeNumber,
ImageId: d.ImageContent.ImageId,
ImageName: d.ImageContent.ImageName,
Size: d.ImageContent.Size,
Pixels: ImagePixels{Width: d.ImageContent.Pixels.Width, Height: d.ImageContent.Pixels.Height},
ImageBuffer: d.ImageContent.ImageData,
DecryptionKey: d.ImageContent.DecryptionKey,
}
case *binary.MessageInfo_MessageContent:
msgData.TextData = &TextMessage{
Content: d.MessageContent.Content,
}
}
msg.MessageData = append(msg.MessageData, msgData)
}
return msg
}

View file

@ -1,7 +0,0 @@
package cache
type Settings struct {
CarrierName string `json:"carrierName,omitempty"`
HexHash string `json:"hexHash,omitempty"`
Version string `json:"version,omitempty"`
}

View file

@ -1,18 +1,15 @@
package textgapi
import (
"encoding/json"
"io"
"log"
"net/http"
"net/url"
"os"
"time"
"github.com/rs/zerolog"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/util"
@ -42,8 +39,6 @@ type Client struct {
proxy Proxy
http *http.Client
cache cache.Cache
}
func NewClient(devicePair *DevicePair, cryptor *crypto.Cryptor, logger zerolog.Logger, proxy *string) *Client {
@ -61,7 +56,6 @@ func NewClient(devicePair *DevicePair, cryptor *crypto.Cryptor, logger zerolog.L
cryptor: cryptor,
imageCryptor: &crypto.ImageCryptor{},
http: &http.Client{},
cache: cache.Cache{},
}
sessionHandler.client = cli
cli.instructions = NewInstructions(cli.cryptor)
@ -71,11 +65,6 @@ func NewClient(devicePair *DevicePair, cryptor *crypto.Cryptor, logger zerolog.L
rpc := &RPC{client: cli, http: &http.Client{Transport: &http.Transport{Proxy: cli.proxy}}}
cli.rpc = rpc
cli.Logger.Debug().Any("data", cryptor).Msg("Cryptor")
cli.cache.Conversations = cache.Conversations{
Conversations: make(map[string]*cache.Conversation),
Order: make(map[int]string),
}
cli.cache.Conversations.SetCache(&cli.cache)
cli.setApiMethods()
return cli
}
@ -228,15 +217,3 @@ func (c *Client) decryptImageData(imageId string, key []byte) ([]byte, error) {
}
return decryptedImageBytes, nil
}
func (c *Client) SaveCache(path string) {
toSaveJson, jsonErr := json.Marshal(c.cache)
if jsonErr != nil {
log.Fatal(jsonErr)
}
os.WriteFile(path, toSaveJson, os.ModePerm)
}
func (c *Client) GetCache() cache.Cache {
return c.cache
}

View file

@ -31,22 +31,16 @@ func (c *Conversations) List(count int64) (*binary.Conversations, error) {
}
if decryptedData, ok := decryptedProto.(*binary.Conversations); ok {
c.client.cache.SetConversations(decryptedData)
return decryptedData, nil
} else {
return nil, fmt.Errorf("failed to assert decryptedProto into type Conversations")
}
}
func (c *Conversations) SendMessage(messageBuilder *MessageBuilder) (*binary.SendMessageResponse, error) {
conv, notFound := c.client.cache.Conversations.GetConversation(messageBuilder.GetConversationId())
if notFound != nil {
log.Fatal(notFound)
}
func (c *Conversations) SendMessage(messageBuilder *MessageBuilder, selfParticipantID string) (*binary.SendMessageResponse, error) {
hasSelfParticipantId := messageBuilder.GetSelfParticipantId()
if hasSelfParticipantId == "" {
messageBuilder.SetSelfParticipantId(conv.SelfParticipantId)
messageBuilder.SetSelfParticipantId(selfParticipantID)
}
encryptedProtoPayload, failedToBuild := messageBuilder.Build()
@ -98,7 +92,6 @@ func (c *Conversations) FetchMessages(convId string, count int64, cursor *binary
return nil, processFail
}
c.client.cache.SetMessages(fetchedMessagesResponse)
return fetchedMessagesResponse, nil
}

View file

@ -1,67 +0,0 @@
package events
import "go.mau.fi/mautrix-gmessages/libgm/cache"
type ConversationEvent interface {
GetConversation() *cache.Conversation
}
// Triggered when tabbing out of a conversation
type CONVERSATION_EXIT struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_EXIT) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is archived
type CONVERSATION_ARCHIVED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_ARCHIVED) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is unarchived
type CONVERSATION_UNARCHIVED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_UNARCHIVED) GetConversation() *cache.Conversation {
return c.Conversation
}
// Triggered when a conversation is deleted
type CONVERSATION_DELETED struct {
Conversation *cache.Conversation
}
func (c *CONVERSATION_DELETED) GetConversation() *cache.Conversation {
return c.Conversation
}
func NewConversationExit(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_EXIT{
Conversation: conversation,
}
}
func NewConversationArchived(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_ARCHIVED{
Conversation: conversation,
}
}
func NewConversationUnarchived(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_UNARCHIVED{
Conversation: conversation,
}
}
func NewConversationDeleted(conversation *cache.Conversation) ConversationEvent {
return &CONVERSATION_DELETED{
Conversation: conversation,
}
}

View file

@ -1,65 +0,0 @@
package events
import (
"go.mau.fi/mautrix-gmessages/libgm/cache"
)
type MessageEvent interface {
GetMessage() cache.Message
}
type MESSAGE_SENDING struct {
Message cache.Message
}
func (m *MESSAGE_SENDING) GetMessage() cache.Message {
return m.Message
}
func NewMessageSending(message cache.Message) MessageEvent {
return &MESSAGE_SENDING{
Message: message,
}
}
type MESSAGE_SENT struct {
Message cache.Message
}
func (m *MESSAGE_SENT) GetMessage() cache.Message {
return m.Message
}
func NewMessageSent(message cache.Message) MessageEvent {
return &MESSAGE_SENT{
Message: message,
}
}
type MESSAGE_RECEIVING struct {
Message cache.Message
}
func (m *MESSAGE_RECEIVING) GetMessage() cache.Message {
return m.Message
}
func NewMessageReceiving(message cache.Message) MessageEvent {
return &MESSAGE_RECEIVING{
Message: message,
}
}
type MESSAGE_RECEIVED struct {
Message cache.Message
}
func (m *MESSAGE_RECEIVED) GetMessage() cache.Message {
return m.Message
}
func NewMessageReceived(message cache.Message) MessageEvent {
return &MESSAGE_RECEIVED{
Message: message,
}
}

View file

@ -2,43 +2,8 @@ package textgapi
import (
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
func (c *Client) handleConversationEvent(response *Response, evtData *binary.Event_ConversationEvent) {
lastCacheConv, notExists := c.cache.Conversations.GetConversation(evtData.ConversationEvent.Data.ConversationId)
evtConv := evtData.ConversationEvent.Data
//c.Logger.Debug().Any("convData", evtConv).Msg("Got conversation event!")
var eventData events.ConversationEvent
if evtConv.Status == 3 {
lastCacheConv.Delete()
eventData = events.NewConversationDeleted(lastCacheConv)
c.triggerEvent(eventData)
return
}
updatedCacheConv := c.cache.Conversations.UpdateConversation(evtConv)
eventData = c.getConversationEventInterface(lastCacheConv, updatedCacheConv, notExists)
if eventData == nil {
return
}
c.triggerEvent(eventData)
}
func (c *Client) getConversationEventInterface(lastCacheConv *cache.Conversation, updatedCacheConv *cache.Conversation, notExists error) events.ConversationEvent {
var evt events.ConversationEvent
convStatus := updatedCacheConv.Status
switch convStatus {
case 1: // unarchived
if lastCacheConv.Status != 1 {
evt = events.NewConversationUnarchived(updatedCacheConv)
}
case 2: // archived
evt = events.NewConversationArchived(updatedCacheConv)
case 3: // deleted
evt = events.NewConversationDeleted(updatedCacheConv)
}
return evt
c.triggerEvent(evtData)
}

View file

@ -1,57 +1,9 @@
package textgapi
import (
"log"
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/cache"
//"github.com/0xzer/textgapi/cache"
"go.mau.fi/mautrix-gmessages/libgm/events"
)
func (c *Client) handleMessageEvent(response *Response, evtData *binary.Event_MessageEvent) {
msgData := evtData.MessageEvent.Data
currConv, convNotFound := c.cache.Conversations.GetConversation(msgData.ConversationId)
if convNotFound != nil {
log.Fatal(convNotFound)
}
lastCacheMsg, errGetMsg := currConv.GetMessage(msgData.MessageId)
updatedCacheMsg := currConv.UpdateMessage(msgData)
eventData := c.getMessageEventInterface(currConv, lastCacheMsg, errGetMsg, updatedCacheMsg)
if eventData == nil {
return
}
c.triggerEvent(eventData)
}
func (c *Client) getMessageEventInterface(currConv *cache.Conversation, lastCacheMsg cache.Message, lastCacheErr error, evtMsg cache.Message) events.MessageEvent {
var evt events.MessageEvent
msgStatusCode := evtMsg.MessageStatus.Code
fromMe := evtMsg.FromMe()
switch msgStatusCode {
case 5: // sending
if lastCacheErr != nil {
if fromMe {
evt = events.NewMessageSending(evtMsg)
} else {
evt = events.NewMessageReceiving(evtMsg)
}
}
case 1: // sent
if lastCacheMsg.MessageStatus.Code != 1 {
if fromMe {
evt = events.NewMessageSent(evtMsg)
} else {
evt = events.NewMessageReceived(evtMsg)
}
}
default:
c.Logger.Debug().Any("data", evtMsg).Msg("Unknown msgstatus code")
}
return evt
c.triggerEvent(evtData)
}

View file

@ -1,11 +1,6 @@
package textgapi
import (
"fmt"
"os"
validator "github.com/gabriel-vasile/mimetype"
"go.mau.fi/mautrix-gmessages/libgm/crypto"
"go.mau.fi/mautrix-gmessages/libgm/util"
)
@ -102,27 +97,15 @@ func (i *Image) GetImageId() string {
return i.imageId
}
func (mb *MessageBuilder) AddImageFromPath(filePath string) *MessageBuilder {
if mb.err != nil {
return mb
}
file, err := os.ReadFile(filePath)
if err != nil {
mb.err = err
return mb
}
return mb.AddImage(file)
}
// This is the equivalent of dragging an image into the window on messages web
//
// Keep in mind that adding an image to a MessageBuilder will also upload the image to googles server
func (mb *MessageBuilder) AddImage(imgBytes []byte) *MessageBuilder {
func (mb *MessageBuilder) AddImage(imgBytes []byte, mime string) *MessageBuilder {
if mb.err != nil {
return mb
}
newImage, newImageErr := mb.newImageData(imgBytes)
newImage, newImageErr := mb.newImageData(imgBytes, mime)
if newImageErr != nil {
mb.err = newImageErr
return mb
@ -144,12 +127,9 @@ func (mb *MessageBuilder) AddImage(imgBytes []byte) *MessageBuilder {
return mb
}
func (mb *MessageBuilder) newImageData(imgBytes []byte) (*Image, error) {
imgFormat := validator.Detect(imgBytes)
if imgFormat.String() == "text/plain" {
return nil, fmt.Errorf("could not validate media content-type: received %s", imgFormat.String())
}
imgType := ImageTypes[imgFormat.String()]
func (mb *MessageBuilder) newImageData(imgBytes []byte, mime string) (*Image, error) {
// TODO explode on unsupported types
imgType := ImageTypes[mime]
imageId := util.GenerateImageId()
imageName := util.RandStr(8) + "." + imgType.Extension
decryptionKey, err := crypto.GenerateKey(32)

View file

@ -27,7 +27,6 @@ func (s *Session) SetActiveSession() (*util.SessionResponse, error) {
return nil, processFail
}
s.client.cache.SetSettings(sessionResponse.Settings)
return sessionResponse, nil
}

View file

@ -8,7 +8,7 @@ import (
"net/http"
"time"
uuid "github.com/nu7hatch/gouuid"
"github.com/google/uuid"
)
var Charset = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890")
@ -47,8 +47,7 @@ func RandomHex(n int) string {
}
func RandomUUIDv4() string {
id, _ := uuid.NewV4()
return id.String()
return uuid.New().String()
}
func RemoveFromSlice(s []string, v string) []string {