move gotd fork into repo. (#111)
- update to latest telegram layer - remove some references to fields in tg.Entities that don't exist in the schema - originally added here: https://github.com/beeper/td/commit/820929062a2ba0104397bc01235ab58a9cff780e - referenced here - https://github.com/mautrix/telegramgo/commit/124f0967ed195b5a380c9bd02e170ada9710dde3 - https://github.com/mautrix/telegramgo/commit/4205047aab2e0639217148b5d125bfaab668bd8e
This commit is contained in:
@@ -0,0 +1,401 @@
|
||||
package tljson
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"strconv"
|
||||
|
||||
"github.com/go-faster/errors"
|
||||
"github.com/go-faster/jx"
|
||||
|
||||
"go.mau.fi/mautrix-telegram/pkg/gotd/tg"
|
||||
)
|
||||
|
||||
// EmojiSound represents emoji sound file location.
|
||||
//
|
||||
// See https://core.telegram.org/api/animated-emojis#emojis-with-sounds.
|
||||
type EmojiSound struct {
|
||||
ID int64 `json:"id"`
|
||||
AccessHash int64 `json:"access_hash"`
|
||||
FileReference []byte `json:"file_reference_base64"`
|
||||
}
|
||||
|
||||
// DecodeJSON decodes EmojiSound.
|
||||
func (e *EmojiSound) DecodeJSON(d *jx.Decoder) error {
|
||||
return d.ObjBytes(func(d *jx.Decoder, key []byte) error {
|
||||
switch string(key) {
|
||||
case "id":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode id")
|
||||
}
|
||||
|
||||
id, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse id")
|
||||
}
|
||||
e.ID = id
|
||||
case "access_hash":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode access_hash")
|
||||
}
|
||||
|
||||
accessHash, err := strconv.ParseInt(v, 10, 64)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "parse access_hash")
|
||||
}
|
||||
e.AccessHash = accessHash
|
||||
case "file_reference_base64":
|
||||
encoded, err := d.StrBytes()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode file_reference_base64")
|
||||
}
|
||||
encoding := base64.RawURLEncoding
|
||||
|
||||
e.FileReference = make([]byte, encoding.DecodedLen(len(encoded)))
|
||||
n, err := encoding.Decode(e.FileReference, encoded)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "un-base64 file_reference_base64")
|
||||
}
|
||||
e.FileReference = e.FileReference[:n]
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// EmojiSendDiceSuccess represents the winning dice value and the final frame of the animated sticker.
|
||||
//
|
||||
// See https://core.telegram.org/api/dice.
|
||||
type EmojiSendDiceSuccess struct {
|
||||
Value int `json:"value"`
|
||||
FrameStart int `json:"frame_start"`
|
||||
}
|
||||
|
||||
// DecodeJSON decodes EmojiSendDiceSuccess.
|
||||
func (e *EmojiSendDiceSuccess) DecodeJSON(d *jx.Decoder) error {
|
||||
return d.ObjBytes(func(d *jx.Decoder, key []byte) error {
|
||||
switch string(key) {
|
||||
case "value":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode value")
|
||||
}
|
||||
e.Value = v
|
||||
case "frame_start":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode frame_start")
|
||||
}
|
||||
e.FrameStart = v
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// RoundVideoEncoding represents a set of recommended codec parameters for round videos.
|
||||
type RoundVideoEncoding struct {
|
||||
Diameter int `json:"diameter"`
|
||||
VideoBitrate int `json:"video_bitrate"`
|
||||
AudioBitrate int `json:"audio_bitrate"`
|
||||
MaxSize int `json:"max_size"`
|
||||
}
|
||||
|
||||
// DecodeJSON decodes RoundVideoEncoding.
|
||||
func (e *RoundVideoEncoding) DecodeJSON(d *jx.Decoder) error {
|
||||
return d.ObjBytes(func(d *jx.Decoder, key []byte) error {
|
||||
switch string(key) {
|
||||
case "diameter":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode diameter")
|
||||
}
|
||||
e.Diameter = v
|
||||
case "video_bitrate":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode video_bitrate")
|
||||
}
|
||||
e.VideoBitrate = v
|
||||
case "audio_bitrate":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode audio_bitrate")
|
||||
}
|
||||
e.AudioBitrate = v
|
||||
case "max_size":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode max_size")
|
||||
}
|
||||
e.MaxSize = v
|
||||
default:
|
||||
return d.Skip()
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// AppConfig represents app config structure.
|
||||
//
|
||||
// See https://core.telegram.org/api/config#client-configuration.
|
||||
type AppConfig struct {
|
||||
Test int `json:"test"`
|
||||
// Animated emojis and animated dice should be scaled by this factor before being shown to the user.
|
||||
EmojiesAnimatedZoom float64 `json:"emojies_animated_zoom"`
|
||||
// A list of supported animated dice stickers.
|
||||
EmojiesSendDice []string `json:"emojies_send_dice"`
|
||||
// For animated dice emojis other than the basic 🎲, indicates the winning dice value
|
||||
// and the final frame of the animated sticker, at which to show the fireworks.
|
||||
EmojiesSendDiceSuccess map[string]EmojiSendDiceSuccess `json:"emojies_send_dice_success"`
|
||||
// A map of soundbites to be played when the user clicks on the specified animated emoji.
|
||||
//
|
||||
// The file reference field should be base64-decoded before downloading the file.
|
||||
EmojiesSounds map[string]EmojiSound `json:"emojies_sounds"`
|
||||
// Specifies the name of the service providing GIF search through gif_search_username.
|
||||
GIFSearchBranding string `json:"gif_search_branding"`
|
||||
// Specifies a list of emojies that should be suggested as search term in a bar above the GIF search box.
|
||||
GIFSearchEmojies []string `json:"gif_search_emojies"`
|
||||
// Specifies that the app should not display local sticker suggestions
|
||||
// for emojis at all and just use the result of messages.getStickers.
|
||||
StickersEmojiSuggestOnlyAPI bool `json:"stickers_emoji_suggest_only_api"`
|
||||
// Specifies the validity period of the local cache of messages.getStickers,
|
||||
// also relevant when generating the pagination hash when invoking the method.
|
||||
StickersEmojiCacheTime int `json:"stickers_emoji_cache_time"`
|
||||
GroupCallVideoParticipantsMax int `json:"groupcall_video_participants_max"`
|
||||
YoutubePIP string `json:"youtube_pip"`
|
||||
// Whether the Settings->Devices menu should show an option to scan a QR login code.
|
||||
QRLoginCamera bool `json:"qr_login_camera"`
|
||||
// Whether the login screen should show a QR code login option, possibly
|
||||
// as default login method ("disabled", "primary" or "secondary")
|
||||
QRLoginCode string `json:"qr_login_code"`
|
||||
// Whether clients should show an option for managing dialog filters AKA folders.
|
||||
DialogFiltersEnabled bool `json:"dialog_filters_enabled"`
|
||||
// Whether clients should actively show a tooltip, inviting the user to configure dialog filters AKA folders.
|
||||
//
|
||||
// Typically, this happens when the chat list is long enough to start getting cluttered.
|
||||
DialogFiltersTooltip bool `json:"dialog_filters_tooltip"`
|
||||
// Whether clients can invoke account.setGlobalPrivacySettings
|
||||
// with globalPrivacySettings.archive_and_mute_new_noncontact_peers = boolTrue,
|
||||
// to automatically archive and mute new incoming chats from non-contacts.
|
||||
AutoArchiveSettingAvailable bool `json:"autoarchive_setting_available"`
|
||||
// Contains a list of suggestions that should be actively shown as a tooltip to the user.
|
||||
PendingSuggestions []string `json:"pending_suggestions"`
|
||||
// Autologin token.
|
||||
//
|
||||
// See https://core.telegram.org/api/url-authorization#link-url-authorization.
|
||||
AutologinToken string `json:"autologin_token"`
|
||||
// A list of Telegram domains that support automatic login with no user confirmation.
|
||||
//
|
||||
// See https://core.telegram.org/api/url-authorization#link-url-authorization.
|
||||
AutologinDomains []string `json:"autologin_domains"`
|
||||
// A list of domains that support automatic login with manual user confirmation.
|
||||
//
|
||||
// See https://core.telegram.org/api/url-authorization#link-url-authorization.
|
||||
URLAuthDomains []string `json:"url_auth_domains"`
|
||||
// Contains a set of recommended codec parameters for round videos.
|
||||
RoundVideoEncoding RoundVideoEncoding `json:"round_video_encoding"`
|
||||
// To protect user privacy, read receipts are only stored for
|
||||
// chat_read_mark_expire_period seconds after the message was sent.
|
||||
ChatReadMarkExpirePeriod int `json:"chat_read_mark_expire_period"`
|
||||
// Per-user read receipts, fetchable using messages.getMessageReadParticipants
|
||||
// will be available in groups with less than chat_read_mark_size_threshold participants.
|
||||
ChatReadMarkSizeThreshold int `json:"chat_read_mark_size_threshold"`
|
||||
|
||||
// Unparsed is map of unknown unparsed fields.
|
||||
Unparsed map[string]tg.JSONValueClass
|
||||
}
|
||||
|
||||
func decodeStringArray(d *jx.Decoder, array *[]string) error {
|
||||
return d.Arr(func(d *jx.Decoder) error {
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "decode %d", len(*array))
|
||||
}
|
||||
*array = append(*array, v)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DecodeJSON decodes AppConfig.
|
||||
func (e *AppConfig) DecodeJSON(d *jx.Decoder) error {
|
||||
// TODO(tdakkota): use schema-based parser
|
||||
return d.ObjBytes(func(d *jx.Decoder, key []byte) error {
|
||||
switch string(key) {
|
||||
case "test":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode test")
|
||||
}
|
||||
e.Test = v
|
||||
case "emojies_animated_zoom":
|
||||
v, err := d.Float64()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode emojies_animated_zoom")
|
||||
}
|
||||
e.EmojiesAnimatedZoom = v
|
||||
case "emojies_send_dice":
|
||||
if err := decodeStringArray(d, &e.EmojiesSendDice); err != nil {
|
||||
return errors.Wrap(err, "decode emojies_send_dice")
|
||||
}
|
||||
case "emojies_send_dice_success":
|
||||
if e.EmojiesSendDiceSuccess == nil {
|
||||
e.EmojiesSendDiceSuccess = map[string]EmojiSendDiceSuccess{}
|
||||
}
|
||||
if err := d.Obj(func(d *jx.Decoder, key string) error {
|
||||
var v EmojiSendDiceSuccess
|
||||
if err := v.DecodeJSON(d); err != nil {
|
||||
return errors.Wrapf(err, "decode %q", key)
|
||||
}
|
||||
e.EmojiesSendDiceSuccess[key] = v
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode emojies_send_dice_success")
|
||||
}
|
||||
case "emojies_sounds":
|
||||
if e.EmojiesSounds == nil {
|
||||
e.EmojiesSounds = map[string]EmojiSound{}
|
||||
}
|
||||
if err := d.Obj(func(d *jx.Decoder, key string) error {
|
||||
var v EmojiSound
|
||||
if err := v.DecodeJSON(d); err != nil {
|
||||
return errors.Wrapf(err, "decode %q", key)
|
||||
}
|
||||
e.EmojiesSounds[key] = v
|
||||
return nil
|
||||
}); err != nil {
|
||||
return errors.Wrap(err, "decode emojies_sounds")
|
||||
}
|
||||
case "gif_search_branding":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode gif_search_branding")
|
||||
}
|
||||
e.GIFSearchBranding = v
|
||||
case "gif_search_emojies":
|
||||
if err := decodeStringArray(d, &e.GIFSearchEmojies); err != nil {
|
||||
return errors.Wrap(err, "decode gif_search_emojies")
|
||||
}
|
||||
case "stickers_emoji_suggest_only_api":
|
||||
v, err := d.Bool()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode stickers_emoji_suggest_only_api")
|
||||
}
|
||||
e.StickersEmojiSuggestOnlyAPI = v
|
||||
case "stickers_emoji_cache_time":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode stickers_emoji_cache_time")
|
||||
}
|
||||
e.StickersEmojiCacheTime = v
|
||||
case "groupcall_video_participants_max":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode groupcall_video_participants_max")
|
||||
}
|
||||
e.GroupCallVideoParticipantsMax = v
|
||||
case "youtube_pip":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode youtube_pip")
|
||||
}
|
||||
e.YoutubePIP = v
|
||||
case "qr_login_camera":
|
||||
v, err := d.Bool()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode qr_login_camera")
|
||||
}
|
||||
e.QRLoginCamera = v
|
||||
case "qr_login_code":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode qr_login_code")
|
||||
}
|
||||
e.QRLoginCode = v
|
||||
case "dialog_filters_enabled":
|
||||
v, err := d.Bool()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode dialog_filters_enabled")
|
||||
}
|
||||
e.DialogFiltersEnabled = v
|
||||
case "dialog_filters_tooltip":
|
||||
v, err := d.Bool()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode dialog_filters_tooltip")
|
||||
}
|
||||
e.DialogFiltersTooltip = v
|
||||
case "autoarchive_setting_available":
|
||||
v, err := d.Bool()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode autoarchive_setting_available")
|
||||
}
|
||||
e.AutoArchiveSettingAvailable = v
|
||||
case "pending_suggestions":
|
||||
if err := decodeStringArray(d, &e.PendingSuggestions); err != nil {
|
||||
return errors.Wrap(err, "decode pending_suggestions")
|
||||
}
|
||||
case "autologin_token":
|
||||
v, err := d.Str()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode autologin_token")
|
||||
}
|
||||
e.AutologinToken = v
|
||||
case "autologin_domains":
|
||||
if err := decodeStringArray(d, &e.AutologinDomains); err != nil {
|
||||
return errors.Wrap(err, "decode autologin_domains")
|
||||
}
|
||||
case "url_auth_domains":
|
||||
if err := decodeStringArray(d, &e.URLAuthDomains); err != nil {
|
||||
return errors.Wrap(err, "decode url_auth_domains")
|
||||
}
|
||||
case "round_video_encoding":
|
||||
if err := e.RoundVideoEncoding.DecodeJSON(d); err != nil {
|
||||
return errors.Wrap(err, "decode round_video_encoding")
|
||||
}
|
||||
case "chat_read_mark_expire_period":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode chat_read_mark_expire_period")
|
||||
}
|
||||
e.ChatReadMarkExpirePeriod = v
|
||||
case "chat_read_mark_size_threshold":
|
||||
v, err := d.Int()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "decode chat_read_mark_size_threshold")
|
||||
}
|
||||
e.ChatReadMarkSizeThreshold = v
|
||||
default:
|
||||
if e.Unparsed == nil {
|
||||
e.Unparsed = map[string]tg.JSONValueClass{}
|
||||
}
|
||||
v, err := Decode(d)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "decode %q", key)
|
||||
}
|
||||
e.Unparsed[string(key)] = v
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// DecodeJSONValue decodes AppConfig from tg.JSONValueClass.
|
||||
func (e *AppConfig) DecodeJSONValue(val tg.JSONValueClass) error {
|
||||
v, ok := val.(*tg.JSONObject)
|
||||
if !ok {
|
||||
return errors.Errorf("unexpected type %T", val)
|
||||
}
|
||||
|
||||
// TODO(tdakkota): decode directly
|
||||
encoder := jx.GetEncoder()
|
||||
Encode(v, encoder)
|
||||
|
||||
return e.DecodeJSON(jx.DecodeBytes(encoder.Bytes()))
|
||||
}
|
||||
Reference in New Issue
Block a user