mirror of
https://github.com/tucnak/telebot
synced 2024-11-19 03:25:39 +00:00
Replace IQR*.MarshalJSON with InlineQueryResultBase
This commit gets rid of multiple redundant copies of MarhsalJSON() method present for all existing IQR. It does so by introducing a new struct called InlineQueryResultBase, which takes care of new Type (for JSON) and existing duplicated ID field. InlineQueryResults is a new helper wrapper for []IQR slices. It implements MarshalJSON, which makes sure IQR.ID and IQR.Type are set properly (by computing a hash and infering IQR type).
This commit is contained in:
commit
e5d60e6913
71
inline.go
71
inline.go
@ -1,6 +1,8 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"hash/fnv"
|
||||
"strconv"
|
||||
|
||||
@ -41,7 +43,7 @@ type QueryResponse struct {
|
||||
QueryID string `json:"inline_query_id"`
|
||||
|
||||
// The results for the inline query.
|
||||
Results []InlineQueryResult `json:"results"`
|
||||
Results InlineQueryResults `json:"results"`
|
||||
|
||||
// (Optional) The maximum amount of time in seconds that the result
|
||||
// of the inline query may be cached on the server.
|
||||
@ -70,18 +72,67 @@ type QueryResponse struct {
|
||||
|
||||
// InlineQueryResult represents one result of an inline query.
|
||||
type InlineQueryResult interface {
|
||||
MarshalJSON() ([]byte, error)
|
||||
id() (string, error)
|
||||
GetID() string
|
||||
SetID(string)
|
||||
}
|
||||
|
||||
// hashInlineQueryResult calculates the 64-bit FNV-1 hash of an
|
||||
// inline query result.
|
||||
func hashInlineQueryResult(result InlineQueryResult) (string, error) {
|
||||
hash, err := hashstructure.Hash(result, inlineQueryHashOptions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
// InlineQueryResults is a slice wrapper for convenient marshalling.
|
||||
type InlineQueryResults []InlineQueryResult
|
||||
|
||||
// MarshalJSON makes sure IQRs have proper IDs and Type variables set.
|
||||
//
|
||||
// If ID of some result appears empty, it gets set to a new hash.
|
||||
// JSON-specific Type gets infered from the actual (specific) IQR type.
|
||||
func (results *InlineQueryResults) MarshalJSON() ([]byte, error) {
|
||||
for i, result := range *results {
|
||||
if result.GetID() == "" {
|
||||
hash, err := hashstructure.Hash(result, inlineQueryHashOptions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("telebot: can't hash IQR #%d: %s",
|
||||
i, err)
|
||||
}
|
||||
|
||||
result.SetID(strconv.FormatUint(hash, 16))
|
||||
}
|
||||
|
||||
if err := inferIQR(result); err != nil {
|
||||
return nil, fmt.Errorf("telebot: can't infer type of IQR #%d: %s",
|
||||
i, err)
|
||||
}
|
||||
}
|
||||
return strconv.FormatUint(hash, 16), nil
|
||||
|
||||
return json.Marshal([]InlineQueryResult(*results))
|
||||
}
|
||||
|
||||
func inferIQR(result InlineQueryResult) error {
|
||||
switch r := result.(type) {
|
||||
case *InlineQueryResultArticle:
|
||||
r.Type = "article"
|
||||
case *InlineQueryResultAudio:
|
||||
r.Type = "audio"
|
||||
case *InlineQueryResultContact:
|
||||
r.Type = "contact"
|
||||
case *InlineQueryResultDocument:
|
||||
r.Type = "document"
|
||||
case *InlineQueryResultGif:
|
||||
r.Type = "gif"
|
||||
case *InlineQueryResultLocation:
|
||||
r.Type = "location"
|
||||
case *InlineQueryResultMpeg4Gif:
|
||||
r.Type = "mpeg4_gif"
|
||||
case *InlineQueryResultPhoto:
|
||||
r.Type = "photo"
|
||||
case *InlineQueryResultVenue:
|
||||
r.Type = "venue"
|
||||
case *InlineQueryResultVideo:
|
||||
r.Type = "video"
|
||||
case *InlineQueryResultVoice:
|
||||
r.Type = "voice"
|
||||
default:
|
||||
return fmt.Errorf("%T is not an IQR", result)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Result is a deprecated type, superseded by InlineQueryResult.
|
||||
|
387
inline_types.go
387
inline_types.go
@ -1,17 +1,31 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// InlineQueryResultArticle represents a link to an article or web page.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultarticle
|
||||
type InlineQueryResultArticle struct {
|
||||
// InlineQueryResultBase must be embedded into all IQRs.
|
||||
type InlineQueryResultBase struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
|
||||
// Ignore. This field gets set automatically.
|
||||
Type string `json:"type",hash:"ignore"`
|
||||
}
|
||||
|
||||
// GetID is part of IQRBase's implementation of IQR interface.
|
||||
func (result *InlineQueryResultBase) GetID() string {
|
||||
return result.ID
|
||||
}
|
||||
|
||||
// SetID is part of IQRBase's implementation of IQR interface.
|
||||
func (result *InlineQueryResultBase) SetID(id string) {
|
||||
result.ID = id
|
||||
}
|
||||
|
||||
// InlineQueryResultArticle represents a link to an article or web page.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultarticle
|
||||
type InlineQueryResultArticle struct {
|
||||
InlineQueryResultBase
|
||||
|
||||
// Title of the result.
|
||||
Title string `json:"title"`
|
||||
|
||||
@ -44,39 +58,9 @@ type InlineQueryResultArticle struct {
|
||||
ThumbHeight int `json:"thumb_height,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultArticle) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultArticle
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "article",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultArticle) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultAudio represents a link to an mp3 audio file.
|
||||
type InlineQueryResultAudio struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL for the audio file.
|
||||
AudioURL string `json:"audio_url"`
|
||||
@ -97,41 +81,10 @@ type InlineQueryResultAudio struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultAudio) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultAudio
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "audio",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultAudio) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultContact represents a contact with a phone number.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultcontact
|
||||
type InlineQueryResultContact struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// Contact's phone number.
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
@ -158,41 +111,10 @@ type InlineQueryResultContact struct {
|
||||
ThumbHeight int `json:"thumb_height,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultContact) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultContact
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "contact",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultContact) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultDocument represents a link to a file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultdocument
|
||||
type InlineQueryResultDocument struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// Title for the result.
|
||||
Title string `json:"title"`
|
||||
@ -226,41 +148,10 @@ type InlineQueryResultDocument struct {
|
||||
ThumbHeight int `json:"thumb_height,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultDocument) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultDocument
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "document",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultDocument) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultGif represents a link to an animated GIF file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultgif
|
||||
type InlineQueryResultGif struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL for the GIF file. File size must not exceed 1MB.
|
||||
GifURL string `json:"gif_url"`
|
||||
@ -287,42 +178,10 @@ type InlineQueryResultGif struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultGif) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultGif
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "gif",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultGif) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultLocation represents a location on a map.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultlocation
|
||||
type InlineQueryResultLocation struct {
|
||||
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// Latitude of the location in degrees.
|
||||
Latitude float32 `json:"latitude"`
|
||||
@ -349,42 +208,11 @@ type InlineQueryResultLocation struct {
|
||||
ThumbHeight int `json:"thumb_height,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultLocation) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultLocation
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "location",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultLocation) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultMpeg4Gif represents a link to a video animation
|
||||
// (H.264/MPEG-4 AVC video without sound).
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultmpeg4gif
|
||||
type InlineQueryResultMpeg4Gif struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL for the MP4 file.
|
||||
URL string `json:"mpeg4_url"`
|
||||
@ -411,41 +239,10 @@ type InlineQueryResultMpeg4Gif struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultMpeg4Gif) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultMpeg4Gif
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "mpeg4_gif",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultMpeg4Gif) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultPhoto represents a link to a photo.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultphoto
|
||||
type InlineQueryResultPhoto struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL of the photo. Photo must be in jpeg format.
|
||||
// Photo size must not exceed 5MB.
|
||||
@ -476,41 +273,10 @@ type InlineQueryResultPhoto struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultPhoto) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultPhoto
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "photo",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultPhoto) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultVenue represents a venue.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvenue
|
||||
type InlineQueryResultVenue struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// Latitude of the venue location in degrees.
|
||||
Latitude float32 `json:"latitude"`
|
||||
@ -543,42 +309,11 @@ type InlineQueryResultVenue struct {
|
||||
ThumbHeight int `json:"thumb_height,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVenue) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultVenue
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "venue",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVenue) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultVideo represents a link to a page containing an embedded
|
||||
// video player or a video file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvideo
|
||||
type InlineQueryResultVideo struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL for the embedded video player or video file.
|
||||
VideoURL string `json:"video_url"`
|
||||
@ -614,43 +349,11 @@ type InlineQueryResultVideo struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVideo) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultVideo
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "video",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVideo) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
||||
// InlineQueryResultVoice represents a link to a voice recording in a
|
||||
// .ogg container encoded with OPUS.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvoice
|
||||
type InlineQueryResultVoice struct {
|
||||
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
// from the other fields and used automatically.
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
InlineQueryResultBase
|
||||
|
||||
// A valid URL for the voice recording.
|
||||
VoiceURL string `json:"voice_url"`
|
||||
@ -667,31 +370,3 @@ type InlineQueryResultVoice struct {
|
||||
// Optional. Content of the message to be sent instead of the audio.
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVoice) MarshalJSON() ([]byte, error) {
|
||||
// avoiding endless self-recursion
|
||||
type wrapper InlineQueryResultVoice
|
||||
|
||||
id, err := r.id()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return json.Marshal(struct {
|
||||
wrapper
|
||||
Type string `json:"type"`
|
||||
ID string `json:"id",hash:"ignore"`
|
||||
}{
|
||||
wrapper: wrapper(*r),
|
||||
ID: id,
|
||||
Type: "voice",
|
||||
})
|
||||
}
|
||||
|
||||
func (r *InlineQueryResultVoice) id() (string, error) {
|
||||
if r.ID == "" {
|
||||
return hashInlineQueryResult(r)
|
||||
}
|
||||
|
||||
return r.ID, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user