Skip to content

Commit 5d49574

Browse files
committed
render incoming reaction
1 parent d79bd2b commit 5d49574

File tree

6 files changed

+1934
-1275
lines changed

6 files changed

+1934
-1275
lines changed

pkg/connector/handlegchat.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"fmt"
66
"time"
77

8+
"github.com/rs/zerolog"
89
"maunium.net/go/mautrix/bridgev2"
910
"maunium.net/go/mautrix/bridgev2/networkid"
1011
"maunium.net/go/mautrix/bridgev2/simplevent"
@@ -50,6 +51,8 @@ func (c *GChatClient) onStreamEvent(ctx context.Context, raw any) {
5051
}
5152

5253
c.setPortalRevision(ctx, evt)
54+
55+
c.handleReaction(ctx, evt)
5356
}
5457

5558
func (c *GChatClient) convertToMatrix(ctx context.Context, portal *bridgev2.Portal, intent bridgev2.MatrixAPI, msg *proto.Message) *bridgev2.ConvertedMessage {
@@ -96,3 +99,42 @@ func (c *GChatClient) convertToMatrix(ctx context.Context, portal *bridgev2.Port
9699

97100
return cm
98101
}
102+
103+
func (c *GChatClient) handleReaction(ctx context.Context, evt *proto.Event) {
104+
reaction := evt.Body.GetMessageReaction()
105+
if reaction == nil {
106+
return
107+
}
108+
109+
var eventType bridgev2.RemoteEventType
110+
if reaction.GetType() == proto.MessageReactionEvent_ADD {
111+
eventType = bridgev2.RemoteEventReaction
112+
} else {
113+
eventType = bridgev2.RemoteEventReactionRemove
114+
115+
}
116+
117+
sender := reaction.UserId.GetId()
118+
messageId := reaction.MessageId.GetMessageId()
119+
c.userLogin.Bridge.QueueRemoteEvent(c.userLogin, &simplevent.Reaction{
120+
EventMeta: simplevent.EventMeta{
121+
Type: eventType,
122+
LogContext: func(c zerolog.Context) zerolog.Context {
123+
return c.
124+
Str("message_id", messageId).
125+
Str("sender", sender).
126+
Str("emoji", reaction.Emoji.GetUnicode()).
127+
Str("type", reaction.GetType().String())
128+
},
129+
PortalKey: c.makePortalKey(evt),
130+
Timestamp: time.UnixMicro(*reaction.Timestamp),
131+
Sender: bridgev2.EventSender{
132+
IsFromMe: sender == string(c.userLogin.ID),
133+
Sender: networkid.UserID(sender),
134+
},
135+
},
136+
EmojiID: "",
137+
Emoji: reaction.Emoji.GetUnicode(),
138+
TargetMessage: networkid.MessageID(messageId),
139+
})
140+
}

pkg/connector/ids.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package connector
2+
3+
import (
4+
"maunium.net/go/mautrix/bridgev2/networkid"
5+
6+
"go.mau.fi/mautrix-googlechat/pkg/gchatmeow/proto"
7+
)
8+
9+
func (c *GChatClient) makePortalKey(evt *proto.Event) networkid.PortalKey {
10+
return networkid.PortalKey{
11+
ID: networkid.PortalID(evt.GroupId.String()),
12+
Receiver: c.userLogin.ID,
13+
}
14+
}

pkg/gchatmeow/channel.go

Lines changed: 17 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package gchatmeow
33
import (
44
"context"
55
"encoding/base64"
6-
"encoding/binary"
76
"encoding/json"
87
"errors"
98
"fmt"
@@ -17,7 +16,7 @@ import (
1716
"strconv"
1817
"strings"
1918
"time"
20-
"unicode/utf8"
19+
"unicode/utf16"
2120

2221
"go.mau.fi/util/pblite"
2322

@@ -62,6 +61,16 @@ type Channel struct {
6261
OnReceiveArray *Event
6362
}
6463

64+
type UTF16String []uint16
65+
66+
func NewUTF16String(s string) UTF16String {
67+
return utf16.Encode([]rune(s))
68+
}
69+
70+
func (u UTF16String) String() string {
71+
return string(utf16.Decode(u))
72+
}
73+
6574
type ChunkParser struct {
6675
buf []byte
6776
}
@@ -72,91 +81,24 @@ func NewChunkParser() *ChunkParser {
7281
}
7382
}
7483

75-
// bestEffortDecode attempts to decode as much UTF-8 data as possible from the buffer
76-
func bestEffortDecode(data []byte) string {
77-
valid := make([]byte, 0, len(data))
78-
for len(data) > 0 {
79-
r, size := utf8.DecodeRune(data)
80-
if r == utf8.RuneError {
81-
break
82-
}
83-
valid = append(valid, data[:size]...)
84-
data = data[size:]
85-
}
86-
return string(valid)
87-
}
88-
89-
// GetChunks yields chunks generated from received data.
90-
// The buffer may not be decodable as UTF-8 if there's a split multi-byte
91-
// character at the end. To handle this, we do a "best effort" decode of the
92-
// buffer to decode as much of it as possible.
9384
func (p *ChunkParser) GetChunks(newDataBytes []byte) []string {
9485
var chunks []string
9586
p.buf = append(p.buf, newDataBytes...)
9687

9788
for {
98-
// Decode buffer with best effort
99-
bufDecoded := bestEffortDecode(p.buf)
100-
101-
// Convert to UTF-16 (removing BOM)
102-
var bufUtf16 []byte
103-
for _, r := range bufDecoded {
104-
// Convert each rune to UTF-16
105-
buf := make([]byte, 2)
106-
binary.BigEndian.PutUint16(buf, uint16(r))
107-
bufUtf16 = append(bufUtf16, buf...)
108-
}
109-
110-
// Find length string match
111-
matches := lenRegex.FindStringSubmatch(bufDecoded)
112-
if matches == nil {
113-
break
114-
}
115-
116-
lengthStr := matches[1]
117-
// Both lengths are in number of bytes in UTF-16 encoding
89+
bufStr := string(p.buf)
90+
lengthStr, after, _ := strings.Cut(bufStr, "\n")
11891
length, err := strconv.Atoi(lengthStr)
11992
if err != nil {
12093
break
12194
}
122-
length *= 2 // Convert to UTF-16 byte count
123-
124-
// Calculate length of the submission length and newline in UTF-16
125-
lenStrAndNewline := lengthStr + "\n"
126-
var lenLength int
127-
for _, r := range lenStrAndNewline {
128-
lenLength += 2 // Each UTF-16 character is 2 bytes
129-
_ = r
130-
}
131-
132-
if len(bufUtf16)-lenLength < length {
95+
utf16Str := NewUTF16String(after)
96+
if len(utf16Str) < length {
13397
break
13498
}
13599

136-
// Extract submission
137-
submission := bufUtf16[lenLength : lenLength+length]
138-
139-
// Convert UTF-16 bytes back to string
140-
var result string
141-
for i := 0; i < len(submission); i += 2 {
142-
if i+1 >= len(submission) {
143-
break
144-
}
145-
char := binary.BigEndian.Uint16(submission[i : i+2])
146-
result += string(rune(char))
147-
}
148-
149-
chunks = append(chunks, result)
150-
151-
// Calculate how many bytes to drop from the buffer
152-
dropLength := len(matches[0]) // length of the length string and newline
153-
dropLength += len(result) // length of the actual content in UTF-8
154-
155-
if dropLength <= len(p.buf) {
156-
p.buf = p.buf[dropLength:]
157-
} else {
158-
p.buf = p.buf[:0]
159-
}
100+
chunks = append(chunks, utf16Str[0:length].String())
101+
p.buf = []byte(utf16Str[length:].String())
160102
}
161103

162104
return chunks

0 commit comments

Comments
 (0)