1
0
Fork 0
mirror of https://github.com/mautrix/discord.git synced 2026-07-07 14:53:17 -04:00
mautrix-discord/pkg/discordid/mediaid.go

166 lines
4 KiB
Go
Raw Permalink Normal View History

2026-03-19 23:33:14 -07:00
// mautrix-discord - A Matrix-Discord puppeting bridge.
// Copyright (C) 2026 Tulir Asokan
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
package discordid
import (
"encoding/binary"
"fmt"
"strconv"
"maunium.net/go/mautrix/bridgev2/networkid"
)
type DirectMediaType byte
const (
DirectMediaTypeV1 DirectMediaType = 1
encodedSnowflakeSize = 8
encodedMediaIDV1Size = 1 + 4*encodedSnowflakeSize
)
func (dmt DirectMediaType) isSupported() bool {
switch dmt {
case DirectMediaTypeV1:
return true
}
return false
}
type MediaInfoV1 struct {
2026-03-19 23:33:14 -07:00
UserLoginID networkid.UserLoginID
ChannelID string
MessageID string
AttachmentID string
}
type MediaInfo struct {
Type DirectMediaType
MediaInfoV1
}
func NewMediaInfoV1(userLoginID networkid.UserLoginID, channelID, messageID, attachmentID string) MediaInfo {
return MediaInfo{
Type: DirectMediaTypeV1,
MediaInfoV1: MediaInfoV1{
UserLoginID: userLoginID,
ChannelID: channelID,
MessageID: messageID,
AttachmentID: attachmentID,
},
}
}
2026-03-19 23:33:14 -07:00
func (mi *MediaInfo) Encode() ([]byte, error) {
buf := make([]byte, 1, encodedMediaIDV1Size)
buf[0] = byte(mi.Type)
appendSnowflake := func(what, snowflakeStr string) error {
snowflake, err := strconv.ParseUint(snowflakeStr, 10, 64)
if err != nil {
return fmt.Errorf("invalid %s: %w", what, err)
}
buf = binary.BigEndian.AppendUint64(buf, snowflake)
return nil
}
if err := appendSnowflake("user login id", ParseUserLoginID(mi.UserLoginID)); err != nil {
return nil, err
}
if err := appendSnowflake("channel id", mi.ChannelID); err != nil {
return nil, err
}
if err := appendSnowflake("message id", mi.MessageID); err != nil {
return nil, err
}
if err := appendSnowflake("attachment id", mi.AttachmentID); err != nil {
return nil, err
}
return buf, nil
}
func ParseMediaID(mediaID networkid.MediaID) (*MediaInfo, error) {
var info MediaInfo
ptr := 0
read := func(size int, what string) ([]byte, error) {
if len(mediaID) < ptr+size {
return nil, fmt.Errorf("media ID too short (%d bytes) to read %d byte %s starting at byte %d", len(mediaID), size, what, ptr)
}
b := mediaID[ptr : ptr+size]
ptr += size
return b, nil
}
readOne := func(what string) (byte, error) {
b, err := read(1, what)
if err != nil {
return 0, err
}
return b[0], nil
}
readSnowflake := func(what string) (string, error) {
snowflakeBytes, err := read(encodedSnowflakeSize, what)
if err != nil {
return "", err
}
snowflake := binary.BigEndian.Uint64(snowflakeBytes)
return strconv.FormatUint(snowflake, 10), nil
}
mediaType, err := readOne("media type")
if err != nil {
return nil, err
}
info.Type = DirectMediaType(mediaType)
if !info.Type.isSupported() {
return nil, fmt.Errorf("unrecognized media type %d", info.Type)
}
userLoginID, err := readSnowflake("user login id")
info.UserLoginID = networkid.UserLoginID(userLoginID)
if err != nil {
return nil, err
}
channelID, err := readSnowflake("channel id")
info.ChannelID = channelID
if err != nil {
return nil, err
}
messageID, err := readSnowflake("message id")
info.MessageID = messageID
if err != nil {
return nil, err
}
attachmentID, err := readSnowflake("attachment id")
info.AttachmentID = attachmentID
if err != nil {
return nil, err
}
if ptr != len(mediaID) {
return nil, fmt.Errorf("media ID has %d trailing bytes", len(mediaID)-ptr)
}
return &info, nil
}