gmessages/libgm/session_handler.go

161 lines
3.9 KiB
Go
Raw Normal View History

2023-06-30 11:05:33 +00:00
package libgm
2023-06-30 09:54:08 +00:00
import (
"fmt"
2023-07-15 12:57:07 +00:00
"sync"
2023-06-30 09:54:08 +00:00
"time"
"golang.org/x/exp/slices"
"google.golang.org/protobuf/proto"
"go.mau.fi/mautrix-gmessages/libgm/pblite"
2023-06-30 09:54:08 +00:00
"go.mau.fi/mautrix-gmessages/libgm/binary"
"go.mau.fi/mautrix-gmessages/libgm/payload"
"go.mau.fi/mautrix-gmessages/libgm/routes"
2023-06-30 09:54:08 +00:00
"go.mau.fi/mautrix-gmessages/libgm/util"
)
/*
2023-06-30 09:54:08 +00:00
type Response struct {
client *Client
ResponseId string
2023-06-30 09:54:08 +00:00
RoutingOpCode int64
Data *binary.EncodedResponse // base64 encoded (decode -> protomessage)
2023-06-30 09:54:08 +00:00
StartExecute string
2023-06-30 09:54:08 +00:00
FinishExecute string
DevicePair *pblite.DevicePair
2023-06-30 09:54:08 +00:00
}
*/
2023-06-30 09:54:08 +00:00
type SessionHandler struct {
client *Client
requests map[string]map[binary.ActionType]*ResponseChan
2023-06-30 09:54:08 +00:00
2023-07-15 12:57:07 +00:00
ackMapLock sync.Mutex
ackMap []string
ackTicker *time.Ticker
2023-06-30 09:54:08 +00:00
sessionId string
2023-06-30 09:54:08 +00:00
responseTimeout time.Duration
}
func (s *SessionHandler) SetResponseTimeout(milliSeconds int) {
s.responseTimeout = time.Duration(milliSeconds) * time.Millisecond
}
func (s *SessionHandler) ResetSessionId() {
s.sessionId = util.RandomUUIDv4()
2023-06-30 09:54:08 +00:00
}
func (s *SessionHandler) completeSendMessage(actionType binary.ActionType, addToChannel bool, encryptedData proto.Message) (string, error) {
requestId, payload, action, buildErr := s.buildMessage(actionType, encryptedData)
if buildErr != nil {
return "", buildErr
2023-06-30 09:54:08 +00:00
}
if addToChannel {
s.addRequestToChannel(requestId, action)
2023-06-30 09:54:08 +00:00
}
_, reqErr := s.client.rpc.sendMessageRequest(util.SEND_MESSAGE, payload)
if reqErr != nil {
return "", reqErr
2023-06-30 09:54:08 +00:00
}
return requestId, nil
}
2023-06-30 09:54:08 +00:00
func (s *SessionHandler) buildMessage(actionType binary.ActionType, encryptedData proto.Message) (string, []byte, binary.ActionType, error) {
var requestId string
pairedDevice := s.client.authData.DevicePair.Mobile
sessionId := s.client.sessionHandler.sessionId
token := s.client.authData.TachyonAuthToken
2023-06-30 09:54:08 +00:00
routeInfo, ok := routes.Routes[actionType]
if !ok {
return "", nil, 0, fmt.Errorf("failed to build message: could not find route %d", actionType)
2023-06-30 09:54:08 +00:00
}
if routeInfo.UseSessionID {
requestId = s.sessionId
} else {
requestId = util.RandomUUIDv4()
2023-06-30 09:54:08 +00:00
}
tmpMessage := payload.NewSendMessageBuilder(token, pairedDevice, requestId, sessionId).SetRoute(routeInfo.Action).SetSessionId(s.sessionId)
if encryptedData != nil {
tmpMessage.SetEncryptedProtoMessage(encryptedData, s.client.authData.Cryptor)
2023-06-30 09:54:08 +00:00
}
if routeInfo.UseTTL {
tmpMessage.SetTTL(s.client.authData.TTL)
2023-06-30 09:54:08 +00:00
}
message, buildErr := tmpMessage.Build()
if buildErr != nil {
return "", nil, 0, buildErr
2023-06-30 09:54:08 +00:00
}
return requestId, message, routeInfo.Action, nil
2023-06-30 09:54:08 +00:00
}
func (s *SessionHandler) addResponseAck(responseId string) {
s.client.Logger.Debug().Any("responseId", responseId).Msg("Added to ack map")
2023-07-15 12:57:07 +00:00
s.ackMapLock.Lock()
defer s.ackMapLock.Unlock()
2023-06-30 09:54:08 +00:00
hasResponseId := slices.Contains(s.ackMap, responseId)
if !hasResponseId {
s.ackMap = append(s.ackMap, responseId)
}
}
func (s *SessionHandler) startAckInterval() {
if s.ackTicker != nil {
s.ackTicker.Stop()
}
ticker := time.NewTicker(5 * time.Second)
s.ackTicker = ticker
go func() {
for range ticker.C {
s.sendAckRequest()
}
}()
}
func (s *SessionHandler) sendAckRequest() {
2023-07-15 12:57:07 +00:00
s.ackMapLock.Lock()
dataToAck := s.ackMap
s.ackMap = nil
2023-07-15 12:57:07 +00:00
s.ackMapLock.Unlock()
if len(dataToAck) == 0 {
return
}
ackMessages := make([]*binary.AckMessageData, len(dataToAck))
for i, reqID := range dataToAck {
ackMessages[i] = &binary.AckMessageData{
RequestID: reqID,
Device: s.client.authData.DevicePair.Browser,
}
}
2023-06-30 09:54:08 +00:00
ackMessagePayload := &binary.AckMessagePayload{
AuthData: &binary.AuthMessage{
RequestID: util.RandomUUIDv4(),
TachyonAuthToken: s.client.authData.TachyonAuthToken,
ConfigVersion: payload.ConfigMessage,
2023-06-30 09:54:08 +00:00
},
EmptyArr: &binary.EmptyArr{},
Acks: ackMessages,
2023-06-30 09:54:08 +00:00
}
jsonData, err := pblite.Marshal(ackMessagePayload)
2023-06-30 09:54:08 +00:00
if err != nil {
2023-07-09 20:32:19 +00:00
panic(err)
2023-06-30 09:54:08 +00:00
}
_, err = s.client.rpc.sendMessageRequest(util.ACK_MESSAGES, jsonData)
if err != nil {
2023-07-09 20:32:19 +00:00
panic(err)
2023-06-30 09:54:08 +00:00
}
2023-07-15 15:49:28 +00:00
s.client.Logger.Debug().Strs("message_ids", dataToAck).Msg("Sent acks")
2023-06-30 09:54:08 +00:00
}