[WIP] Update deps
This commit is contained in:
2
vendor/github.com/NicoNex/echotron/v3/README.md
generated
vendored
2
vendor/github.com/NicoNex/echotron/v3/README.md
generated
vendored
@@ -1,4 +1,4 @@
|
||||
| <img src="assets/readme_banner.png" alt="logo" width="800"><br/><br/> [](https://golang.org/) [](https://pkg.go.dev/github.com/NicoNex/echotron/v3) [](https://goreportcard.com/report/github.com/NicoNex/echotron/v3) [](https://github.com/NicoNex/echotron/blob/master/LICENSE) [](https://coveralls.io/github/NicoNex/echotron?branch=master) [](https://github.com/avelino/awesome-go) [](https://t.me/echotronnews) |
|
||||
| <img src="assets/readme_banner.png" alt="logo" width="800"><br/><br/> [](https://golang.org/) [](https://pkg.go.dev/github.com/NicoNex/echotron/v3) [](https://goreportcard.com/report/github.com/NicoNex/echotron/v3) [](https://codecov.io/gh/NicoNex/echotron) [](https://github.com/NicoNex/echotron/blob/master/LICENSE) [](https://github.com/avelino/awesome-go) [](https://t.me/echotronnews) |
|
||||
| :------: |
|
||||
|
||||
**Echotron** is an elegant and concurrent library for the Telegram bot API in Go.
|
||||
|
||||
225
vendor/github.com/NicoNex/echotron/v3/api.go
generated
vendored
225
vendor/github.com/NicoNex/echotron/v3/api.go
generated
vendored
@@ -27,21 +27,32 @@ import (
|
||||
|
||||
// API is the object that contains all the functions that wrap those of the Telegram Bot API.
|
||||
type API struct {
|
||||
token string
|
||||
base string
|
||||
client *client
|
||||
token string
|
||||
base string
|
||||
}
|
||||
|
||||
// NewAPI returns a new API object.
|
||||
func NewAPI(token string) API {
|
||||
return API{
|
||||
token: token,
|
||||
base: fmt.Sprintf("https://api.telegram.org/bot%s/", token),
|
||||
token: token,
|
||||
base: fmt.Sprintf("https://api.telegram.org/bot%s/", token),
|
||||
client: lclient,
|
||||
}
|
||||
}
|
||||
|
||||
// NewLocalAPI is like NewAPI but allows to use a local API server.
|
||||
func NewLocalAPI(url, token string) API {
|
||||
return API{
|
||||
token: token,
|
||||
base: url,
|
||||
client: lclient,
|
||||
}
|
||||
}
|
||||
|
||||
// GetUpdates is used to receive incoming updates using long polling.
|
||||
func (a API) GetUpdates(opts *UpdateOptions) (res APIResponseUpdate, err error) {
|
||||
return get[APIResponseUpdate](a.base, "getUpdates", urlValues(opts))
|
||||
return res, a.client.get(a.base, "getUpdates", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// SetWebhook is used to specify a url and receive incoming updates via an outgoing webhook.
|
||||
@@ -60,7 +71,7 @@ func (a API) SetWebhook(webhookURL string, dropPendingUpdates bool, opts *Webhoo
|
||||
addValues(vals, opts)
|
||||
url = fmt.Sprintf("%s?%s", strings.TrimSuffix(url, "/"), vals.Encode())
|
||||
|
||||
cnt, err := sendPostForm(url, keyVal)
|
||||
cnt, err := a.client.doPostForm(url, keyVal)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -78,17 +89,17 @@ func (a API) DeleteWebhook(dropPendingUpdates bool) (res APIResponseBase, err er
|
||||
var vals = make(url.Values)
|
||||
vals.Set("drop_pending_updates", btoa(dropPendingUpdates))
|
||||
|
||||
return get[APIResponseBase](a.base, "deleteWebhook", vals)
|
||||
return res, a.client.get(a.base, "deleteWebhook", vals, &res)
|
||||
}
|
||||
|
||||
// GetWebhookInfo is used to get current webhook status.
|
||||
func (a API) GetWebhookInfo() (res APIResponseWebhook, err error) {
|
||||
return get[APIResponseWebhook](a.base, "getWebhookInfo", nil)
|
||||
return res, a.client.get(a.base, "getWebhookInfo", nil, &res)
|
||||
}
|
||||
|
||||
// GetMe is a simple method for testing your bot's auth token.
|
||||
func (a API) GetMe() (res APIResponseUser, err error) {
|
||||
return get[APIResponseUser](a.base, "getMe", nil)
|
||||
return res, a.client.get(a.base, "getMe", nil, &res)
|
||||
}
|
||||
|
||||
// LogOut is used to log out from the cloud Bot API server before launching the bot locally.
|
||||
@@ -96,14 +107,14 @@ func (a API) GetMe() (res APIResponseUser, err error) {
|
||||
// After a successful call, you can immediately log in on a local server,
|
||||
// but will not be able to log in back to the cloud Bot API server for 10 minutes.
|
||||
func (a API) LogOut() (res APIResponseBool, err error) {
|
||||
return get[APIResponseBool](a.base, "logOut", nil)
|
||||
return res, a.client.get(a.base, "logOut", nil, &res)
|
||||
}
|
||||
|
||||
// Close is used to close the bot instance before moving it from one local server to another.
|
||||
// You need to delete the webhook before calling this method to ensure that the bot isn't launched again after server restart.
|
||||
// The method will return error 429 in the first 10 minutes after the bot is launched.
|
||||
func (a API) Close() (res APIResponseBool, err error) {
|
||||
return get[APIResponseBool](a.base, "close", nil)
|
||||
return res, a.client.get(a.base, "close", nil, &res)
|
||||
}
|
||||
|
||||
// SendMessage is used to send text messages.
|
||||
@@ -112,7 +123,7 @@ func (a API) SendMessage(text string, chatID int64, opts *MessageOptions) (res A
|
||||
|
||||
vals.Set("text", text)
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseMessage](a.base, "sendMessage", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendMessage", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// ForwardMessage is used to forward messages of any kind.
|
||||
@@ -123,7 +134,7 @@ func (a API) ForwardMessage(chatID, fromChatID int64, messageID int, opts *Forwa
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("from_chat_id", itoa(fromChatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseMessage](a.base, "forwardMessage", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "forwardMessage", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// ForwardMessages is used to forward multiple messages of any kind.
|
||||
@@ -141,7 +152,7 @@ func (a API) ForwardMessages(chatID, fromChatID int64, messageIDs []int, opts *F
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("from_chat_id", itoa(fromChatID))
|
||||
vals.Set("message_ids", string(msgIDs))
|
||||
return get[APIResponseMessageIDs](a.base, "forwardMessages", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "forwardMessages", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// CopyMessage is used to copy messages of any kind.
|
||||
@@ -154,7 +165,7 @@ func (a API) CopyMessage(chatID, fromChatID int64, messageID int, opts *CopyOpti
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("from_chat_id", itoa(fromChatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseMessageID](a.base, "copyMessage", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "copyMessage", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// CopyMessages is used to copy messages of any kind.
|
||||
@@ -174,7 +185,7 @@ func (a API) CopyMessages(chatID, fromChatID int64, messageIDs []int, opts *Copy
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("from_chat_id", itoa(fromChatID))
|
||||
vals.Set("message_ids", string(msgIDs))
|
||||
return get[APIResponseMessageIDs](a.base, "copyMessages", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "copyMessages", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendPhoto is used to send photos.
|
||||
@@ -182,7 +193,7 @@ func (a API) SendPhoto(file InputFile, chatID int64, opts *PhotoOptions) (res AP
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendPhoto", "photo", file, InputFile{}, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendPhoto", "photo", file, InputFile{}, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendAudio is used to send audio files,
|
||||
@@ -199,7 +210,7 @@ func (a API) SendAudio(file InputFile, chatID int64, opts *AudioOptions) (res AP
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendAudio", "audio", file, thumbnail, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendAudio", "audio", file, thumbnail, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendDocument is used to send general files.
|
||||
@@ -214,7 +225,7 @@ func (a API) SendDocument(file InputFile, chatID int64, opts *DocumentOptions) (
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendDocument", "document", file, thumbnail, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendDocument", "document", file, thumbnail, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendVideo is used to send video files.
|
||||
@@ -230,7 +241,7 @@ func (a API) SendVideo(file InputFile, chatID int64, opts *VideoOptions) (res AP
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendVideo", "video", file, thumbnail, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendVideo", "video", file, thumbnail, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendAnimation is used to send animation files (GIF or H.264/MPEG-4 AVC video without sound).
|
||||
@@ -245,7 +256,7 @@ func (a API) SendAnimation(file InputFile, chatID int64, opts *AnimationOptions)
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendAnimation", "animation", file, thumbnail, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendAnimation", "animation", file, thumbnail, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendVoice is used to send audio files, if you want Telegram clients to display the file as a playable voice message.
|
||||
@@ -254,7 +265,7 @@ func (a API) SendVoice(file InputFile, chatID int64, opts *VoiceOptions) (res AP
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendVoice", "voice", file, InputFile{}, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendVoice", "voice", file, InputFile{}, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendVideoNote is used to send video messages.
|
||||
@@ -269,7 +280,7 @@ func (a API) SendVideoNote(file InputFile, chatID int64, opts *VideoNoteOptions)
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseMessage](a.base, "sendVideoNote", "video_note", file, thumbnail, addValues(vals, opts))
|
||||
return res, a.client.postFile(a.base, "sendVideoNote", "video_note", file, thumbnail, addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendMediaGroup is used to send a group of photos, videos, documents or audios as an album.
|
||||
@@ -278,7 +289,7 @@ func (a API) SendMediaGroup(chatID int64, media []GroupableInputMedia, opts *Med
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postMedia[APIResponseMessageArray](a.base, "sendMediaGroup", false, addValues(vals, opts), toInputMedia(media)...)
|
||||
return res, a.client.postMedia(a.base, "sendMediaGroup", false, addValues(vals, opts), &res, toInputMedia(media)...)
|
||||
}
|
||||
|
||||
// SendLocation is used to send point on the map.
|
||||
@@ -288,7 +299,7 @@ func (a API) SendLocation(chatID int64, latitude, longitude float64, opts *Locat
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("latitude", ftoa(latitude))
|
||||
vals.Set("longitude", ftoa(longitude))
|
||||
return get[APIResponseMessage](a.base, "sendLocation", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendLocation", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// EditMessageLiveLocation is used to edit live location messages.
|
||||
@@ -298,12 +309,12 @@ func (a API) EditMessageLiveLocation(msg MessageIDOptions, latitude, longitude f
|
||||
|
||||
vals.Set("latitude", ftoa(latitude))
|
||||
vals.Set("longitude", ftoa(longitude))
|
||||
return get[APIResponseMessage](a.base, "editMessageLiveLocation", addValues(addValues(vals, msg), opts))
|
||||
return res, a.client.get(a.base, "editMessageLiveLocation", addValues(addValues(vals, msg), opts), &res)
|
||||
}
|
||||
|
||||
// StopMessageLiveLocation is used to stop updating a live location message before `LivePeriod` expires.
|
||||
func (a API) StopMessageLiveLocation(msg MessageIDOptions, opts *MessageReplyMarkup) (res APIResponseMessage, err error) {
|
||||
return get[APIResponseMessage](a.base, "stopMessageLiveLocation", addValues(urlValues(msg), opts))
|
||||
func (a API) StopMessageLiveLocation(msg MessageIDOptions, opts *StopLocationOptions) (res APIResponseMessage, err error) {
|
||||
return res, a.client.get(a.base, "stopMessageLiveLocation", addValues(urlValues(msg), opts), &res)
|
||||
}
|
||||
|
||||
// SendVenue is used to send information about a venue.
|
||||
@@ -315,7 +326,7 @@ func (a API) SendVenue(chatID int64, latitude, longitude float64, title, address
|
||||
vals.Set("longitude", ftoa(longitude))
|
||||
vals.Set("title", title)
|
||||
vals.Set("address", address)
|
||||
return get[APIResponseMessage](a.base, "sendVenue", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendVenue", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendContact is used to send phone contacts.
|
||||
@@ -325,11 +336,11 @@ func (a API) SendContact(phoneNumber, firstName string, chatID int64, opts *Cont
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("phone_number", phoneNumber)
|
||||
vals.Set("first_name", firstName)
|
||||
return get[APIResponseMessage](a.base, "sendContact", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendContact", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendPoll is used to send a native poll.
|
||||
func (a API) SendPoll(chatID int64, question string, options []string, opts *PollOptions) (res APIResponseMessage, err error) {
|
||||
func (a API) SendPoll(chatID int64, question string, options []InputPollOption, opts *PollOptions) (res APIResponseMessage, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
pollOpts, err := json.Marshal(options)
|
||||
@@ -340,7 +351,7 @@ func (a API) SendPoll(chatID int64, question string, options []string, opts *Pol
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("question", question)
|
||||
vals.Set("options", string(pollOpts))
|
||||
return get[APIResponseMessage](a.base, "sendPoll", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendPoll", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendDice is used to send an animated emoji that will display a random value.
|
||||
@@ -349,7 +360,7 @@ func (a API) SendDice(chatID int64, emoji DiceEmoji, opts *BaseOptions) (res API
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("emoji", string(emoji))
|
||||
return get[APIResponseMessage](a.base, "sendDice", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendDice", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SendChatAction is used to tell the user that something is happening on the bot's side.
|
||||
@@ -359,7 +370,7 @@ func (a API) SendChatAction(action ChatAction, chatID int64, opts *ChatActionOpt
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("action", string(action))
|
||||
return get[APIResponseBool](a.base, "sendChatAction", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendChatAction", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SetMessageReaction is used to change the chosen reactions on a message.
|
||||
@@ -371,7 +382,7 @@ func (a API) SetMessageReaction(chatID int64, messageID int, opts *MessageReacti
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseBool](a.base, "setMessageReaction", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "setMessageReaction", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// GetUserProfilePhotos is used to get a list of profile pictures for a user.
|
||||
@@ -379,7 +390,7 @@ func (a API) GetUserProfilePhotos(userID int64, opts *UserProfileOptions) (res A
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseUserProfile](a.base, "getUserProfilePhotos", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "getUserProfilePhotos", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// GetFile returns the basic info about a file and prepares it for downloading.
|
||||
@@ -391,14 +402,14 @@ func (a API) GetFile(fileID string) (res APIResponseFile, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("file_id", fileID)
|
||||
return get[APIResponseFile](a.base, "getFile", vals)
|
||||
return res, a.client.get(a.base, "getFile", vals, &res)
|
||||
}
|
||||
|
||||
// DownloadFile returns the bytes of the file corresponding to the given filePath.
|
||||
// This function is callable for at least 1 hour since the call to GetFile.
|
||||
// When the download expires a new one can be requested by calling GetFile again.
|
||||
func (a API) DownloadFile(filePath string) ([]byte, error) {
|
||||
return sendGetRequest(fmt.Sprintf(
|
||||
return a.client.doGet(fmt.Sprintf(
|
||||
"https://api.telegram.org/file/bot%s/%s",
|
||||
a.token,
|
||||
filePath,
|
||||
@@ -414,7 +425,7 @@ func (a API) BanChatMember(chatID, userID int64, opts *BanOptions) (res APIRespo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseBool](a.base, "banChatMember", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "banChatMember", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// UnbanChatMember is used to unban a previously banned user in a supergroup or channel.
|
||||
@@ -428,7 +439,7 @@ func (a API) UnbanChatMember(chatID, userID int64, opts *UnbanOptions) (res APIR
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseBool](a.base, "unbanChatMember", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "unbanChatMember", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// RestrictChatMember is used to restrict a user in a supergroup.
|
||||
@@ -436,15 +447,15 @@ func (a API) UnbanChatMember(chatID, userID int64, opts *UnbanOptions) (res APIR
|
||||
func (a API) RestrictChatMember(chatID, userID int64, permissions ChatPermissions, opts *RestrictOptions) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
perm, err := serializePerms(permissions)
|
||||
perm, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("permissions", perm)
|
||||
return get[APIResponseBool](a.base, "restrictChatMember", addValues(vals, opts))
|
||||
vals.Set("permissions", string(perm))
|
||||
return res, a.client.get(a.base, "restrictChatMember", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// PromoteChatMember is used to promote or demote a user in a supergroup or a channel.
|
||||
@@ -454,7 +465,7 @@ func (a API) PromoteChatMember(chatID, userID int64, opts *PromoteOptions) (res
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseBool](a.base, "promoteChatMember", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "promoteChatMember", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SetChatAdministratorCustomTitle is used to set a custom title for an administrator in a supergroup promoted by the bot.
|
||||
@@ -464,7 +475,7 @@ func (a API) SetChatAdministratorCustomTitle(chatID, userID int64, customTitle s
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("custom_title", customTitle)
|
||||
return get[APIResponseBool](a.base, "setChatAdministratorCustomTitle", vals)
|
||||
return res, a.client.get(a.base, "setChatAdministratorCustomTitle", vals, &res)
|
||||
}
|
||||
|
||||
// BanChatSenderChat is used to ban a channel chat in a supergroup or a channel.
|
||||
@@ -475,7 +486,7 @@ func (a API) BanChatSenderChat(chatID, senderChatID int64) (res APIResponseBool,
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("sender_chat_id", itoa(senderChatID))
|
||||
return get[APIResponseBool](a.base, "banChatSenderChat", vals)
|
||||
return res, a.client.get(a.base, "banChatSenderChat", vals, &res)
|
||||
}
|
||||
|
||||
// UnbanChatSenderChat is used to unban a previously channel chat in a supergroup or channel.
|
||||
@@ -485,7 +496,7 @@ func (a API) UnbanChatSenderChat(chatID, senderChatID int64) (res APIResponseBoo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("sender_chat_id", itoa(senderChatID))
|
||||
return get[APIResponseBool](a.base, "unbanChatSenderChat", vals)
|
||||
return res, a.client.get(a.base, "unbanChatSenderChat", vals, &res)
|
||||
}
|
||||
|
||||
// SetChatPermissions is used to set default chat permissions for all members.
|
||||
@@ -493,14 +504,14 @@ func (a API) UnbanChatSenderChat(chatID, senderChatID int64) (res APIResponseBoo
|
||||
func (a API) SetChatPermissions(chatID int64, permissions ChatPermissions, opts *ChatPermissionsOptions) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
perm, err := serializePerms(permissions)
|
||||
perm, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("permissions", perm)
|
||||
return get[APIResponseBool](a.base, "setChatPermissions", addValues(vals, opts))
|
||||
vals.Set("permissions", string(perm))
|
||||
return res, a.client.get(a.base, "setChatPermissions", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// ExportChatInviteLink is used to generate a new primary invite link for a chat;
|
||||
@@ -510,7 +521,7 @@ func (a API) ExportChatInviteLink(chatID int64) (res APIResponseString, err erro
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseString](a.base, "exportChatInviteLink", vals)
|
||||
return res, a.client.get(a.base, "exportChatInviteLink", vals, &res)
|
||||
}
|
||||
|
||||
// CreateChatInviteLink is used to create an additional invite link for a chat.
|
||||
@@ -520,7 +531,7 @@ func (a API) CreateChatInviteLink(chatID int64, opts *InviteLinkOptions) (res AP
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseInviteLink](a.base, "createChatInviteLink", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "createChatInviteLink", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// EditChatInviteLink is used to edit a non-primary invite link created by the bot.
|
||||
@@ -530,7 +541,7 @@ func (a API) EditChatInviteLink(chatID int64, inviteLink string, opts *InviteLin
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("invite_link", inviteLink)
|
||||
return get[APIResponseInviteLink](a.base, "editChatInviteLink", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "editChatInviteLink", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// RevokeChatInviteLink is used to revoke an invite link created by the bot.
|
||||
@@ -541,7 +552,7 @@ func (a API) RevokeChatInviteLink(chatID int64, inviteLink string) (res APIRespo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("invite_link", inviteLink)
|
||||
return get[APIResponseInviteLink](a.base, "editChatInviteLink", vals)
|
||||
return res, a.client.get(a.base, "editChatInviteLink", vals, &res)
|
||||
}
|
||||
|
||||
// ApproveChatJoinRequest is used to approve a chat join request.
|
||||
@@ -551,7 +562,7 @@ func (a API) ApproveChatJoinRequest(chatID, userID int64) (res APIResponseBool,
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseBool](a.base, "approveChatJoinRequest", vals)
|
||||
return res, a.client.get(a.base, "approveChatJoinRequest", vals, &res)
|
||||
}
|
||||
|
||||
// DeclineChatJoinRequest is used to decline a chat join request.
|
||||
@@ -561,7 +572,7 @@ func (a API) DeclineChatJoinRequest(chatID, userID int64) (res APIResponseBool,
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseBool](a.base, "declineChatJoinRequest", vals)
|
||||
return res, a.client.get(a.base, "declineChatJoinRequest", vals, &res)
|
||||
}
|
||||
|
||||
// SetChatPhoto is used to set a new profile photo for the chat.
|
||||
@@ -571,7 +582,7 @@ func (a API) SetChatPhoto(file InputFile, chatID int64) (res APIResponseBool, er
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return postFile[APIResponseBool](a.base, "setChatPhoto", "photo", file, InputFile{}, vals)
|
||||
return res, a.client.postFile(a.base, "setChatPhoto", "photo", file, InputFile{}, vals, &res)
|
||||
}
|
||||
|
||||
// DeleteChatPhoto is used to delete a chat photo.
|
||||
@@ -581,7 +592,7 @@ func (a API) DeleteChatPhoto(chatID int64) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "deleteChatPhoto", vals)
|
||||
return res, a.client.get(a.base, "deleteChatPhoto", vals, &res)
|
||||
}
|
||||
|
||||
// SetChatTitle is used to change the title of a chat.
|
||||
@@ -592,7 +603,7 @@ func (a API) SetChatTitle(chatID int64, title string) (res APIResponseBool, err
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("title", title)
|
||||
return get[APIResponseBool](a.base, "setChatTitle", vals)
|
||||
return res, a.client.get(a.base, "setChatTitle", vals, &res)
|
||||
}
|
||||
|
||||
// SetChatDescription is used to change the description of a group, a supergroup or a channel.
|
||||
@@ -602,7 +613,7 @@ func (a API) SetChatDescription(chatID int64, description string) (res APIRespon
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("description", description)
|
||||
return get[APIResponseBool](a.base, "setChatDescription", vals)
|
||||
return res, a.client.get(a.base, "setChatDescription", vals, &res)
|
||||
}
|
||||
|
||||
// PinChatMessage is used to add a message to the list of pinned messages in the chat.
|
||||
@@ -613,7 +624,7 @@ func (a API) PinChatMessage(chatID int64, messageID int, opts *PinMessageOptions
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseBool](a.base, "pinChatMessage", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "pinChatMessage", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// UnpinChatMessage is used to remove a message from the list of pinned messages in the chat.
|
||||
@@ -624,7 +635,7 @@ func (a API) UnpinChatMessage(chatID int64, messageID int) (res APIResponseBool,
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseBool](a.base, "unpinChatMessage", vals)
|
||||
return res, a.client.get(a.base, "unpinChatMessage", vals, &res)
|
||||
}
|
||||
|
||||
// UnpinAllChatMessages is used to clear the list of pinned messages in a chat.
|
||||
@@ -634,7 +645,7 @@ func (a API) UnpinAllChatMessages(chatID int64) (res APIResponseBool, err error)
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "unpinAllChatMessages", vals)
|
||||
return res, a.client.get(a.base, "unpinAllChatMessages", vals, &res)
|
||||
}
|
||||
|
||||
// LeaveChat is used to make the bot leave a group, supergroup or channel.
|
||||
@@ -642,7 +653,7 @@ func (a API) LeaveChat(chatID int64) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "leaveChat", vals)
|
||||
return res, a.client.get(a.base, "leaveChat", vals, &res)
|
||||
}
|
||||
|
||||
// GetChat is used to get up to date information about the chat.
|
||||
@@ -651,7 +662,7 @@ func (a API) GetChat(chatID int64) (res APIResponseChat, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseChat](a.base, "getChat", vals)
|
||||
return res, a.client.get(a.base, "getChat", vals, &res)
|
||||
}
|
||||
|
||||
// GetChatAdministrators is used to get a list of administrators in a chat.
|
||||
@@ -659,7 +670,7 @@ func (a API) GetChatAdministrators(chatID int64) (res APIResponseAdministrators,
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseAdministrators](a.base, "getChatAdministrators", vals)
|
||||
return res, a.client.get(a.base, "getChatAdministrators", vals, &res)
|
||||
}
|
||||
|
||||
// GetChatMemberCount is used to get the number of members in a chat.
|
||||
@@ -667,7 +678,7 @@ func (a API) GetChatMemberCount(chatID int64) (res APIResponseInteger, err error
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseInteger](a.base, "getChatMemberCount", vals)
|
||||
return res, a.client.get(a.base, "getChatMemberCount", vals, &res)
|
||||
}
|
||||
|
||||
// GetChatMember is used to get information about a member of a chat.
|
||||
@@ -676,7 +687,7 @@ func (a API) GetChatMember(chatID, userID int64) (res APIResponseChatMember, err
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseChatMember](a.base, "getChatMember", vals)
|
||||
return res, a.client.get(a.base, "getChatMember", vals, &res)
|
||||
}
|
||||
|
||||
// SetChatStickerSet is used to set a new group sticker set for a supergroup.
|
||||
@@ -687,7 +698,7 @@ func (a API) SetChatStickerSet(chatID int64, stickerSetName string) (res APIResp
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("sticker_set_name", stickerSetName)
|
||||
return get[APIResponseBool](a.base, "setChatStickerSet", vals)
|
||||
return res, a.client.get(a.base, "setChatStickerSet", vals, &res)
|
||||
}
|
||||
|
||||
// DeleteChatStickerSet is used to delete a group sticker set for a supergroup.
|
||||
@@ -697,7 +708,7 @@ func (a API) DeleteChatStickerSet(chatID int64) (res APIResponseBool, err error)
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "deleteChatStickerSet", vals)
|
||||
return res, a.client.get(a.base, "deleteChatStickerSet", vals, &res)
|
||||
}
|
||||
|
||||
// CreateForumTopic is used to create a topic in a forum supergroup chat.
|
||||
@@ -707,7 +718,7 @@ func (a API) CreateForumTopic(chatID int64, name string, opts *CreateTopicOption
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("name", name)
|
||||
return get[APIResponseForumTopic](a.base, "createForumTopic", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "createForumTopic", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// EditForumTopic is used to edit name and icon of a topic in a forum supergroup chat.
|
||||
@@ -717,7 +728,7 @@ func (a API) EditForumTopic(chatID, messageThreadID int64, opts *EditTopicOption
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_thread_id", itoa(messageThreadID))
|
||||
return get[APIResponseBool](a.base, "editForumTopic", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "editForumTopic", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// CloseForumTopic is used to close an open topic in a forum supergroup chat.
|
||||
@@ -727,7 +738,7 @@ func (a API) CloseForumTopic(chatID, messageThreadID int64) (res APIResponseBool
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_thread_id", itoa(messageThreadID))
|
||||
return get[APIResponseBool](a.base, "closeForumTopic", vals)
|
||||
return res, a.client.get(a.base, "closeForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// ReopenForumTopic is used to reopen a closed topic in a forum supergroup chat.
|
||||
@@ -737,7 +748,7 @@ func (a API) ReopenForumTopic(chatID, messageThreadID int64) (res APIResponseBoo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_thread_id", itoa(messageThreadID))
|
||||
return get[APIResponseBool](a.base, "reopenForumTopic", vals)
|
||||
return res, a.client.get(a.base, "reopenForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// DeleteForumTopic is used to delete a forum topic along with all its messages in a forum supergroup chat.
|
||||
@@ -747,7 +758,7 @@ func (a API) DeleteForumTopic(chatID, messageThreadID int64) (res APIResponseBoo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_thread_id", itoa(messageThreadID))
|
||||
return get[APIResponseBool](a.base, "deleteForumTopic", vals)
|
||||
return res, a.client.get(a.base, "deleteForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// UnpinAllForumTopicMessages is used to clear the list of pinned messages in a forum topic.
|
||||
@@ -757,7 +768,7 @@ func (a API) UnpinAllForumTopicMessages(chatID, messageThreadID int64) (res APIR
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_thread_id", itoa(messageThreadID))
|
||||
return get[APIResponseBool](a.base, "unpinAllForumTopicMessages", vals)
|
||||
return res, a.client.get(a.base, "unpinAllForumTopicMessages", vals, &res)
|
||||
}
|
||||
|
||||
// EditGeneralForumTopic is used to edit the name of the 'General' topic in a forum supergroup chat.
|
||||
@@ -767,7 +778,7 @@ func (a API) EditGeneralForumTopic(chatID int64, name string) (res APIResponseBo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("name", name)
|
||||
return get[APIResponseBool](a.base, "editGeneralForumTopic", vals)
|
||||
return res, a.client.get(a.base, "editGeneralForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// CloseGeneralForumTopic is used to close an open 'General' topic in a forum supergroup chat.
|
||||
@@ -776,7 +787,7 @@ func (a API) CloseGeneralForumTopic(chatID int64) (res APIResponseBool, err erro
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "closeGeneralForumTopic", vals)
|
||||
return res, a.client.get(a.base, "closeGeneralForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// ReopenGeneralForumTopic is used to reopen a closed 'General' topic in a forum supergroup chat.
|
||||
@@ -786,7 +797,7 @@ func (a API) ReopenGeneralForumTopic(chatID int64) (res APIResponseBool, err err
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "reopenGeneralForumTopic", vals)
|
||||
return res, a.client.get(a.base, "reopenGeneralForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// HideGeneralForumTopic is used to hide the 'General' topic in a forum supergroup chat.
|
||||
@@ -796,7 +807,7 @@ func (a API) HideGeneralForumTopic(chatID int64) (res APIResponseBool, err error
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "hideGeneralForumTopic", vals)
|
||||
return res, a.client.get(a.base, "hideGeneralForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// UnhideGeneralForumTopic is used to unhide the 'General' topic in a forum supergroup chat.
|
||||
@@ -805,7 +816,7 @@ func (a API) UnhideGeneralForumTopic(chatID int64) (res APIResponseBool, err err
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "unhideGeneralForumTopic", vals)
|
||||
return res, a.client.get(a.base, "unhideGeneralForumTopic", vals, &res)
|
||||
}
|
||||
|
||||
// UnpinAllGeneralForumTopicMessages is used to clear the list of pinned messages in a General forum topic.
|
||||
@@ -814,7 +825,7 @@ func (a API) UnpinAllGeneralForumTopicMessages(chatID int64) (res APIResponseBoo
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseBool](a.base, "unpinAllGeneralForumTopicMessages", vals)
|
||||
return res, a.client.get(a.base, "unpinAllGeneralForumTopicMessages", vals, &res)
|
||||
}
|
||||
|
||||
// AnswerCallbackQuery is used to send answers to callback queries sent from inline keyboards.
|
||||
@@ -823,7 +834,7 @@ func (a API) AnswerCallbackQuery(callbackID string, opts *CallbackQueryOptions)
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("callback_query_id", callbackID)
|
||||
return get[APIResponseBool](a.base, "answerCallbackQuery", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "answerCallbackQuery", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// GetUserChatBoosts is used to get the list of boosts added to a chat by a user.
|
||||
@@ -833,7 +844,15 @@ func (a API) GetUserChatBoosts(chatID, userID int64) (res APIResponseUserChatBoo
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseUserChatBoosts](a.base, "getUserChatBoosts", vals)
|
||||
return res, a.client.get(a.base, "getUserChatBoosts", vals, &res)
|
||||
}
|
||||
|
||||
// GetBusinessConnection is used to get information about the connection of the bot with a business account.
|
||||
func (a API) GetBusinessConnection(business_connection_id string) (res APIResponseBusinessConnection, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("business_connection_id", business_connection_id)
|
||||
return res, a.client.get(a.base, "getBusinessConnection", vals, &res)
|
||||
}
|
||||
|
||||
// SetMyCommands is used to change the list of the bot's commands for the given scope and user language.
|
||||
@@ -842,17 +861,17 @@ func (a API) SetMyCommands(opts *CommandOptions, commands ...BotCommand) (res AP
|
||||
|
||||
jsn, _ := json.Marshal(commands)
|
||||
vals.Set("commands", string(jsn))
|
||||
return get[APIResponseBool](a.base, "setMyCommands", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "setMyCommands", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// DeleteMyCommands is used to delete the list of the bot's commands for the given scope and user language.
|
||||
func (a API) DeleteMyCommands(opts *CommandOptions) (res APIResponseBool, err error) {
|
||||
return get[APIResponseBool](a.base, "deleteMyCommands", urlValues(opts))
|
||||
return res, a.client.get(a.base, "deleteMyCommands", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// GetMyCommands is used to get the current list of the bot's commands for the given scope and user language.
|
||||
func (a API) GetMyCommands(opts *CommandOptions) (res APIResponseCommands, err error) {
|
||||
return get[APIResponseCommands](a.base, "getMyCommands", urlValues(opts))
|
||||
return res, a.client.get(a.base, "getMyCommands", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// SetMyName is used to change the bot's name.
|
||||
@@ -861,7 +880,7 @@ func (a API) SetMyName(name, languageCode string) (res APIResponseBool, err erro
|
||||
|
||||
vals.Set("name", name)
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBool](a.base, "setMyName", vals)
|
||||
return res, a.client.get(a.base, "setMyName", vals, &res)
|
||||
}
|
||||
|
||||
// GetMyName is used to get the current bot name for the given user language.
|
||||
@@ -869,7 +888,7 @@ func (a API) GetMyName(languageCode string) (res APIResponseBotName, err error)
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBotName](a.base, "getMyName", vals)
|
||||
return res, a.client.get(a.base, "getMyName", vals, &res)
|
||||
}
|
||||
|
||||
// SetMyDescription is used to to change the bot's description, which is shown in the chat with the bot if the chat is empty.
|
||||
@@ -878,7 +897,7 @@ func (a API) SetMyDescription(description, languageCode string) (res APIResponse
|
||||
|
||||
vals.Set("description", description)
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBool](a.base, "setMyDescription", vals)
|
||||
return res, a.client.get(a.base, "setMyDescription", vals, &res)
|
||||
}
|
||||
|
||||
// GetMyDescription is used to get the current bot description for the given user language.
|
||||
@@ -886,7 +905,7 @@ func (a API) GetMyDescription(languageCode string) (res APIResponseBotDescriptio
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBotDescription](a.base, "getMyDescription", vals)
|
||||
return res, a.client.get(a.base, "getMyDescription", vals, &res)
|
||||
}
|
||||
|
||||
// SetMyShortDescription is used to to change the bot's short description,
|
||||
@@ -896,7 +915,7 @@ func (a API) SetMyShortDescription(shortDescription, languageCode string) (res A
|
||||
|
||||
vals.Set("short_description", shortDescription)
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBool](a.base, "setMyShortDescription", vals)
|
||||
return res, a.client.get(a.base, "setMyShortDescription", vals, &res)
|
||||
}
|
||||
|
||||
// GetMyShortDescription is used to get the current bot short description for the given user language.
|
||||
@@ -904,7 +923,7 @@ func (a API) GetMyShortDescription(languageCode string) (res APIResponseBotShort
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("language_code", languageCode)
|
||||
return get[APIResponseBotShortDescription](a.base, "getMyDescription", vals)
|
||||
return res, a.client.get(a.base, "getMyDescription", vals, &res)
|
||||
}
|
||||
|
||||
// EditMessageText is used to edit text and game messages.
|
||||
@@ -912,12 +931,12 @@ func (a API) EditMessageText(text string, msg MessageIDOptions, opts *MessageTex
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("text", text)
|
||||
return get[APIResponseMessage](a.base, "editMessageText", addValues(addValues(vals, msg), opts))
|
||||
return res, a.client.get(a.base, "editMessageText", addValues(addValues(vals, msg), opts), &res)
|
||||
}
|
||||
|
||||
// EditMessageCaption is used to edit captions of messages.
|
||||
func (a API) EditMessageCaption(msg MessageIDOptions, opts *MessageCaptionOptions) (res APIResponseMessage, err error) {
|
||||
return get[APIResponseMessage](a.base, "editMessageCaption", addValues(urlValues(msg), opts))
|
||||
return res, a.client.get(a.base, "editMessageCaption", addValues(urlValues(msg), opts), &res)
|
||||
}
|
||||
|
||||
// EditMessageMedia is used to edit animation, audio, document, photo or video messages.
|
||||
@@ -925,22 +944,22 @@ func (a API) EditMessageCaption(msg MessageIDOptions, opts *MessageCaptionOption
|
||||
// only to a document for document albums and to a photo or a video otherwise.
|
||||
// When an inline message is edited, a new file can't be uploaded.
|
||||
// Use a previously uploaded file via its file_id or specify a URL.
|
||||
func (a API) EditMessageMedia(msg MessageIDOptions, media InputMedia, opts *MessageReplyMarkup) (res APIResponseMessage, err error) {
|
||||
return postMedia[APIResponseMessage](a.base, "editMessageMedia", true, addValues(urlValues(msg), opts), media)
|
||||
func (a API) EditMessageMedia(msg MessageIDOptions, media InputMedia, opts *MessageMediaOptions) (res APIResponseMessage, err error) {
|
||||
return res, a.client.postMedia(a.base, "editMessageMedia", true, addValues(urlValues(msg), opts), &res, media)
|
||||
}
|
||||
|
||||
// EditMessageReplyMarkup is used to edit only the reply markup of messages.
|
||||
func (a API) EditMessageReplyMarkup(msg MessageIDOptions, opts *MessageReplyMarkup) (res APIResponseMessage, err error) {
|
||||
return get[APIResponseMessage](a.base, "editMessageReplyMarkup", addValues(urlValues(msg), opts))
|
||||
func (a API) EditMessageReplyMarkup(msg MessageIDOptions, opts *MessageReplyMarkupOptions) (res APIResponseMessage, err error) {
|
||||
return res, a.client.get(a.base, "editMessageReplyMarkup", addValues(urlValues(msg), opts), &res)
|
||||
}
|
||||
|
||||
// StopPoll is used to stop a poll which was sent by the bot.
|
||||
func (a API) StopPoll(chatID int64, messageID int, opts *MessageReplyMarkup) (res APIResponsePoll, err error) {
|
||||
func (a API) StopPoll(chatID int64, messageID int, opts *StopPollOptions) (res APIResponsePoll, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponsePoll](a.base, "stopPoll", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "stopPoll", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// DeleteMessage is used to delete a message, including service messages, with the following limitations:
|
||||
@@ -956,7 +975,7 @@ func (a API) DeleteMessage(chatID int64, messageID int) (res APIResponseBase, er
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_id", itoa(int64(messageID)))
|
||||
return get[APIResponseBase](a.base, "deleteMessage", vals)
|
||||
return res, a.client.get(a.base, "deleteMessage", vals, &res)
|
||||
}
|
||||
|
||||
// DeleteMessages is used to delete multiple messages simultaneously.
|
||||
@@ -971,5 +990,5 @@ func (a API) DeleteMessages(chatID int64, messageIDs []int) (res APIResponseBool
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("message_ids", string(msgIDs))
|
||||
return get[APIResponseBool](a.base, "deleteMessages", vals)
|
||||
return res, a.client.get(a.base, "deleteMessages", vals, &res)
|
||||
}
|
||||
|
||||
8
vendor/github.com/NicoNex/echotron/v3/chatadminrights.go
generated
vendored
8
vendor/github.com/NicoNex/echotron/v3/chatadminrights.go
generated
vendored
@@ -54,11 +54,11 @@ type GetMyDefaultAdministratorRightsOptions struct {
|
||||
// requested by the bot when it's added as an administrator to groups or channels.
|
||||
// These rights will be suggested to users, but they are are free to modify the list
|
||||
// before adding the bot.
|
||||
func (a API) SetMyDefaultAdministratorRights(opts SetMyDefaultAdministratorRightsOptions) (res APIResponseBool, err error) {
|
||||
return get[APIResponseBool](a.base, "setMyDefaultAdministratorRights", urlValues(opts))
|
||||
func (a API) SetMyDefaultAdministratorRights(opts *SetMyDefaultAdministratorRightsOptions) (res APIResponseBool, err error) {
|
||||
return res, a.client.get(a.base, "setMyDefaultAdministratorRights", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// GetMyDefaultAdministratorRights is used to get the current default administrator rights of the bot.
|
||||
func (a API) GetMyDefaultAdministratorRights(opts GetMyDefaultAdministratorRightsOptions) (res APIResponseChatAdministratorRights, err error) {
|
||||
return get[APIResponseChatAdministratorRights](a.base, "getMyDefaultAdministratorRights", urlValues(opts))
|
||||
func (a API) GetMyDefaultAdministratorRights(opts *GetMyDefaultAdministratorRightsOptions) (res APIResponseChatAdministratorRights, err error) {
|
||||
return res, a.client.get(a.base, "getMyDefaultAdministratorRights", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
6
vendor/github.com/NicoNex/echotron/v3/games.go
generated
vendored
6
vendor/github.com/NicoNex/echotron/v3/games.go
generated
vendored
@@ -52,7 +52,7 @@ func (a API) SendGame(gameShortName string, chatID int64, opts *BaseOptions) (re
|
||||
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
vals.Set("game_short_name", gameShortName)
|
||||
return get[APIResponseMessage](a.base, "sendGame", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendGame", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// SetGameScore is used to set the score of the specified user in a game.
|
||||
@@ -61,7 +61,7 @@ func (a API) SetGameScore(userID int64, score int, msgID MessageIDOptions, opts
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("score", itoa(int64(score)))
|
||||
return get[APIResponseMessage](a.base, "setGameScore", addValues(addValues(vals, msgID), opts))
|
||||
return res, a.client.get(a.base, "setGameScore", addValues(addValues(vals, msgID), opts), &res)
|
||||
}
|
||||
|
||||
// GetGameHighScores is used to get data for high score tables.
|
||||
@@ -69,5 +69,5 @@ func (a API) GetGameHighScores(userID int64, opts MessageIDOptions) (res APIResp
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return get[APIResponseGameHighScore](a.base, "getGameHighScores", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "getGameHighScores", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
206
vendor/github.com/NicoNex/echotron/v3/helpers.go
generated
vendored
206
vendor/github.com/NicoNex/echotron/v3/helpers.go
generated
vendored
@@ -19,7 +19,6 @@
|
||||
package echotron
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
@@ -27,6 +26,13 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// content contains a file's name, its type and its data.
|
||||
type content struct {
|
||||
fname string
|
||||
ftype string
|
||||
fdata []byte
|
||||
}
|
||||
|
||||
func check(r APIResponse) error {
|
||||
if b := r.Base(); !b.Ok {
|
||||
return &APIError{code: b.ErrorCode, desc: b.Description}
|
||||
@@ -109,123 +115,6 @@ func readFile(im InputFile) (content []byte, path string, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func sendFile(file, thumbnail InputFile, url, fileType string) (res []byte, err error) {
|
||||
var cnt []content
|
||||
|
||||
if file.id != "" {
|
||||
url = fmt.Sprintf("%s&%s=%s", url, fileType, file.id)
|
||||
} else if file.url != "" {
|
||||
url = fmt.Sprintf("%s&%s=%s", url, fileType, file.url)
|
||||
} else if c, e := toContent(fileType, file); e == nil {
|
||||
cnt = append(cnt, c)
|
||||
} else {
|
||||
err = e
|
||||
}
|
||||
|
||||
if c, e := toContent("thumbnail", thumbnail); e == nil {
|
||||
cnt = append(cnt, c)
|
||||
} else {
|
||||
err = e
|
||||
}
|
||||
|
||||
if len(cnt) > 0 {
|
||||
res, err = sendPostRequest(url, cnt...)
|
||||
} else {
|
||||
res, err = sendGetRequest(url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func sendMediaFiles(url string, editSingle bool, files ...InputMedia) (res []byte, err error) {
|
||||
var (
|
||||
med []mediaEnvelope
|
||||
cnt []content
|
||||
jsn []byte
|
||||
)
|
||||
|
||||
for _, file := range files {
|
||||
var im mediaEnvelope
|
||||
var cntArr []content
|
||||
|
||||
media := file.media()
|
||||
thumbnail := file.thumbnail()
|
||||
|
||||
im, cntArr, err = processMedia(media, thumbnail)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
im.InputMedia = file
|
||||
|
||||
med = append(med, im)
|
||||
cnt = append(cnt, cntArr...)
|
||||
}
|
||||
|
||||
if editSingle {
|
||||
jsn, err = json.Marshal(med[0])
|
||||
} else {
|
||||
jsn, err = json.Marshal(med)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
url = fmt.Sprintf("%s&media=%s", url, jsn)
|
||||
|
||||
if len(cnt) > 0 {
|
||||
return sendPostRequest(url, cnt...)
|
||||
}
|
||||
|
||||
return sendGetRequest(url)
|
||||
}
|
||||
|
||||
func sendStickers(url string, stickers ...InputSticker) (res []byte, err error) {
|
||||
var (
|
||||
sti []stickerEnvelope
|
||||
cnt []content
|
||||
jsn []byte
|
||||
)
|
||||
|
||||
for _, s := range stickers {
|
||||
var se stickerEnvelope
|
||||
var cntArr []content
|
||||
|
||||
se, cntArr, err = processSticker(s.Sticker)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
se.InputSticker = s
|
||||
|
||||
sti = append(sti, se)
|
||||
cnt = append(cnt, cntArr...)
|
||||
}
|
||||
|
||||
if len(sti) == 1 {
|
||||
jsn, _ = json.Marshal(sti[0])
|
||||
url = fmt.Sprintf("%s&sticker=%s", url, jsn)
|
||||
} else {
|
||||
jsn, _ = json.Marshal(sti)
|
||||
url = fmt.Sprintf("%s&stickers=%s", url, jsn)
|
||||
}
|
||||
|
||||
if len(cnt) > 0 {
|
||||
return sendPostRequest(url, cnt...)
|
||||
}
|
||||
|
||||
return sendGetRequest(url)
|
||||
}
|
||||
|
||||
func serializePerms(permissions ChatPermissions) (string, error) {
|
||||
perm, err := json.Marshal(permissions)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(perm), nil
|
||||
}
|
||||
|
||||
func toContent(ftype string, f InputFile) (content, error) {
|
||||
if f.path != "" && len(f.content) == 0 {
|
||||
var err error
|
||||
@@ -247,87 +136,6 @@ func toInputMedia(media []GroupableInputMedia) (ret []InputMedia) {
|
||||
return ret
|
||||
}
|
||||
|
||||
func get[T APIResponse](base, endpoint string, vals url.Values) (res T, err error) {
|
||||
url, err := url.JoinPath(base, endpoint)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if vals != nil {
|
||||
if queries := vals.Encode(); queries != "" {
|
||||
url = fmt.Sprintf("%s?%s", url, queries)
|
||||
}
|
||||
}
|
||||
|
||||
cnt, err := sendGetRequest(url)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(cnt, &res); err != nil {
|
||||
return
|
||||
}
|
||||
err = check(res)
|
||||
return
|
||||
}
|
||||
|
||||
func postFile[T APIResponse](base, endpoint, fileType string, file, thumbnail InputFile, vals url.Values) (res T, err error) {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
cnt, err := sendFile(file, thumbnail, url, fileType)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(cnt, &res); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = check(res)
|
||||
return
|
||||
}
|
||||
|
||||
func postMedia[T APIResponse](base, endpoint string, editSingle bool, vals url.Values, files ...InputMedia) (res T, err error) {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
cnt, err := sendMediaFiles(url, editSingle, files...)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(cnt, &res); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = check(res)
|
||||
return
|
||||
}
|
||||
|
||||
func postStickers[T APIResponse](base, endpoint string, vals url.Values, stickers ...InputSticker) (res T, err error) {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
cnt, err := sendStickers(url, stickers...)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(cnt, &res); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = check(res)
|
||||
return
|
||||
}
|
||||
|
||||
func joinURL(base, endpoint string, vals url.Values) (addr string, err error) {
|
||||
addr, err = url.JoinPath(base, endpoint)
|
||||
if err != nil {
|
||||
|
||||
227
vendor/github.com/NicoNex/echotron/v3/inline.go
generated
vendored
227
vendor/github.com/NicoNex/echotron/v3/inline.go
generated
vendored
@@ -90,19 +90,20 @@ func (i InlineQueryResultArticle) ImplementsInlineQueryResult() {}
|
||||
// By default, this photo will be sent by the user with optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the photo.
|
||||
type InlineQueryResultPhoto struct {
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
PhotoURL string `json:"photo_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
PhotoHeight int `json:"photo_height,omitempty"`
|
||||
PhotoWidth int `json:"photo_width,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
PhotoURL string `json:"photo_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
PhotoHeight int `json:"photo_height,omitempty"`
|
||||
PhotoWidth int `json:"photo_width,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -112,20 +113,21 @@ func (i InlineQueryResultPhoto) ImplementsInlineQueryResult() {}
|
||||
// By default, this animated GIF file will be sent by the user with optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the animation.
|
||||
type InlineQueryResultGif struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
GifURL string `json:"gif_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
ID string `json:"id"`
|
||||
ThumbnailMimeType string `json:"thumbnail_mime_type,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
GifDuration int `json:"gif_duration,omitempty"`
|
||||
GifHeight int `json:"gif_height,omitempty"`
|
||||
GifWidth int `json:"gif_width,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
GifURL string `json:"gif_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
ID string `json:"id"`
|
||||
ThumbnailMimeType string `json:"thumbnail_mime_type,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
GifDuration int `json:"gif_duration,omitempty"`
|
||||
GifHeight int `json:"gif_height,omitempty"`
|
||||
GifWidth int `json:"gif_width,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -135,20 +137,21 @@ func (i InlineQueryResultGif) ImplementsInlineQueryResult() {}
|
||||
// By default, this animated MPEG-4 file will be sent by the user with optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the animation.
|
||||
type InlineQueryResultMpeg4Gif struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Mpeg4URL string `json:"mpeg4_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
ID string `json:"id"`
|
||||
ThumbnailMimeType string `json:"thumbnail_mime_type,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Mpeg4Duration int `json:"mpeg4_duration,omitempty"`
|
||||
Mpeg4Height int `json:"mpeg4_height,omitempty"`
|
||||
Mpeg4Width int `json:"mpeg4_width,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Mpeg4URL string `json:"mpeg4_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
ID string `json:"id"`
|
||||
ThumbnailMimeType string `json:"thumbnail_mime_type,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Mpeg4Duration int `json:"mpeg4_duration,omitempty"`
|
||||
Mpeg4Height int `json:"mpeg4_height,omitempty"`
|
||||
Mpeg4Width int `json:"mpeg4_width,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -158,21 +161,22 @@ func (i InlineQueryResultMpeg4Gif) ImplementsInlineQueryResult() {}
|
||||
// By default, this video file will be sent by the user with an optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the video.
|
||||
type InlineQueryResultVideo struct {
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MimeType string `json:"mime_type"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ID string `json:"id"`
|
||||
VideoURL string `json:"video_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
VideoHeight int `json:"video_height,omitempty"`
|
||||
VideoDuration int `json:"video_duration,omitempty"`
|
||||
VideoWidth int `json:"video_width,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MimeType string `json:"mime_type"`
|
||||
ThumbnailURL string `json:"thumbnail_url"`
|
||||
Title string `json:"title"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ID string `json:"id"`
|
||||
VideoURL string `json:"video_url"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
VideoHeight int `json:"video_height,omitempty"`
|
||||
VideoDuration int `json:"video_duration,omitempty"`
|
||||
VideoWidth int `json:"video_width,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -323,16 +327,17 @@ func (i InlineQueryResultGame) ImplementsInlineQueryResult() {}
|
||||
// By default, this photo will be sent by the user with an optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the photo.
|
||||
type InlineQueryResultCachedPhoto struct {
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
PhotoFileID string `json:"photo_file_id"`
|
||||
Title string `json:"title,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
PhotoFileID string `json:"photo_file_id"`
|
||||
Title string `json:"title,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -342,15 +347,16 @@ func (i InlineQueryResultCachedPhoto) ImplementsInlineQueryResult() {}
|
||||
// By default, this animated GIF file will be sent by the user with an optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with specified content instead of the animation.
|
||||
type InlineQueryResultCachedGif struct {
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
GifFileID string `json:"gif_file_id"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
GifFileID string `json:"gif_file_id"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -360,15 +366,16 @@ func (i InlineQueryResultCachedGif) ImplementsInlineQueryResult() {}
|
||||
// By default, this animated MPEG-4 file will be sent by the user with an optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the animation.
|
||||
type InlineQueryResultCachedMpeg4Gif struct {
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Mpeg4FileID string `json:"mpeg4_file_id"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
ID string `json:"id"`
|
||||
Mpeg4FileID string `json:"mpeg4_file_id"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -411,16 +418,17 @@ func (i InlineQueryResultCachedDocument) ImplementsInlineQueryResult() {}
|
||||
// By default, this video file will be sent by the user with an optional caption.
|
||||
// Alternatively, you can use InputMessageContent to send a message with the specified content instead of the video.
|
||||
type InlineQueryResultCachedVideo struct {
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
VideoFileID string `json:"video_file_id"`
|
||||
Title string `json:"title"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ReplyMarkup ReplyMarkup `json:"reply_markup,omitempty"`
|
||||
InputMessageContent InputMessageContent `json:"input_message_content,omitempty"`
|
||||
Type InlineQueryType `json:"type"`
|
||||
ID string `json:"id"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
VideoFileID string `json:"video_file_id"`
|
||||
Title string `json:"title"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInlineQueryResult is used to implement the InlineQueryResult interface.
|
||||
@@ -468,10 +476,10 @@ type InputMessageContent interface {
|
||||
|
||||
// InputTextMessageContent represents the content of a text message to be sent as the result of an inline query.
|
||||
type InputTextMessageContent struct {
|
||||
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||
MessageText string `json:"message_text"`
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
Entities []*MessageEntity `json:"entities,omitempty"`
|
||||
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInputMessageContent is used to implement the InputMessageContent interface.
|
||||
@@ -516,6 +524,33 @@ type InputContactMessageContent struct {
|
||||
// ImplementsInputMessageContent is used to implement the InputMessageContent interface.
|
||||
func (i InputContactMessageContent) ImplementsInputMessageContent() {}
|
||||
|
||||
// InputInvoiceMessageContent represents the content of an invoice message to be sent as the result of an inline query.
|
||||
type InputInvoiceMessageContent struct {
|
||||
SuggestedTipAmounts *[]int `json:"suggested_tip_amounts,omitempty"`
|
||||
PhotoURL string `json:"photo_url,omitempty"`
|
||||
Description string `json:"description"`
|
||||
Payload string `json:"string"`
|
||||
ProviderToken string `json:"provider_token,omitempty"`
|
||||
Currency string `json:"currency"`
|
||||
Title string `json:"title"`
|
||||
ProviderData string `json:"provider_data,omitempty"`
|
||||
Prices []LabeledPrice `json:"prices"`
|
||||
PhotoSize int `json:"photo_size,omitempty"`
|
||||
MaxTipAmount int `json:"max_tip_amount,omitempty"`
|
||||
PhotoWidth int `json:"photo_width,omitempty"`
|
||||
PhotoHeight int `json:"photo_height,omitempty"`
|
||||
NeedName bool `json:"need_name,omitempty"`
|
||||
NeedPhoneNumber bool `json:"need_phone_number,omitempty"`
|
||||
NeedEmail bool `json:"need_email,omitempty"`
|
||||
NeedShippingAddress bool `json:"need_shipping_address,omitempty"`
|
||||
SendPhoneNumberToProvider bool `json:"send_phone_number_to_provider,omitempty"`
|
||||
SendEmailToProvider bool `json:"send_email_to_provider,omitempty"`
|
||||
IsFlexible bool `json:"is_flexible,omitempty"`
|
||||
}
|
||||
|
||||
// ImplementsInputMessageContent is used to implement the InputMessageContent interface.
|
||||
func (i InputInvoiceMessageContent) ImplementsInputMessageContent() {}
|
||||
|
||||
// InlineQueryResultsButton represents a button to be shown above inline query results.
|
||||
// You MUST use exactly one of the fields.
|
||||
type InlineQueryResultsButton struct {
|
||||
@@ -539,5 +574,5 @@ func (a API) AnswerInlineQuery(inlineQueryID string, results []InlineQueryResult
|
||||
jsn, _ := json.Marshal(results)
|
||||
vals.Set("inline_query_id", inlineQueryID)
|
||||
vals.Set("results", string(jsn))
|
||||
return get[APIResponseBase](a.base, "answerInlineQuery", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "answerInlineQuery", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
8
vendor/github.com/NicoNex/echotron/v3/menubutton.go
generated
vendored
8
vendor/github.com/NicoNex/echotron/v3/menubutton.go
generated
vendored
@@ -47,11 +47,11 @@ type GetChatMenuButtonOptions struct {
|
||||
}
|
||||
|
||||
// SetChatMenuButton is used to change the bot's menu button in a private chat, or the default menu button.
|
||||
func (a API) SetChatMenuButton(opts SetChatMenuButtonOptions) (res APIResponseBool, err error) {
|
||||
return get[APIResponseBool](a.base, "setChatMenuButton", urlValues(opts))
|
||||
func (a API) SetChatMenuButton(opts *SetChatMenuButtonOptions) (res APIResponseBool, err error) {
|
||||
return res, a.client.get(a.base, "setChatMenuButton", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// GetChatMenuButton is used to get the current value of the bot's menu button in a private chat, or the default menu button.
|
||||
func (a API) GetChatMenuButton(opts GetChatMenuButtonOptions) (res APIResponseMenuButton, err error) {
|
||||
return get[APIResponseMenuButton](a.base, "getChatMenuButton", urlValues(opts))
|
||||
func (a API) GetChatMenuButton(opts *GetChatMenuButtonOptions) (res APIResponseMenuButton, err error) {
|
||||
return res, a.client.get(a.base, "getChatMenuButton", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
338
vendor/github.com/NicoNex/echotron/v3/network.go
generated
vendored
338
vendor/github.com/NicoNex/echotron/v3/network.go
generated
vendored
@@ -20,99 +20,345 @@ package echotron
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"golang.org/x/time/rate"
|
||||
)
|
||||
|
||||
// content is a struct which contains a file's name, its type and its data.
|
||||
type content struct {
|
||||
fname string
|
||||
ftype string
|
||||
fdata []byte
|
||||
type client struct {
|
||||
*http.Client
|
||||
*sync.RWMutex
|
||||
cl map[string]*rate.Limiter // chat based limiter
|
||||
gl *rate.Limiter // global limiter
|
||||
climiter func() *rate.Limiter
|
||||
}
|
||||
|
||||
// sendGetRequest is used to send an HTTP GET request.
|
||||
func sendGetRequest(url string) ([]byte, error) {
|
||||
resp, err := http.Get(url)
|
||||
var lclient = newClient()
|
||||
|
||||
// SetGlobalRequestLimit sets the global rate limit for requests to the Telegram API.
|
||||
// A duration of 0 disables the rate limiter, allowing unlimited requests.
|
||||
// By default the duration of this limiter is set to time.Second/30.
|
||||
func SetGlobalRequestLimit(d time.Duration) {
|
||||
lclient.Lock()
|
||||
lclient.gl = rate.NewLimiter(rate.Every(d), 10)
|
||||
lclient.Unlock()
|
||||
}
|
||||
|
||||
// SetChatRequestLimit sets the per-chat rate limit for requests to the Telegram API.
|
||||
// A duration of 0 disables the rate limiter, allowing unlimited requests.
|
||||
// By default the duration of this limiter is set to time.Minute/20.
|
||||
func SetChatRequestLimit(d time.Duration) {
|
||||
lclient.Lock()
|
||||
lclient.cl = make(map[string]*rate.Limiter)
|
||||
lclient.climiter = func() *rate.Limiter {
|
||||
return rate.NewLimiter(rate.Every(d), 1)
|
||||
}
|
||||
lclient.Unlock()
|
||||
}
|
||||
|
||||
func newClient() *client {
|
||||
return &client{
|
||||
Client: new(http.Client),
|
||||
RWMutex: new(sync.RWMutex),
|
||||
cl: make(map[string]*rate.Limiter),
|
||||
gl: rate.NewLimiter(rate.Every(time.Second/30), 10),
|
||||
climiter: func() *rate.Limiter {
|
||||
return rate.NewLimiter(rate.Every(time.Minute/20), 1)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c client) wait(chatID string) error {
|
||||
c.RLock()
|
||||
defer c.RUnlock()
|
||||
|
||||
ctx := context.Background()
|
||||
// If the chatID is empty, it's a general API call like GetUpdates, GetMe
|
||||
// and similar, so skip the per-chat request limit wait.
|
||||
if chatID != "" {
|
||||
// If no limiter exists for a chat, create one.
|
||||
l, ok := c.cl[chatID]
|
||||
if !ok {
|
||||
l = c.climiter()
|
||||
c.cl[chatID] = l
|
||||
}
|
||||
|
||||
// Make sure to respect the single chat limit of requests.
|
||||
if err := l.Wait(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure to respect the global limit of requests.
|
||||
return c.gl.Wait(ctx)
|
||||
}
|
||||
|
||||
func (c client) doGet(reqURL string) ([]byte, error) {
|
||||
resp, err := c.Get(reqURL)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
// sendPostRequest is used to send an HTTP POST request.
|
||||
func sendPostRequest(url string, files ...content) ([]byte, error) {
|
||||
var buf = new(bytes.Buffer)
|
||||
var w = multipart.NewWriter(buf)
|
||||
func (c client) doPost(reqURL string, files ...content) ([]byte, error) {
|
||||
var (
|
||||
buf = new(bytes.Buffer)
|
||||
w = multipart.NewWriter(buf)
|
||||
)
|
||||
|
||||
for _, f := range files {
|
||||
part, err := w.CreateFormFile(f.ftype, filepath.Base(f.fname))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
part.Write(f.fdata)
|
||||
}
|
||||
|
||||
w.Close()
|
||||
|
||||
req, err := http.NewRequest("POST", url, buf)
|
||||
req, err := http.NewRequest(http.MethodPost, reqURL, buf)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
req.Header.Add("Content-Type", w.FormDataContentType())
|
||||
|
||||
var client = new(http.Client)
|
||||
res, err := client.Do(req)
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
|
||||
cnt, err := io.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
return cnt, nil
|
||||
return io.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
// sendPostForm is used to send an "application/x-www-form-urlencoded" through an HTTP POST request.
|
||||
func sendPostForm(reqURL string, keyVals map[string]string) ([]byte, error) {
|
||||
func (c client) doPostForm(reqURL string, keyVals map[string]string) ([]byte, error) {
|
||||
var form = make(url.Values)
|
||||
|
||||
for k, v := range keyVals {
|
||||
form.Add(k, v)
|
||||
}
|
||||
|
||||
request, err := http.NewRequest("POST", reqURL, strings.NewReader(form.Encode()))
|
||||
req, err := http.NewRequest(http.MethodPost, reqURL, strings.NewReader(form.Encode()))
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
request.PostForm = form
|
||||
request.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
req.PostForm = form
|
||||
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
|
||||
|
||||
var client http.Client
|
||||
|
||||
response, err := client.Do(request)
|
||||
res, err := c.Do(req)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer response.Body.Close()
|
||||
|
||||
content, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
return []byte{}, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
defer res.Body.Close()
|
||||
return io.ReadAll(res.Body)
|
||||
}
|
||||
|
||||
func (c client) sendFile(file, thumbnail InputFile, url, fileType string) (res []byte, err error) {
|
||||
var cnt []content
|
||||
|
||||
if file.id != "" {
|
||||
url = fmt.Sprintf("%s&%s=%s", url, fileType, file.id)
|
||||
} else if file.url != "" {
|
||||
url = fmt.Sprintf("%s&%s=%s", url, fileType, file.url)
|
||||
} else if c, e := toContent(fileType, file); e == nil {
|
||||
cnt = append(cnt, c)
|
||||
} else {
|
||||
err = e
|
||||
}
|
||||
|
||||
if c, e := toContent("thumbnail", thumbnail); e == nil {
|
||||
cnt = append(cnt, c)
|
||||
} else {
|
||||
err = e
|
||||
}
|
||||
|
||||
if len(cnt) > 0 {
|
||||
res, err = c.doPost(url, cnt...)
|
||||
} else {
|
||||
res, err = c.doGet(url)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (c client) get(base, endpoint string, vals url.Values, v APIResponse) error {
|
||||
url, err := url.JoinPath(base, endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if vals != nil {
|
||||
if queries := vals.Encode(); queries != "" {
|
||||
url = fmt.Sprintf("%s?%s", url, queries)
|
||||
}
|
||||
}
|
||||
|
||||
if err := c.wait(vals.Get("chat_id")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt, err := c.doGet(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(cnt, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return check(v)
|
||||
}
|
||||
|
||||
func (c client) postFile(base, endpoint, fileType string, file, thumbnail InputFile, vals url.Values, v APIResponse) error {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.wait(vals.Get("chat_id")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt, err := c.sendFile(file, thumbnail, url, fileType)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(cnt, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return check(v)
|
||||
}
|
||||
|
||||
func (c client) postMedia(base, endpoint string, editSingle bool, vals url.Values, v APIResponse, files ...InputMedia) error {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.wait(vals.Get("chat_id")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt, err := c.sendMediaFiles(url, editSingle, files...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(cnt, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return check(v)
|
||||
}
|
||||
|
||||
func (c client) postStickers(base, endpoint string, vals url.Values, v APIResponse, stickers ...InputSticker) error {
|
||||
url, err := joinURL(base, endpoint, vals)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := c.wait(vals.Get("chat_id")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cnt, err := c.sendStickers(url, stickers...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := json.Unmarshal(cnt, v); err != nil {
|
||||
return err
|
||||
}
|
||||
return check(v)
|
||||
}
|
||||
|
||||
func (c client) sendMediaFiles(url string, editSingle bool, files ...InputMedia) (res []byte, err error) {
|
||||
var (
|
||||
med []mediaEnvelope
|
||||
cnt []content
|
||||
jsn []byte
|
||||
)
|
||||
|
||||
for _, file := range files {
|
||||
var im mediaEnvelope
|
||||
var cntArr []content
|
||||
|
||||
media := file.media()
|
||||
thumbnail := file.thumbnail()
|
||||
|
||||
im, cntArr, err = processMedia(media, thumbnail)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
im.InputMedia = file
|
||||
|
||||
med = append(med, im)
|
||||
cnt = append(cnt, cntArr...)
|
||||
}
|
||||
|
||||
if editSingle {
|
||||
jsn, err = json.Marshal(med[0])
|
||||
} else {
|
||||
jsn, err = json.Marshal(med)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
url = fmt.Sprintf("%s&media=%s", url, jsn)
|
||||
|
||||
if len(cnt) > 0 {
|
||||
return c.doPost(url, cnt...)
|
||||
}
|
||||
return c.doGet(url)
|
||||
}
|
||||
|
||||
func (c client) sendStickers(url string, stickers ...InputSticker) (res []byte, err error) {
|
||||
var (
|
||||
sti []stickerEnvelope
|
||||
cnt []content
|
||||
jsn []byte
|
||||
)
|
||||
|
||||
for _, s := range stickers {
|
||||
var se stickerEnvelope
|
||||
var cntArr []content
|
||||
|
||||
se, cntArr, err = processSticker(s.Sticker)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
se.InputSticker = s
|
||||
|
||||
sti = append(sti, se)
|
||||
cnt = append(cnt, cntArr...)
|
||||
}
|
||||
|
||||
if len(sti) == 1 {
|
||||
jsn, _ = json.Marshal(sti[0])
|
||||
url = fmt.Sprintf("%s&sticker=%s", url, jsn)
|
||||
} else {
|
||||
jsn, _ = json.Marshal(sti)
|
||||
url = fmt.Sprintf("%s&stickers=%s", url, jsn)
|
||||
}
|
||||
|
||||
if len(cnt) > 0 {
|
||||
return c.doPost(url, cnt...)
|
||||
}
|
||||
return c.doGet(url)
|
||||
}
|
||||
|
||||
388
vendor/github.com/NicoNex/echotron/v3/options.go
generated
vendored
388
vendor/github.com/NicoNex/echotron/v3/options.go
generated
vendored
@@ -74,23 +74,25 @@ type MessageEntityType string
|
||||
|
||||
// These are all the possible types for MessageEntityType.
|
||||
const (
|
||||
MentionEntity MessageEntityType = "mention"
|
||||
HashtagEntity = "hashtag"
|
||||
CashtagEntity = "cashtag"
|
||||
BotCommandEntity = "bot_command"
|
||||
UrlEntity = "url"
|
||||
EmailEntity = "email"
|
||||
PhoneNumberEntity = "phone_number"
|
||||
BoldEntity = "bold"
|
||||
ItalicEntity = "italic"
|
||||
UnderlineEntity = "underline"
|
||||
StrikethroughEntity = "strikethrough"
|
||||
SpoilerEntity = "spoiler"
|
||||
CodeEntity = "code"
|
||||
PreEntity = "pre"
|
||||
TextLinkEntity = "text_link"
|
||||
TextMentionEntity = "text_mention"
|
||||
CustomEmojiEntity = "custom_emoji"
|
||||
MentionEntity MessageEntityType = "mention"
|
||||
HashtagEntity = "hashtag"
|
||||
CashtagEntity = "cashtag"
|
||||
BotCommandEntity = "bot_command"
|
||||
UrlEntity = "url"
|
||||
EmailEntity = "email"
|
||||
PhoneNumberEntity = "phone_number"
|
||||
BoldEntity = "bold"
|
||||
ItalicEntity = "italic"
|
||||
UnderlineEntity = "underline"
|
||||
StrikethroughEntity = "strikethrough"
|
||||
SpoilerEntity = "spoiler"
|
||||
BlockQuoteEntity = "blockquote"
|
||||
ExpandableBlockQuoteEntity = "expandable_blockquote"
|
||||
CodeEntity = "code"
|
||||
PreEntity = "pre"
|
||||
TextLinkEntity = "text_link"
|
||||
TextMentionEntity = "text_mention"
|
||||
CustomEmojiEntity = "custom_emoji"
|
||||
)
|
||||
|
||||
// UpdateType is a custom type for the various update types that a bot can be subscribed to.
|
||||
@@ -137,10 +139,13 @@ type KeyboardButtonPollType struct {
|
||||
// KeyboardButtonRequestUsers defines the criteria used to request suitable users.
|
||||
// The identifiers of the selected users will be shared with the bot when the corresponding button is pressed.
|
||||
type KeyboardButtonRequestUsers struct {
|
||||
RequestID int `json:"request_id"`
|
||||
MaxQuantity int `json:"max_quantity,omitempty"`
|
||||
UserIsBot bool `json:"user_is_bot,omitempty"`
|
||||
UserIsPremium bool `json:"user_is_premium,omitempty"`
|
||||
RequestID int `json:"request_id"`
|
||||
MaxQuantity int `json:"max_quantity,omitempty"`
|
||||
UserIsBot bool `json:"user_is_bot,omitempty"`
|
||||
UserIsPremium bool `json:"user_is_premium,omitempty"`
|
||||
RequestName bool `json:"request_name,omitempty"`
|
||||
RequestUsername bool `json:"request_username,omitempty"`
|
||||
RequestPhoto bool `json:"request_photo,omitempty"`
|
||||
}
|
||||
|
||||
// KeyboardButtonRequestChat defines the criteria used to request a suitable chat.
|
||||
@@ -154,6 +159,9 @@ type KeyboardButtonRequestChat struct {
|
||||
ChatHasUsername bool `json:"chat_has_username,omitempty"`
|
||||
ChatIsCreated bool `json:"chat_is_created,omitempty"`
|
||||
BotIsMember bool `json:"bot_is_member,omitempty"`
|
||||
RequestName bool `json:"request_name,omitempty"`
|
||||
RequestUsername bool `json:"request_username,omitempty"`
|
||||
RequestPhoto bool `json:"request_photo,omitempty"`
|
||||
}
|
||||
|
||||
// ReplyKeyboardMarkup represents a custom keyboard with reply options.
|
||||
@@ -233,23 +241,27 @@ type WebhookOptions struct {
|
||||
|
||||
// BaseOptions contains the optional parameters used frequently in some Telegram API methods.
|
||||
type BaseOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// MessageOptions contains the optional parameters used by some Telegram API methods.
|
||||
type MessageOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
LinkPreviewOptions LinkPreviewOptions `query:"link_preview_options"`
|
||||
Entities []MessageEntity `query:"entities"`
|
||||
MessageThreadID int64 `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
LinkPreviewOptions LinkPreviewOptions `query:"link_preview_options"`
|
||||
Entities []MessageEntity `query:"entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int64 `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// PinMessageOptions contains the optional parameters used by the PinChatMember method.
|
||||
@@ -266,14 +278,15 @@ type ForwardOptions struct {
|
||||
|
||||
// CopyOptions contains the optional parameters used by the CopyMessage method.
|
||||
type CopyOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ShowCaptionAboveMedia bool `query:"show_caption_above_media"`
|
||||
}
|
||||
|
||||
// CopyMessagesOptions contains the optional parameters used by the CopyMessages methods.
|
||||
@@ -286,12 +299,14 @@ type CopyMessagesOptions struct {
|
||||
|
||||
// StickerOptions contains the optional parameters used by the SendSticker method.
|
||||
type StickerOptions struct {
|
||||
Emoji string `query:"emoji"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
Emoji string `query:"emoji"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// InputFile is a struct which contains data about a file to be sent.
|
||||
@@ -299,7 +314,6 @@ type InputFile struct {
|
||||
id string
|
||||
path string
|
||||
url string
|
||||
ftype string
|
||||
content []byte
|
||||
}
|
||||
|
||||
@@ -325,41 +339,48 @@ func NewInputFileBytes(fileName string, content []byte) InputFile {
|
||||
|
||||
// PhotoOptions contains the optional parameters used by the SendPhoto method.
|
||||
type PhotoOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ShowCaptionAboveMedia bool `query:"show_caption_above_media"`
|
||||
}
|
||||
|
||||
// AudioOptions contains the optional parameters used by the SendAudio method.
|
||||
type AudioOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
Performer string `query:"performer"`
|
||||
Title string `query:"title"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
Title string `query:"title"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
Performer string `query:"performer"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// DocumentOptions contains the optional parameters used by the SendDocument method.
|
||||
type DocumentOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
@@ -368,74 +389,91 @@ type DocumentOptions struct {
|
||||
|
||||
// VideoOptions contains the optional parameters used by the SendVideo method.
|
||||
type VideoOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
Caption string `query:"caption"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Width int `query:"width"`
|
||||
Height int `query:"height"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
SupportsStreaming bool `query:"supports_streaming"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
Caption string `query:"caption"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Width int `query:"width"`
|
||||
Height int `query:"height"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
SupportsStreaming bool `query:"supports_streaming"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ShowCaptionAboveMedia bool `query:"show_caption_above_media"`
|
||||
}
|
||||
|
||||
// AnimationOptions contains the optional parameters used by the SendAnimation method.
|
||||
type AnimationOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Width int `query:"width"`
|
||||
Height int `query:"height"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
Thumbnail InputFile
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Width int `query:"width"`
|
||||
Height int `query:"height"`
|
||||
HasSpoiler bool `query:"has_spoiler"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ShowCaptionAboveMedia bool `query:"show_caption_above_media"`
|
||||
}
|
||||
|
||||
// VoiceOptions contains the optional parameters used by the SendVoice method.
|
||||
type VoiceOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Caption string `query:"caption"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// VideoNoteOptions contains the optional parameters used by the SendVideoNote method.
|
||||
type VideoNoteOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
Thumbnail InputFile
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Length int `query:"length"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
Thumbnail InputFile
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
Duration int `query:"duration"`
|
||||
Length int `query:"length"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// MediaGroupOptions contains the optional parameters used by the SendMediaGroup method.
|
||||
type MediaGroupOptions struct {
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// This is a custom constant to set an infinite live period value in LocationOptions and EditLocationOptions.
|
||||
const InfiniteLivePeriod = 0x7FFFFFFF
|
||||
|
||||
// LocationOptions contains the optional parameters used by the SendLocation method.
|
||||
type LocationOptions struct {
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
HorizontalAccuracy float64 `query:"horizontal_accuracy"`
|
||||
@@ -449,46 +487,62 @@ type LocationOptions struct {
|
||||
|
||||
// EditLocationOptions contains the optional parameters used by the EditMessageLiveLocation method.
|
||||
type EditLocationOptions struct {
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
HorizontalAccuracy float64 `query:"horizontal_accuracy"`
|
||||
Heading int `query:"heading"`
|
||||
LivePeriod int `query:"live_period"`
|
||||
ProximityAlertRadius int `query:"proximity_alert_radius"`
|
||||
}
|
||||
|
||||
// StopLocationOptions contains the optional parameters used by the StopMessageLiveLocation method.
|
||||
type StopLocationOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
}
|
||||
|
||||
// VenueOptions contains the optional parameters used by the SendVenue method.
|
||||
type VenueOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
FoursquareID string `query:"foursquare_id"`
|
||||
FoursquareType string `query:"foursquare_type"`
|
||||
GooglePlaceType string `query:"google_place_type"`
|
||||
GooglePlaceID string `query:"google_place_id"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
FoursquareID string `query:"foursquare_id"`
|
||||
FoursquareType string `query:"foursquare_type"`
|
||||
GooglePlaceType string `query:"google_place_type"`
|
||||
GooglePlaceID string `query:"google_place_id"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// ContactOptions contains the optional parameters used by the SendContact method.
|
||||
type ContactOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
VCard string `query:"vcard"`
|
||||
LastName string `query:"last_name"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
VCard string `query:"vcard"`
|
||||
LastName string `query:"last_name"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
ProtectContent bool `query:"protect_content"`
|
||||
}
|
||||
|
||||
// PollOptions contains the optional parameters used by the SendPoll method.
|
||||
type PollOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
Explanation string `query:"explanation"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ExplanationParseMode ParseMode `query:"explanation_parse_mode"`
|
||||
QuestionParseMode ParseMode `query:"question_parse_mode"`
|
||||
Type PollType `query:"type"`
|
||||
ExplanationEntities []MessageEntity `query:"explanation_entities"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
QuestionEntities []MessageEntity `query:"question_entities"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
CorrectOptionID int `query:"correct_option_id"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
CloseDate int `query:"close_date"`
|
||||
OpenPeriod int `query:"open_period"`
|
||||
IsClosed bool `query:"is_closed"`
|
||||
@@ -498,6 +552,12 @@ type PollOptions struct {
|
||||
IsAnonymous bool `query:"is_anonymous"`
|
||||
}
|
||||
|
||||
// StopPollOptions contains the optional parameters used by the StopPoll method.
|
||||
type StopPollOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
}
|
||||
|
||||
// BanOptions contains the optional parameters used by the BanChatMember method.
|
||||
type BanOptions struct {
|
||||
UntilDate int `query:"until_date"`
|
||||
@@ -580,23 +640,33 @@ func NewInlineMessageID(ID string) MessageIDOptions {
|
||||
|
||||
// MessageTextOptions contains the optional parameters used by the EditMessageText method.
|
||||
type MessageTextOptions struct {
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
Entities []MessageEntity `query:"entities"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
LinkPreviewOptions LinkPreviewOptions `query:"link_preview_options"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
Entities []MessageEntity `query:"entities"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
LinkPreviewOptions LinkPreviewOptions `query:"link_preview_options"`
|
||||
}
|
||||
|
||||
// MessageCaptionOptions contains the optional parameters used by the EditMessageCaption method.
|
||||
type MessageCaptionOptions struct {
|
||||
Caption string `query:"caption"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
Caption string `query:"caption"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
ParseMode ParseMode `query:"parse_mode"`
|
||||
CaptionEntities []MessageEntity `query:"caption_entities"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
ShowCaptionAboveMedia bool `query:"show_caption_above_media"`
|
||||
}
|
||||
|
||||
// MessageReplyMarkup contains the optional parameters used by the method which only require reply_markup.
|
||||
type MessageReplyMarkup struct {
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
// MessageMediaOptions contains the optional parameters used by the EditMessageMedia method.
|
||||
type MessageMediaOptions struct {
|
||||
ReplyMarkup ReplyMarkup `query:"reply_markup"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
}
|
||||
|
||||
// MessageReplyMarkupOptions contains the optional parameters used by the EditMessageReplyMarkup method.
|
||||
type MessageReplyMarkupOptions struct {
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
}
|
||||
|
||||
// CommandOptions contains the optional parameters used by the SetMyCommands, DeleteMyCommands and GetMyCommands methods.
|
||||
@@ -610,17 +680,19 @@ type InvoiceOptions struct {
|
||||
StartParameter string `query:"start_parameter"`
|
||||
ProviderData string `query:"provider_data"`
|
||||
PhotoURL string `query:"photo_url"`
|
||||
ProviderToken string `query:"provider_token"`
|
||||
MessageEffectID string `query:"message_effect_id"`
|
||||
ReplyMarkup InlineKeyboardMarkup `query:"reply_markup"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
SuggestedTipAmount []int `query:"suggested_tip_amounts"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
ReplyParameters ReplyParameters `query:"reply_parameters"`
|
||||
MaxTipAmount int `query:"max_tip_amount"`
|
||||
PhotoSize int `query:"photo_size"`
|
||||
PhotoWidth int `query:"photo_width"`
|
||||
PhotoHeight int `query:"photo_height"`
|
||||
MaxTipAmount int `query:"max_tip_amount"`
|
||||
NeedPhoneNumber bool `query:"need_phone_number"`
|
||||
NeepShippingAddress bool `query:"need_shipping_address"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
SendPhoneNumberToProvider bool `query:"send_phone_number_to_provider"`
|
||||
NeepShippingAddress bool `query:"need_shipping_address"`
|
||||
NeedPhoneNumber bool `query:"need_phone_number"`
|
||||
SendEmailToProvider bool `query:"send_email_to_provider"`
|
||||
IsFlexible bool `query:"is_flexible"`
|
||||
DisableNotification bool `query:"disable_notification"`
|
||||
@@ -633,6 +705,7 @@ type InvoiceOptions struct {
|
||||
type CreateInvoiceLinkOptions struct {
|
||||
ProviderData string `query:"provider_data"`
|
||||
PhotoURL string `query:"photo_url"`
|
||||
ProviderToken string `query:"provider_token"`
|
||||
SuggestedTipAmounts []int `query:"suggested_tip_amounts"`
|
||||
PhotoSize int `query:"photo_size"`
|
||||
PhotoWidth int `query:"photo_width"`
|
||||
@@ -679,7 +752,8 @@ type EditTopicOptions struct {
|
||||
|
||||
// ChatActionOptions contains the optional parameters used by the SendChatAction API method.
|
||||
type ChatActionOptions struct {
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
BusinessConnectionID string `query:"business_connection_id"`
|
||||
MessageThreadID int `query:"message_thread_id"`
|
||||
}
|
||||
|
||||
// MessageReactionOptions contains the optional parameters used by the SetMessageReaction API method.
|
||||
|
||||
2
vendor/github.com/NicoNex/echotron/v3/passport.go
generated
vendored
2
vendor/github.com/NicoNex/echotron/v3/passport.go
generated
vendored
@@ -224,5 +224,5 @@ func (a API) SetPassportDataErrors(userID int64, errors []PassportElementError)
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("errors", string(errorsArr))
|
||||
return get[APIResponseBool](a.base, "setPassportDataErrors", vals)
|
||||
return res, a.client.get(a.base, "setPassportDataErrors", vals, &res)
|
||||
}
|
||||
|
||||
132
vendor/github.com/NicoNex/echotron/v3/payments.go
generated
vendored
132
vendor/github.com/NicoNex/echotron/v3/payments.go
generated
vendored
@@ -96,8 +96,90 @@ type PreCheckoutQuery struct {
|
||||
TotalAmount int `json:"total_amount"`
|
||||
}
|
||||
|
||||
// RevenueWithdrawalState describes the state of a revenue withdrawal operation.
|
||||
type RevenueWithdrawalState interface {
|
||||
ImplementsRevenueWithdrawalState()
|
||||
}
|
||||
|
||||
// RevenueWithdrawalStatePending describes the state of a withdrawal in progress.
|
||||
type RevenueWithdrawalStatePending struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// ImplementsRevenueWithdrawalState is used to implement the RevenueWithdrawalState interface.
|
||||
func (r RevenueWithdrawalStatePending) ImplementsRevenueWithdrawalState() {}
|
||||
|
||||
// RevenueWithdrawalStateSucceeded describes the state of a succeeded withdrawal.
|
||||
type RevenueWithdrawalStateSucceeded struct {
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
Date int `json:"date"`
|
||||
}
|
||||
|
||||
// ImplementsRevenueWithdrawalState is used to implement the RevenueWithdrawalState interface.
|
||||
func (r RevenueWithdrawalStateSucceeded) ImplementsRevenueWithdrawalState() {}
|
||||
|
||||
// RevenueWithdrawalStateFailed describes the state of a failed withdrawal, in which the transaction was refunded.
|
||||
type RevenueWithdrawalStateFailed struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// ImplementsRevenueWithdrawalState is used to implement the RevenueWithdrawalState interface.
|
||||
func (r RevenueWithdrawalStateFailed) ImplementsRevenueWithdrawalState() {}
|
||||
|
||||
// TransactionPartner describes the source of a transaction, or its recipient for outgoing transactions.
|
||||
type TransactionPartner interface {
|
||||
ImplementsTransactionPartner()
|
||||
}
|
||||
|
||||
// TransactionPartnerFragment describes a withdrawal transaction with Fragment.
|
||||
type TransactionPartnerFragment struct {
|
||||
WithdrawalState RevenueWithdrawalState `json:"withdrawal_state"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// ImplementsTransactionPartner is used to implement the TransactionPartner interface.
|
||||
func (t TransactionPartnerFragment) ImplementsTransactionPartner() {}
|
||||
|
||||
// TransactionPartnerUser describes a transaction with a user.
|
||||
type TransactionPartnerUser struct {
|
||||
Type string `json:"type"`
|
||||
User User `json:"user"`
|
||||
}
|
||||
|
||||
// ImplementsTransactionPartner is used to implement the TransactionPartner interface.
|
||||
func (t TransactionPartnerUser) ImplementsTransactionPartner() {}
|
||||
|
||||
// TransactionPartnerOther describes a transaction with an unknown source or recipient.
|
||||
type TransactionPartnerOther struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
// ImplementsTransactionPartner is used to implement the TransactionPartner interface.
|
||||
func (t TransactionPartnerOther) ImplementsTransactionPartner() {}
|
||||
|
||||
// StarTransaction describes a Telegram Star transaction.
|
||||
type StarTransaction struct {
|
||||
Source TransactionPartner `json:"source"`
|
||||
Receiver TransactionPartner `json:"receiver"`
|
||||
ID string `json:"id"`
|
||||
Amount int `json:"amount"`
|
||||
Date int `json:"date"`
|
||||
}
|
||||
|
||||
// StarTransactions contains a list of Telegram Star transactions.
|
||||
type StarTransactions struct {
|
||||
Transaction []StarTransaction `json:"transaction"`
|
||||
}
|
||||
|
||||
// StarTransactionsOptions contains the optional parameters used by the GetStarTransactions method.
|
||||
type StarTransactionsOptions struct {
|
||||
Offset int `query:"offset"`
|
||||
Limit int `query:"limit"`
|
||||
}
|
||||
|
||||
// SendInvoice is used to send invoices.
|
||||
func (a API) SendInvoice(chatID int64, title, description, payload, providerToken, currency string, prices []LabeledPrice, opts *InvoiceOptions) (res APIResponseMessage, err error) {
|
||||
func (a API) SendInvoice(chatID int64, title, description, payload, currency string, prices []LabeledPrice, opts *InvoiceOptions) (res APIResponseMessage, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
p, err := json.Marshal(prices)
|
||||
@@ -109,10 +191,26 @@ func (a API) SendInvoice(chatID int64, title, description, payload, providerToke
|
||||
vals.Set("title", title)
|
||||
vals.Set("description", description)
|
||||
vals.Set("payload", payload)
|
||||
vals.Set("provider_token", providerToken)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("prices", string(p))
|
||||
return get[APIResponseMessage](a.base, "sendInvoice", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendInvoice", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// CreateInvoiceLink creates a link for an invoice.
|
||||
func (a API) CreateInvoiceLink(title, description, payload, currency string, prices []LabeledPrice, opts *CreateInvoiceLinkOptions) (res APIResponseBase, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
p, err := json.Marshal(prices)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
vals.Set("title", title)
|
||||
vals.Set("description", description)
|
||||
vals.Set("payload", payload)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("prices", string(p))
|
||||
return res, a.client.get(a.base, "createInvoiceLink", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// AnswerShippingQuery is used to reply to shipping queries.
|
||||
@@ -123,7 +221,7 @@ func (a API) AnswerShippingQuery(shippingQueryID string, ok bool, opts *Shipping
|
||||
|
||||
vals.Set("shipping_query_id", shippingQueryID)
|
||||
vals.Set("ok", btoa(ok))
|
||||
return get[APIResponseBase](a.base, "answerShippingQuery", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "answerShippingQuery", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// AnswerPreCheckoutQuery is used to respond to such pre-checkout queries.
|
||||
@@ -135,23 +233,19 @@ func (a API) AnswerPreCheckoutQuery(preCheckoutQueryID string, ok bool, opts *Pr
|
||||
|
||||
vals.Set("pre_checkout_query_id", preCheckoutQueryID)
|
||||
vals.Set("ok", btoa(ok))
|
||||
return get[APIResponseBase](a.base, "answerPreCheckoutQuery", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "answerPreCheckoutQuery", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// CreateInvoiceLink creates a link for an invoice.
|
||||
func (a API) CreateInvoiceLink(title, description, payload, providerToken, currency string, prices []LabeledPrice, opts *CreateInvoiceLinkOptions) (res APIResponseBase, err error) {
|
||||
// GetStarTransactions returns the bot's Telegram Star transactions in chronological order.
|
||||
func (a API) GetStarTransactions(opts *StarTransactionsOptions) (res APIResponseStarTransactions, err error) {
|
||||
return res, a.client.get(a.base, "getStarTransactions", urlValues(opts), &res)
|
||||
}
|
||||
|
||||
// RefundStarPayment refunds a successful payment in Telegram Stars.
|
||||
func (a API) RefundStarPayment(userID int64, telegramPaymentChargeID string) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
p, err := json.Marshal(prices)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
vals.Set("title", title)
|
||||
vals.Set("description", description)
|
||||
vals.Set("payload", payload)
|
||||
vals.Set("provider_token", providerToken)
|
||||
vals.Set("currency", currency)
|
||||
vals.Set("prices", string(p))
|
||||
return get[APIResponseBase](a.base, "createInvoiceLink", addValues(vals, opts))
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("telegram_payment_charge_id", telegramPaymentChargeID)
|
||||
return res, a.client.get(a.base, "refundStarPayment", vals, &res)
|
||||
}
|
||||
|
||||
4
vendor/github.com/NicoNex/echotron/v3/querybuilder.go
generated
vendored
4
vendor/github.com/NicoNex/echotron/v3/querybuilder.go
generated
vendored
@@ -70,10 +70,6 @@ func scan(i any, v url.Values) url.Values {
|
||||
return v
|
||||
}
|
||||
|
||||
func querify(i any) string {
|
||||
return scan(i, url.Values{}).Encode()
|
||||
}
|
||||
|
||||
func urlValues(i any) url.Values {
|
||||
if i == nil {
|
||||
return nil
|
||||
|
||||
79
vendor/github.com/NicoNex/echotron/v3/stickers.go
generated
vendored
79
vendor/github.com/NicoNex/echotron/v3/stickers.go
generated
vendored
@@ -20,7 +20,6 @@ package echotron
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
@@ -50,8 +49,6 @@ type StickerSet struct {
|
||||
Name string `json:"name"`
|
||||
StickerType StickerSetType `json:"sticker_type"`
|
||||
Stickers []Sticker `json:"stickers"`
|
||||
IsAnimated bool `json:"is_animated"`
|
||||
IsVideo bool `json:"is_video"`
|
||||
}
|
||||
|
||||
// StickerSetType represents the type of a sticker or of the entire set
|
||||
@@ -100,16 +97,17 @@ type NewStickerSetOptions struct {
|
||||
|
||||
// InputSticker is a struct which describes a sticker to be added to a sticker set.
|
||||
type InputSticker struct {
|
||||
Sticker InputFile `json:"-"`
|
||||
EmojiList []string `json:"emoji_list"`
|
||||
MaskPosition *MaskPosition `json:"mask_position,omitempty"`
|
||||
Keywords *[]string `json:"keywords,omitempty"`
|
||||
Format StickerFormat `json:"format"`
|
||||
Sticker InputFile `json:"-"`
|
||||
EmojiList []string `json:"emoji_list"`
|
||||
}
|
||||
|
||||
// stickerEnvelope is a generic struct for all the various structs under the InputSticker interface.
|
||||
type stickerEnvelope struct {
|
||||
InputSticker
|
||||
Sticker string `json:"sticker"`
|
||||
InputSticker
|
||||
}
|
||||
|
||||
// SendSticker is used to send static .WEBP or animated .TGS stickers.
|
||||
@@ -118,7 +116,7 @@ func (a API) SendSticker(stickerID string, chatID int64, opts *StickerOptions) (
|
||||
|
||||
vals.Set("sticker", stickerID)
|
||||
vals.Set("chat_id", itoa(chatID))
|
||||
return get[APIResponseMessage](a.base, "sendSticker", addValues(vals, opts))
|
||||
return res, a.client.get(a.base, "sendSticker", addValues(vals, opts), &res)
|
||||
}
|
||||
|
||||
// GetStickerSet is used to get a sticker set.
|
||||
@@ -126,30 +124,16 @@ func (a API) GetStickerSet(name string) (res APIResponseStickerSet, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("name", name)
|
||||
return get[APIResponseStickerSet](a.base, "getStickerSet", vals)
|
||||
return res, a.client.get(a.base, "getStickerSet", vals, &res)
|
||||
}
|
||||
|
||||
// GetCustomEmojiStickers is used to get information about custom emoji stickers by their identifiers.
|
||||
func (a API) GetCustomEmojiStickers(customEmojiIDs ...string) (res APIResponseStickers, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
jsn, _ := json.Marshal(customEmojiIDs)
|
||||
|
||||
var url = fmt.Sprintf(
|
||||
"%sgetCustomEmojiStickers?custom_emoji_ids=%s",
|
||||
a.base,
|
||||
jsn,
|
||||
)
|
||||
|
||||
cnt, err := sendGetRequest(url)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(cnt, &res); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = check(res)
|
||||
return
|
||||
vals.Set("custom_emoji_ids", string(jsn))
|
||||
return res, a.client.get(a.base, "getCustomEmojiStickers", vals, &res)
|
||||
}
|
||||
|
||||
// UploadStickerFile is used to upload a .PNG file with a sticker for later use in
|
||||
@@ -159,18 +143,17 @@ func (a API) UploadStickerFile(userID int64, sticker InputFile, format StickerFo
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("sticker_format", string(format))
|
||||
return postFile[APIResponseFile](a.base, "uploadStickerFile", "sticker", sticker, InputFile{}, vals)
|
||||
return res, a.client.postFile(a.base, "uploadStickerFile", "sticker", sticker, InputFile{}, vals, &res)
|
||||
}
|
||||
|
||||
// CreateNewStickerSet is used to create a new sticker set owned by a user.
|
||||
func (a API) CreateNewStickerSet(userID int64, name, title string, stickers []InputSticker, format StickerFormat, opts *NewStickerSetOptions) (res APIResponseBool, err error) {
|
||||
func (a API) CreateNewStickerSet(userID int64, name, title string, stickers []InputSticker, opts *NewStickerSetOptions) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("name", name)
|
||||
vals.Set("title", title)
|
||||
vals.Set("sticker_format", string(format))
|
||||
return postStickers[APIResponseBool](a.base, "createNewStickerSet", addValues(vals, opts), stickers...)
|
||||
return res, a.client.postStickers(a.base, "createNewStickerSet", addValues(vals, opts), &res, stickers...)
|
||||
}
|
||||
|
||||
// AddStickerToSet is used to add a new sticker to a set created by the bot.
|
||||
@@ -179,7 +162,7 @@ func (a API) AddStickerToSet(userID int64, name string, sticker InputSticker) (r
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("name", name)
|
||||
return postStickers[APIResponseBool](a.base, "addStickerToSet", vals, sticker)
|
||||
return res, a.client.postStickers(a.base, "addStickerToSet", vals, &res, sticker)
|
||||
}
|
||||
|
||||
// SetStickerPositionInSet is used to move a sticker in a set created by the bot to a specific position.
|
||||
@@ -188,7 +171,7 @@ func (a API) SetStickerPositionInSet(sticker string, position int) (res APIRespo
|
||||
|
||||
vals.Set("sticker", sticker)
|
||||
vals.Set("position", itoa(int64(position)))
|
||||
return get[APIResponseBase](a.base, "setStickerPositionInSet", vals)
|
||||
return res, a.client.get(a.base, "setStickerPositionInSet", vals, &res)
|
||||
}
|
||||
|
||||
// DeleteStickerFromSet is used to delete a sticker from a set created by the bot.
|
||||
@@ -196,7 +179,18 @@ func (a API) DeleteStickerFromSet(sticker string) (res APIResponseBase, err erro
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("sticker", sticker)
|
||||
return get[APIResponseBase](a.base, "deleteStickerFromSet", vals)
|
||||
return res, a.client.get(a.base, "deleteStickerFromSet", vals, &res)
|
||||
}
|
||||
|
||||
// ReplaceStickerInSet is used to replace an existing sticker in a sticker set with a new one.
|
||||
// The method is equivalent to calling DeleteStickerFromSet, then AddStickerToSet, then SetStickerPositionInSet.
|
||||
func (a API) ReplaceStickerInSet(userID int64, name string, old_sticker string, sticker InputSticker) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("user_id", itoa(userID))
|
||||
vals.Set("name", name)
|
||||
vals.Set("old_sticker", old_sticker)
|
||||
return res, a.client.postStickers(a.base, "replaceStickerInSet", vals, &res, sticker)
|
||||
}
|
||||
|
||||
// SetStickerEmojiList is used to change the list of emoji assigned to a regular or custom emoji sticker.
|
||||
@@ -208,7 +202,7 @@ func (a API) SetStickerEmojiList(sticker string, emojis []string) (res APIRespon
|
||||
|
||||
vals.Set("sticker", sticker)
|
||||
vals.Set("emoji_list", string(jsn))
|
||||
return get[APIResponseBool](a.base, "setStickerEmojiList", vals)
|
||||
return res, a.client.get(a.base, "setStickerEmojiList", vals, &res)
|
||||
}
|
||||
|
||||
// SetStickerKeywords is used to change search keywords assigned to a regular or custom emoji sticker.
|
||||
@@ -220,7 +214,7 @@ func (a API) SetStickerKeywords(sticker string, keywords []string) (res APIRespo
|
||||
|
||||
vals.Set("sticker", sticker)
|
||||
vals.Set("keywords", string(jsn))
|
||||
return get[APIResponseBool](a.base, "setStickerKeywords", vals)
|
||||
return res, a.client.get(a.base, "setStickerKeywords", vals, &res)
|
||||
}
|
||||
|
||||
// SetStickerMaskPosition is used to change the mask position of a mask sticker.
|
||||
@@ -232,7 +226,7 @@ func (a API) SetStickerMaskPosition(sticker string, mask MaskPosition) (res APIR
|
||||
|
||||
vals.Set("sticker", sticker)
|
||||
vals.Set("mask_position", string(jsn))
|
||||
return get[APIResponseBool](a.base, "setStickerMaskPosition", vals)
|
||||
return res, a.client.get(a.base, "setStickerMaskPosition", vals, &res)
|
||||
}
|
||||
|
||||
// SetStickerSetTitle is used to set the title of a created sticker set.
|
||||
@@ -241,16 +235,17 @@ func (a API) SetStickerSetTitle(name, title string) (res APIResponseBool, err er
|
||||
|
||||
vals.Set("name", name)
|
||||
vals.Set("title", title)
|
||||
return get[APIResponseBool](a.base, "setStickerSetTitle", vals)
|
||||
return res, a.client.get(a.base, "setStickerSetTitle", vals, &res)
|
||||
}
|
||||
|
||||
// SetStickerSetThumbnail is used to set the thumbnail of a sticker set.
|
||||
func (a API) SetStickerSetThumbnail(name string, userID int64, thumbnail InputFile) (res APIResponseBase, err error) {
|
||||
func (a API) SetStickerSetThumbnail(name string, userID int64, thumbnail InputFile, format StickerFormat) (res APIResponseBase, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("name", name)
|
||||
vals.Set("user_id", itoa(userID))
|
||||
return postFile[APIResponseBase](a.base, "setStickerSetThumbnail", "thumbnail", thumbnail, InputFile{}, vals)
|
||||
vals.Set("format", string(format))
|
||||
return res, a.client.postFile(a.base, "setStickerSetThumbnail", "thumbnail", thumbnail, InputFile{}, vals, &res)
|
||||
}
|
||||
|
||||
// SetCustomEmojiStickerSetThumbnail is used to set the thumbnail of a custom emoji sticker set.
|
||||
@@ -259,7 +254,7 @@ func (a API) SetCustomEmojiStickerSetThumbnail(name, emojiID string) (res APIRes
|
||||
|
||||
vals.Set("name", name)
|
||||
vals.Set("custom_emoji_id", emojiID)
|
||||
return get[APIResponseBool](a.base, "setCustomEmojiStickerSetThumbnail", vals)
|
||||
return res, a.client.get(a.base, "setCustomEmojiStickerSetThumbnail", vals, &res)
|
||||
}
|
||||
|
||||
// DeleteStickerSet is used to delete a sticker set that was created by the bot.
|
||||
@@ -267,10 +262,10 @@ func (a API) DeleteStickerSet(name string) (res APIResponseBool, err error) {
|
||||
var vals = make(url.Values)
|
||||
|
||||
vals.Set("name", name)
|
||||
return get[APIResponseBool](a.base, "DeleteStickerSet", vals)
|
||||
return res, a.client.get(a.base, "DeleteStickerSet", vals, &res)
|
||||
}
|
||||
|
||||
// GetForumTopicIconStickers is used to get custom emoji stickers, which can be used as a forum topic icon by any user.
|
||||
func (a API) GetForumTopicIconStickers() (res APIResponseStickers, err error) {
|
||||
return get[APIResponseStickers](a.base, "getForumTopicIconStickers", nil)
|
||||
return res, a.client.get(a.base, "getForumTopicIconStickers", nil, &res)
|
||||
}
|
||||
|
||||
544
vendor/github.com/NicoNex/echotron/v3/types.go
generated
vendored
544
vendor/github.com/NicoNex/echotron/v3/types.go
generated
vendored
@@ -23,28 +23,40 @@ import "encoding/json"
|
||||
// Update represents an incoming update.
|
||||
// At most one of the optional parameters can be present in any given update.
|
||||
type Update struct {
|
||||
ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"`
|
||||
ChatBoost *ChatBoostUpdated `json:"chat_boost,omitempty"`
|
||||
RemovedChatBoost *ChatBoostRemoved `json:"removed_chat_boost,omitempty"`
|
||||
Message *Message `json:"message,omitempty"`
|
||||
EditedMessage *Message `json:"edited_message,omitempty"`
|
||||
ChannelPost *Message `json:"channel_post,omitempty"`
|
||||
EditedChannelPost *Message `json:"edited_channel_post,omitempty"`
|
||||
MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"`
|
||||
MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"`
|
||||
InlineQuery *InlineQuery `json:"inline_query,omitempty"`
|
||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"`
|
||||
CallbackQuery *CallbackQuery `json:"callback_query,omitempty"`
|
||||
ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"`
|
||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"`
|
||||
MyChatMember *ChatMemberUpdated `json:"my_chat_member,omitempty"`
|
||||
ChatMember *ChatMemberUpdated `json:"chat_member,omitempty"`
|
||||
ID int `json:"update_id"`
|
||||
ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"`
|
||||
ChatBoost *ChatBoostUpdated `json:"chat_boost,omitempty"`
|
||||
RemovedChatBoost *ChatBoostRemoved `json:"removed_chat_boost,omitempty"`
|
||||
Message *Message `json:"message,omitempty"`
|
||||
EditedMessage *Message `json:"edited_message,omitempty"`
|
||||
ChannelPost *Message `json:"channel_post,omitempty"`
|
||||
EditedChannelPost *Message `json:"edited_channel_post,omitempty"`
|
||||
BusinessConnection *BusinessConnection `json:"business_connection,omitempty"`
|
||||
BusinessMessage *Message `json:"business_message,omitempty"`
|
||||
EditedBusinessMessage *Message `json:"edited_business_message,omitempty"`
|
||||
DeletedBusinessMessages *BusinessMessagesDeleted `json:"deleted_business_messages,omitempty"`
|
||||
MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"`
|
||||
MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"`
|
||||
InlineQuery *InlineQuery `json:"inline_query,omitempty"`
|
||||
ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result,omitempty"`
|
||||
CallbackQuery *CallbackQuery `json:"callback_query,omitempty"`
|
||||
ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"`
|
||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"`
|
||||
Poll *Poll `json:"poll,omitempty"`
|
||||
PollAnswer *PollAnswer `json:"poll_answer,omitempty"`
|
||||
MyChatMember *ChatMemberUpdated `json:"my_chat_member,omitempty"`
|
||||
ChatMember *ChatMemberUpdated `json:"chat_member,omitempty"`
|
||||
ID int `json:"update_id"`
|
||||
}
|
||||
|
||||
// ChatID returns the ID of the chat the update is coming from.
|
||||
func (u Update) ChatID() int64 {
|
||||
switch {
|
||||
case u.ChatJoinRequest != nil:
|
||||
return u.ChatJoinRequest.Chat.ID
|
||||
case u.ChatBoost != nil:
|
||||
return u.ChatBoost.Chat.ID
|
||||
case u.RemovedChatBoost != nil:
|
||||
return u.RemovedChatBoost.Chat.ID
|
||||
case u.Message != nil:
|
||||
return u.Message.Chat.ID
|
||||
case u.EditedMessage != nil:
|
||||
@@ -53,6 +65,18 @@ func (u Update) ChatID() int64 {
|
||||
return u.ChannelPost.Chat.ID
|
||||
case u.EditedChannelPost != nil:
|
||||
return u.EditedChannelPost.Chat.ID
|
||||
case u.BusinessConnection != nil:
|
||||
return u.BusinessConnection.User.ID
|
||||
case u.BusinessMessage != nil:
|
||||
return u.BusinessMessage.Chat.ID
|
||||
case u.EditedBusinessMessage != nil:
|
||||
return u.EditedBusinessMessage.Chat.ID
|
||||
case u.DeletedBusinessMessages != nil:
|
||||
return u.DeletedBusinessMessages.Chat.ID
|
||||
case u.MessageReaction != nil:
|
||||
return u.MessageReaction.Chat.ID
|
||||
case u.MessageReactionCount != nil:
|
||||
return u.MessageReactionCount.Chat.ID
|
||||
case u.InlineQuery != nil:
|
||||
return u.InlineQuery.From.ID
|
||||
case u.ChosenInlineResult != nil:
|
||||
@@ -63,12 +87,12 @@ func (u Update) ChatID() int64 {
|
||||
return u.ShippingQuery.From.ID
|
||||
case u.PreCheckoutQuery != nil:
|
||||
return u.PreCheckoutQuery.From.ID
|
||||
case u.PollAnswer != nil:
|
||||
return u.PollAnswer.User.ID
|
||||
case u.MyChatMember != nil:
|
||||
return u.MyChatMember.Chat.ID
|
||||
case u.ChatMember != nil:
|
||||
return u.ChatMember.Chat.ID
|
||||
case u.ChatJoinRequest != nil:
|
||||
return u.ChatJoinRequest.Chat.ID
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
@@ -215,9 +239,9 @@ func (a APIResponseString) Base() APIResponseBase {
|
||||
}
|
||||
|
||||
// APIResponseChat represents the incoming response from Telegram servers.
|
||||
// Used by all methods that return a Chat object on success.
|
||||
// Used by all methods that return a ChatFullInfo object on success.
|
||||
type APIResponseChat struct {
|
||||
Result *Chat `json:"result,omitempty"`
|
||||
Result *ChatFullInfo `json:"result,omitempty"`
|
||||
APIResponseBase
|
||||
}
|
||||
|
||||
@@ -443,7 +467,7 @@ func (a APIResponseBotName) Base() APIResponseBase {
|
||||
}
|
||||
|
||||
// APIResponseUserChatBoosts represents the incoming response from Telegram servers.
|
||||
// Used by all methods that return a BotName object on success.
|
||||
// Used by all methods that return a UserChatBoosts object on success.
|
||||
type APIResponseUserChatBoosts struct {
|
||||
Result *UserChatBoosts `json:"result,omitempty"`
|
||||
APIResponseBase
|
||||
@@ -454,6 +478,30 @@ func (a APIResponseUserChatBoosts) Base() APIResponseBase {
|
||||
return a.APIResponseBase
|
||||
}
|
||||
|
||||
// APIResponseBusinessConnection represents the incoming response from Telegram servers.
|
||||
// Used by all methods that return a BusinessConnection object on success.
|
||||
type APIResponseBusinessConnection struct {
|
||||
Result *BusinessConnection `json:"result,omitempty"`
|
||||
APIResponseBase
|
||||
}
|
||||
|
||||
// Base returns the contained object of type APIResponseBase.
|
||||
func (a APIResponseBusinessConnection) Base() APIResponseBase {
|
||||
return a.APIResponseBase
|
||||
}
|
||||
|
||||
// APIResponseStarTransactions represents the incoming response from Telegram servers.
|
||||
// Used by all methods that return a StarTransactions object on success.
|
||||
type APIResponseStarTransactions struct {
|
||||
Result *StarTransactions `json:"result,omitempty"`
|
||||
APIResponseBase
|
||||
}
|
||||
|
||||
// Base returns the contained object of type APIResponseBase.
|
||||
func (a APIResponseStarTransactions) Base() APIResponseBase {
|
||||
return a.APIResponseBase
|
||||
}
|
||||
|
||||
// User represents a Telegram user or bot.
|
||||
type User struct {
|
||||
FirstName string `json:"first_name"`
|
||||
@@ -465,49 +513,67 @@ type User struct {
|
||||
CanJoinGroups bool `json:"can_join_groups,omitempty"`
|
||||
CanReadAllGroupMessages bool `json:"can_read_all_group_messages,omitempty"`
|
||||
SupportsInlineQueries bool `json:"supports_inline_queries,omitempty"`
|
||||
CanConnectToBusiness bool `json:"can_connect_to_business,omitempty"`
|
||||
IsPremium bool `json:"is_premium,omitempty"`
|
||||
AddedToAttachmentMenu bool `json:"added_to_attachment_menu,omitempty"`
|
||||
}
|
||||
|
||||
// Chat represents a chat.
|
||||
type Chat struct {
|
||||
Permissions *ChatPermissions `json:"permissions,omitempty"`
|
||||
Location *ChatLocation `json:"location,omitempty"`
|
||||
PinnedMessage *Message `json:"pinned_message,omitempty"`
|
||||
Photo *ChatPhoto `json:"photo,omitempty"`
|
||||
ActiveUsernames *[]string `json:"active_usernames,omitempty"`
|
||||
AvailableReactions *[]ReactionType `json:"available_reactions,omitempty"`
|
||||
BackgroundCustomEmojiID string `json:"background_custom_emoji_id,omitempty"`
|
||||
ProfileBackgroundCustomEmojiID string `json:"profile_background_custom_emoji_id,omitempty"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
StickerSetName string `json:"sticker_set_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
InviteLink string `json:"invite_link,omitempty"`
|
||||
EmojiStatusCustomEmojiID string `json:"emoji_status_custom_emoji_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
CustomEmojiStickerSetName string `json:"custom_emoji_sticker_set_name,omitempty"`
|
||||
AccentColorID int `json:"accent_color_id,omitempty"`
|
||||
ProfileAccentColorID int `json:"profile_accent_color_id,omitempty"`
|
||||
EmojiStatusExpirationDate int `json:"emoji_status_expiration_date,omitempty"`
|
||||
MessageAutoDeleteTime int `json:"message_auto_delete_time,omitempty"`
|
||||
SlowModeDelay int `json:"slow_mode_delay,omitempty"`
|
||||
UnrestrictBoostCount int `json:"unrestrict_boost_count,omitempty"`
|
||||
LinkedChatID int64 `json:"linked_chat_id,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
IsForum bool `json:"is_forum,omitempty"`
|
||||
HasAggressiveAntiSpamEnabled bool `json:"has_aggressive_anti_spam_enabled,omitempty"`
|
||||
HasHiddenMembers bool `json:"has_hidden_members,omitempty"`
|
||||
HasProtectedContent bool `json:"has_protected_content,omitempty"`
|
||||
HasVisibleHistory bool `json:"has_visible_history,omitempty"`
|
||||
HasPrivateForwards bool `json:"has_private_forwards,omitempty"`
|
||||
CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"`
|
||||
JoinToSendMessages bool `json:"join_to_send_messages,omitempty"`
|
||||
JoinByRequest bool `json:"join_by_request,omitempty"`
|
||||
HasRestrictedVoiceAndVideoMessages bool `json:"has_restricted_voice_and_video_messages,omitempty"`
|
||||
Type string `json:"type"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
IsForum bool `json:"is_forum,omitempty"`
|
||||
}
|
||||
|
||||
// ChatFullInfo contains full information about a chat.
|
||||
type ChatFullInfo struct {
|
||||
Permissions *ChatPermissions `json:"permissions,omitempty"`
|
||||
Location *ChatLocation `json:"location,omitempty"`
|
||||
PinnedMessage *Message `json:"pinned_message,omitempty"`
|
||||
Photo *ChatPhoto `json:"photo,omitempty"`
|
||||
ActiveUsernames *[]string `json:"active_usernames,omitempty"`
|
||||
AvailableReactions *[]ReactionType `json:"available_reactions,omitempty"`
|
||||
BusinessIntro *BusinessIntro `json:"business_intro,omitempty"`
|
||||
BusinessLocation *BusinessLocation `json:"business_location,omitempty"`
|
||||
BusinessOpeningHours *BusinessOpeningHours `json:"business_opening_hours,omitempty"`
|
||||
PersonalChat *Chat `json:"personal_chat,omitempty"`
|
||||
Birthdate *Birthdate `json:"birthdate,omitempty"`
|
||||
BackgroundCustomEmojiID string `json:"background_custom_emoji_id,omitempty"`
|
||||
ProfileBackgroundCustomEmojiID string `json:"profile_background_custom_emoji_id,omitempty"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
StickerSetName string `json:"sticker_set_name,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
FirstName string `json:"first_name,omitempty"`
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
InviteLink string `json:"invite_link,omitempty"`
|
||||
EmojiStatusCustomEmojiID string `json:"emoji_status_custom_emoji_id,omitempty"`
|
||||
Type string `json:"type"`
|
||||
CustomEmojiStickerSetName string `json:"custom_emoji_sticker_set_name,omitempty"`
|
||||
AccentColorID int `json:"accent_color_id,omitempty"`
|
||||
MaxReactionCount int `json:"max_reaction_count,omitempty"`
|
||||
ProfileAccentColorID int `json:"profile_accent_color_id,omitempty"`
|
||||
EmojiStatusExpirationDate int `json:"emoji_status_expiration_date,omitempty"`
|
||||
MessageAutoDeleteTime int `json:"message_auto_delete_time,omitempty"`
|
||||
SlowModeDelay int `json:"slow_mode_delay,omitempty"`
|
||||
UnrestrictBoostCount int `json:"unrestrict_boost_count,omitempty"`
|
||||
LinkedChatID int64 `json:"linked_chat_id,omitempty"`
|
||||
ID int64 `json:"id"`
|
||||
IsForum bool `json:"is_forum,omitempty"`
|
||||
HasAggressiveAntiSpamEnabled bool `json:"has_aggressive_anti_spam_enabled,omitempty"`
|
||||
HasHiddenMembers bool `json:"has_hidden_members,omitempty"`
|
||||
HasProtectedContent bool `json:"has_protected_content,omitempty"`
|
||||
HasVisibleHistory bool `json:"has_visible_history,omitempty"`
|
||||
HasPrivateForwards bool `json:"has_private_forwards,omitempty"`
|
||||
CanSetStickerSet bool `json:"can_set_sticker_set,omitempty"`
|
||||
JoinToSendMessages bool `json:"join_to_send_messages,omitempty"`
|
||||
JoinByRequest bool `json:"join_by_request,omitempty"`
|
||||
HasRestrictedVoiceAndVideoMessages bool `json:"has_restricted_voice_and_video_messages,omitempty"`
|
||||
}
|
||||
|
||||
// Message represents a message.
|
||||
@@ -561,12 +627,16 @@ type Message struct {
|
||||
LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||
ForwardOrigin *MessageOrigin `json:"forward_origin,omitempty"`
|
||||
BoostAdded *ChatBoostAdded `json:"boost_added,omitempty"`
|
||||
ChatBackgroundSet *ChatBackground `json:"chat_background_set,omitempty"`
|
||||
SenderBusinessBot *User `json:"sender_business_bot,omitempty"`
|
||||
MediaGroupID string `json:"media_group_id,omitempty"`
|
||||
ConnectedWebsite string `json:"connected_website,omitempty"`
|
||||
NewChatTitle string `json:"new_chat_title,omitempty"`
|
||||
AuthorSignature string `json:"author_signature,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Text string `json:"text,omitempty"`
|
||||
BusinessConnectionID string `json:"business_connection_id,omitempty"`
|
||||
EffectID string `json:"effect_id,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
NewChatPhoto []*PhotoSize `json:"new_chat_photo,omitempty"`
|
||||
NewChatMembers []*User `json:"new_chat_members,omitempty"`
|
||||
@@ -588,6 +658,8 @@ type Message struct {
|
||||
ChannelChatCreated bool `json:"channel_chat_created,omitempty"`
|
||||
HasProtectedContent bool `json:"has_protected_content,omitempty"`
|
||||
HasMediaSpoiler bool `json:"has_media_spoiler,omitempty"`
|
||||
IsFromOffline bool `json:"is_from_offline,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// MessageID represents a unique message identifier.
|
||||
@@ -701,8 +773,16 @@ type Dice struct {
|
||||
|
||||
// PollOption contains information about one answer option in a poll.
|
||||
type PollOption struct {
|
||||
Text string `json:"text"`
|
||||
VoterCount int `json:"voter_count"`
|
||||
Text string `json:"text"`
|
||||
TextEntities []*MessageEntity `json:"text_entities,omitempty"`
|
||||
VoterCount int `json:"voter_count"`
|
||||
}
|
||||
|
||||
// InputPollOption contains information about one answer option in a poll to send.
|
||||
type InputPollOption struct {
|
||||
Text string `json:"text"`
|
||||
TextParseMode ParseMode `json:"text_parse_mode,omitempty"`
|
||||
TextEntities []*MessageEntity `json:"text_entities,omitempty"`
|
||||
}
|
||||
|
||||
// PollAnswer represents an answer of a user in a non-anonymous poll.
|
||||
@@ -720,6 +800,7 @@ type Poll struct {
|
||||
Explanation string `json:"explanation,omitempty"`
|
||||
ID string `json:"id"`
|
||||
ExplanationEntities []*MessageEntity `json:"explanation_entities,omitempty"`
|
||||
QuestionEntities []*MessageEntity `json:"question_entities,omitempty"`
|
||||
Options []*PollOption `json:"options"`
|
||||
OpenPeriod int `json:"open_period,omitempty"`
|
||||
TotalVoterCount int `json:"total_voter_count"`
|
||||
@@ -885,12 +966,13 @@ type ChatMember struct {
|
||||
// ChatMemberUpdated represents changes in the status of a chat member.
|
||||
type ChatMemberUpdated struct {
|
||||
InviteLink *ChatInviteLink `json:"invite_link,omitempty"`
|
||||
Chat Chat `json:"chat"`
|
||||
From User `json:"from"`
|
||||
OldChatMember ChatMember `json:"old_chat_member"`
|
||||
NewChatMember ChatMember `json:"new_chat_member"`
|
||||
Chat Chat `json:"chat"`
|
||||
ViaChatFolderInviteLink bool `json:"via_chat_folder_invite_link,omitempty"`
|
||||
Date int `json:"date"`
|
||||
ViaChatFolderInviteLink bool `json:"via_chat_folder_invite_link,omitempty"`
|
||||
ViaJoinRequest bool `json:"via_join_request,omitempty"`
|
||||
}
|
||||
|
||||
// ChatPermissions describes actions that a non-administrator user is allowed to take in a chat.
|
||||
@@ -911,6 +993,38 @@ type ChatPermissions struct {
|
||||
CanManageTopics bool `json:"can_manage_topics,omitempty"`
|
||||
}
|
||||
|
||||
// Birthdate
|
||||
type Birthdate struct {
|
||||
Day int `json:"day"`
|
||||
Month int `json:"month"`
|
||||
Year int `json:"year"`
|
||||
}
|
||||
|
||||
// BusinessIntro
|
||||
type BusinessIntro struct {
|
||||
Sticker *Sticker `json:"sticker,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
}
|
||||
|
||||
// BusinessLocation
|
||||
type BusinessLocation struct {
|
||||
Location *Location `json:"location,omitempty"`
|
||||
Address string `json:"address"`
|
||||
}
|
||||
|
||||
// BusinessOpeningHoursInterval
|
||||
type BusinessOpeningHoursInterval struct {
|
||||
OpeningMinute int `json:"opening_minute"`
|
||||
ClosingMinute int `json:"closing_minute"`
|
||||
}
|
||||
|
||||
// BusinessOpeningHours
|
||||
type BusinessOpeningHours struct {
|
||||
TimeZoneName string `json:"time_zone_name"`
|
||||
OpeningHours []BusinessOpeningHoursInterval `json:"opening_hours"`
|
||||
}
|
||||
|
||||
// ChatLocation represents a location to which a chat is connected.
|
||||
type ChatLocation struct {
|
||||
Location *Location `json:"location"`
|
||||
@@ -1025,12 +1139,13 @@ func (i mediaEnvelope) MarshalJSON() (cnt []byte, err error) {
|
||||
// InputMediaPhoto represents a photo to be sent.
|
||||
// Type MUST BE "photo".
|
||||
type InputMediaPhoto struct {
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// media is a method which allows to obtain the Media (type InputFile) field from the InputMedia* struct.
|
||||
@@ -1045,17 +1160,18 @@ func (i InputMediaPhoto) groupable() {}
|
||||
// InputMediaVideo represents a video to be sent.
|
||||
// Type MUST BE "video".
|
||||
type InputMediaVideo struct {
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Thumbnail InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
SupportsStreaming bool `json:"supports_streaming,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Thumbnail InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
SupportsStreaming bool `json:"supports_streaming,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// media is a method which allows to obtain the Media (type InputFile) field from the InputMedia* struct.
|
||||
@@ -1070,16 +1186,17 @@ func (i InputMediaVideo) groupable() {}
|
||||
// InputMediaAnimation represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent.
|
||||
// Type MUST BE "animation".
|
||||
type InputMediaAnimation struct {
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Thumbnail InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
Type InputMediaType `json:"type"`
|
||||
Media InputFile `json:"-"`
|
||||
Thumbnail InputFile `json:"-"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
ParseMode ParseMode `json:"parse_mode,omitempty"`
|
||||
CaptionEntities []*MessageEntity `json:"caption_entities,omitempty"`
|
||||
Width int `json:"width,omitempty"`
|
||||
Height int `json:"height,omitempty"`
|
||||
Duration int `json:"duration,omitempty"`
|
||||
HasSpoiler bool `json:"has_spoiler,omitempty"`
|
||||
ShowCaptionAboveMedia bool `json:"show_caption_above_media,omitempty"`
|
||||
}
|
||||
|
||||
// media is a method which allows to obtain the Media (type InputFile) field from the InputMedia* struct.
|
||||
@@ -1172,8 +1289,8 @@ type BotName struct {
|
||||
type ChatJoinRequest struct {
|
||||
InviteLink *ChatInviteLink `json:"invite_link,omitempty"`
|
||||
Bio string `json:"bio,omitempty"`
|
||||
From User `json:"user"`
|
||||
Chat Chat `json:"chat"`
|
||||
From User `json:"user"`
|
||||
Date int `json:"date"`
|
||||
UserChatID int64 `json:"user_chat_id"`
|
||||
}
|
||||
@@ -1183,6 +1300,90 @@ type ChatBoostAdded struct {
|
||||
BoostCount int `json:"boost_count"`
|
||||
}
|
||||
|
||||
// BackgroundFill describes the way a background is filled based on the selected colors.
|
||||
type BackgroundFill interface {
|
||||
ImplementsBackgroundFill()
|
||||
}
|
||||
|
||||
// BackgroundFillSolid is a background filled using the selected color.
|
||||
// Type MUST be "solid".
|
||||
type BackgroundFillSolid struct {
|
||||
Type string `json:"type"`
|
||||
Color int `json:"color"`
|
||||
}
|
||||
|
||||
func (b BackgroundFillSolid) ImplementsBackgroundFill() {}
|
||||
|
||||
// BackgroundFillGradient is a background with a gradient fill.
|
||||
// Type MUST be "gradient".
|
||||
type BackgroundFillGradient struct {
|
||||
Type string `json:"type"`
|
||||
TopColor int `json:"top_color"`
|
||||
BottomColor int `json:"bottom_color"`
|
||||
RotationAngle int `json:"rotation_angle"`
|
||||
}
|
||||
|
||||
func (b BackgroundFillGradient) ImplementsBackgroundFill() {}
|
||||
|
||||
// BackgroundFillFreeformGradient is a background with a freeform gradient that rotates after every message in the chat.
|
||||
// Type MUST be "freeform_gradient".
|
||||
type BackgroundFillFreeformGradient struct {
|
||||
Type string `json:"type"`
|
||||
Colors []int `json:"colors"`
|
||||
}
|
||||
|
||||
func (b BackgroundFillFreeformGradient) ImplementsBackgroundFill() {}
|
||||
|
||||
// BackgroundType describes the type of a background.
|
||||
type BackgroundType interface {
|
||||
ImplementsBackgroundType()
|
||||
}
|
||||
|
||||
// BackgroundTypeFill is a background which is automatically filled based on the selected colors.
|
||||
// Type MUST be "fill".
|
||||
type BackgroundTypeFill struct {
|
||||
Fill BackgroundFill `json:"fill"`
|
||||
Type string `json:"type"`
|
||||
DarkThemeDimming int `json:"dark_theme_dimming"`
|
||||
}
|
||||
|
||||
func (b BackgroundTypeFill) ImplementsBackgroundType() {}
|
||||
|
||||
// BackgroundTypeWallpaper is a background which is a wallpaper in the JPEG format.
|
||||
// Type MUST be "wallpaper".
|
||||
type BackgroundTypeWallpaper struct {
|
||||
Type string `json:"type"`
|
||||
Document Document `json:"document"`
|
||||
DarkThemeDimming int `json:"dark_theme_dimming"`
|
||||
IsBlurred bool `json:"is_blurred,omitempty"`
|
||||
IsMoving bool `json:"is_moving,omitempty"`
|
||||
}
|
||||
|
||||
func (b BackgroundTypeWallpaper) ImplementsBackgroundType() {}
|
||||
|
||||
// BackgroundTypePattern is a PNG or TGV (gzipped subset of SVG with MIME type “application/x-tgwallpattern”) pattern
|
||||
// to be combined with the background fill chosen by the user.
|
||||
// Type MUST be "pattern".
|
||||
type BackgroundTypePattern struct {
|
||||
Fill BackgroundFill `json:"fill"`
|
||||
Type string `json:"type"`
|
||||
Document Document `json:"document"`
|
||||
Intensity int `json:"intensity"`
|
||||
IsInverted bool `json:"is_inverted,omitempty"`
|
||||
IsMoving bool `json:"is_moving,omitempty"`
|
||||
}
|
||||
|
||||
func (b BackgroundTypePattern) ImplementsBackgroundType() {}
|
||||
|
||||
// BackgroundTypeChatTheme is taken directly from a built-in chat theme.
|
||||
// Type MUST be "chat_theme".
|
||||
type BackgroundTypeChatTheme struct {
|
||||
Type string `json:"type"`
|
||||
ThemeName string `json:"theme_name"`
|
||||
}
|
||||
|
||||
func (b BackgroundTypeChatTheme) ImplementsBackgroundType() {}
|
||||
|
||||
// ForumTopicCreated represents a service message about a new forum topic created in the chat.
|
||||
type ForumTopicCreated struct {
|
||||
Name string `json:"name"`
|
||||
@@ -1190,6 +1391,11 @@ type ForumTopicCreated struct {
|
||||
IconColor int `json:"icon_color"`
|
||||
}
|
||||
|
||||
// ChatBackground represents a chat background.
|
||||
type ChatBackground struct {
|
||||
Type BackgroundType `json:"type"`
|
||||
}
|
||||
|
||||
// ForumTopicClosed represents a service message about a forum topic closed in the chat.
|
||||
type ForumTopicClosed struct{}
|
||||
|
||||
@@ -1210,8 +1416,8 @@ type GeneralForumTopicUnhidden struct{}
|
||||
|
||||
// WriteAccessAllowed represents a service message about a user allowing a bot added to the attachment menu to write messages.
|
||||
type WriteAccessAllowed struct {
|
||||
FromRequest bool `json:"from_request,omitempty"`
|
||||
WebAppName string `json:"web_app_name,omitempty"`
|
||||
FromRequest bool `json:"from_request,omitempty"`
|
||||
FromAttachmentMenu bool `json:"from_attachment_menu,omitempty"`
|
||||
}
|
||||
|
||||
@@ -1244,8 +1450,11 @@ type UserShared struct {
|
||||
|
||||
// ChatShared contains information about the chat whose identifier was shared with the bot using a KeyboardButtonRequestChat button.
|
||||
type ChatShared struct {
|
||||
RequestID int `json:"request_id"`
|
||||
ChatID int64 `json:"chat_id"`
|
||||
Photo *[]PhotoSize `json:"photo,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
RequestID int `json:"request_id"`
|
||||
ChatID int64 `json:"chat_id"`
|
||||
}
|
||||
|
||||
// Story represents a story.
|
||||
@@ -1254,28 +1463,12 @@ type Story struct {
|
||||
ID int64 `json:"id"`
|
||||
}
|
||||
|
||||
type ReactionType interface {
|
||||
ImplementsReactionType()
|
||||
}
|
||||
|
||||
// ReactionTypeEmoji is based on an emoji.
|
||||
// Type is always "emoji".
|
||||
type ReactionTypeEmoji struct {
|
||||
Type string `json:"type"`
|
||||
Emoji string `json:"emoji"`
|
||||
}
|
||||
|
||||
func (i ReactionTypeEmoji) ImplementsReactionType() {}
|
||||
|
||||
// ReactionTypeCustomEmoji is based on a custom emoji.
|
||||
// Type is always "custom_emoji".
|
||||
type ReactionTypeCustomEmoji struct {
|
||||
type ReactionType struct {
|
||||
Type string `json:"type"`
|
||||
Emoji string `json:"emoji"`
|
||||
CustomEmoji string `json:"custom_emoji"`
|
||||
}
|
||||
|
||||
func (i ReactionTypeCustomEmoji) ImplementsReactionType() {}
|
||||
|
||||
// ReactionCount represents a reaction added to a message along with the number of times it was added.
|
||||
type ReactionCount struct {
|
||||
Type ReactionType `json:"type"`
|
||||
@@ -1285,71 +1478,71 @@ type ReactionCount struct {
|
||||
// MessageReactionUpdated represents a change of a reaction on a message performed by a user.
|
||||
type MessageReactionUpdated struct {
|
||||
Chat Chat `json:"chat"`
|
||||
MessageID int `json:"message_id"`
|
||||
User User `json:"user,omitempty"`
|
||||
ActorChat Chat `json:"actor_chat,omitempty"`
|
||||
Date int `json:"date"`
|
||||
OldReaction []ReactionType `json:"old_reaction"`
|
||||
NewReaction []ReactionType `json:"new_reaction"`
|
||||
User User `json:"user,omitempty"`
|
||||
MessageID int `json:"message_id"`
|
||||
Date int `json:"date"`
|
||||
}
|
||||
|
||||
// MessageReactionCountUpdated represents reaction changes on a message with anonymous reactions.
|
||||
type MessageReactionCountUpdated struct {
|
||||
Reactions []ReactionCount `json:"reactions"`
|
||||
Chat Chat `json:"chat"`
|
||||
MessageID int `json:"message_id"`
|
||||
Date int `json:"date"`
|
||||
Reactions []ReactionCount `json:"reactions"`
|
||||
}
|
||||
|
||||
// TextQuote contains information about the quoted part of a message that is replied to by the given message.
|
||||
type TextQuote struct {
|
||||
Entities *[]MessageEntity `json:"entities,omitempty"`
|
||||
Text string `json:"text"`
|
||||
Position int `json:"position"`
|
||||
IsManual bool `json:"is_manual,omitempty"`
|
||||
Text string `json:"text"`
|
||||
Entities *[]MessageEntity `json:"entities,omitempty"`
|
||||
}
|
||||
|
||||
// ExternalReplyInfo contains information about a message that is being replied to, which may come from another chat or forum topic.
|
||||
type ExternalReplyInfo struct {
|
||||
Origin MessageOrigin `json:"origin"`
|
||||
Chat Chat `json:"chat,omitempty"`
|
||||
MessageID int `json:"message_id,omitempty"`
|
||||
LinkPreviewOptions LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||
Animation Animation `json:"animation,omitempty"`
|
||||
Audio Audio `json:"audio,omitempty"`
|
||||
Document Document `json:"document,omitempty"`
|
||||
Photo []PhotoSize `json:"photo,omitempty"`
|
||||
Sticker Sticker `json:"sticker,omitempty"`
|
||||
Story Story `json:"story,omitempty"`
|
||||
Video Video `json:"video,omitempty"`
|
||||
VideoNote VideoNote `json:"video_note,omitempty"`
|
||||
Voice Voice `json:"voice,omitempty"`
|
||||
HasMediaSpoiler bool `json:"has_media_spoiler,omitempty"`
|
||||
Contact Contact `json:"contact,omitempty"`
|
||||
Dice Dice `json:"dice,omitempty"`
|
||||
Game Game `json:"game,omitempty"`
|
||||
Giveaway Giveaway `json:"giveaway,omitempty"`
|
||||
GiveawayWinners GiveawayWinners `json:"giveaway_winners,omitempty"`
|
||||
Invoice Invoice `json:"invoice,omitempty"`
|
||||
Location Location `json:"location,omitempty"`
|
||||
Poll Poll `json:"poll,omitempty"`
|
||||
Venue Venue `json:"venue,omitempty"`
|
||||
Chat Chat `json:"chat,omitempty"`
|
||||
Document Document `json:"document,omitempty"`
|
||||
Origin MessageOrigin `json:"origin"`
|
||||
Contact Contact `json:"contact,omitempty"`
|
||||
Invoice Invoice `json:"invoice,omitempty"`
|
||||
Dice Dice `json:"dice,omitempty"`
|
||||
LinkPreviewOptions LinkPreviewOptions `json:"link_preview_options,omitempty"`
|
||||
Photo []PhotoSize `json:"photo,omitempty"`
|
||||
Audio Audio `json:"audio,omitempty"`
|
||||
Story Story `json:"story,omitempty"`
|
||||
Voice Voice `json:"voice,omitempty"`
|
||||
VideoNote VideoNote `json:"video_note,omitempty"`
|
||||
Game Game `json:"game,omitempty"`
|
||||
Video Video `json:"video,omitempty"`
|
||||
Animation Animation `json:"animation,omitempty"`
|
||||
Sticker Sticker `json:"sticker,omitempty"`
|
||||
Giveaway Giveaway `json:"giveaway,omitempty"`
|
||||
Poll Poll `json:"poll,omitempty"`
|
||||
GiveawayWinners GiveawayWinners `json:"giveaway_winners,omitempty"`
|
||||
Location Location `json:"location,omitempty"`
|
||||
MessageID int `json:"message_id,omitempty"`
|
||||
HasMediaSpoiler bool `json:"has_media_spoiler,omitempty"`
|
||||
}
|
||||
|
||||
// MessageOrigin describes the origin of a message.
|
||||
type MessageOrigin struct {
|
||||
Date int `json:"date"`
|
||||
SenderChat *Chat `json:"sender_chat,omitempty"`
|
||||
SenderUser *User `json:"sender_user,omitempty"`
|
||||
Type string `json:"type"`
|
||||
SenderUserName string `json:"sender_user_name,omitempty"` // Only for MessageOriginHiddenUser
|
||||
AuthorSignature string `json:"author_signature,omitempty"` // Only for MessageOriginChannel
|
||||
SenderChat *Chat `json:"sender_chat,omitempty"` // Only for MessageOriginChat
|
||||
SenderUser *User `json:"sender_user,omitempty"` // Only for MessageOriginUser
|
||||
SenderUserName string `json:"sender_user_name,omitempty"`
|
||||
AuthorSignature string `json:"author_signature,omitempty"`
|
||||
Date int `json:"date"`
|
||||
}
|
||||
|
||||
// LinkPreviewOptions describes the options used for link preview generation.
|
||||
type LinkPreviewOptions struct {
|
||||
IsDisabled bool `json:"is_disabled,omitempty"`
|
||||
URL string `json:"url,omitempty"`
|
||||
IsDisabled bool `json:"is_disabled,omitempty"`
|
||||
PreferSmallMedia bool `json:"prefer_small_media,omitempty"`
|
||||
PreferLargeMedia bool `json:"prefer_large_media,omitempty"`
|
||||
ShowAboveText bool `json:"show_above_text,omitempty"`
|
||||
@@ -1357,27 +1550,36 @@ type LinkPreviewOptions struct {
|
||||
|
||||
// ReplyParameters describes reply parameters for the message that is being sent.
|
||||
type ReplyParameters struct {
|
||||
MessageID int `json:"message_id"`
|
||||
ChatID int64 `json:"chat_id,omitempty"`
|
||||
AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"`
|
||||
Quote string `json:"quote,omitempty"`
|
||||
QuoteParseMode string `json:"quote_parse_mode,omitempty"`
|
||||
QuoteEntities []MessageEntity `json:"quote_entitites,omitempty"`
|
||||
MessageID int `json:"message_id"`
|
||||
ChatID int64 `json:"chat_id,omitempty"`
|
||||
QuotePosition int `json:"quote_position,omitempty"`
|
||||
AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"`
|
||||
}
|
||||
|
||||
// SharedUser contains information about a user that was shared with the bot using a KeyboardButtonRequestUser button.
|
||||
type SharedUser struct {
|
||||
Photo *[]PhotoSize `json:"photo,omitempty"`
|
||||
FirstName string `json:"firstname,omitempty"`
|
||||
LastName string `json:"lastname,omitempty"`
|
||||
Username string `json:"username,omitempty"`
|
||||
UserID int64 `json:"user_id"`
|
||||
}
|
||||
|
||||
// UsersShared contains information about the users whose identifiers were shared with the bot using a KeyboardButtonRequestUsers button.
|
||||
type UsersShared struct {
|
||||
RequestID int `json:"request_id"`
|
||||
UserIDs []int64 `json:"user_ids"`
|
||||
Users []SharedUser `json:"users"`
|
||||
RequestID int `json:"request_id"`
|
||||
}
|
||||
|
||||
// ChatBoost contains information about a chat boost.
|
||||
type ChatBoost struct {
|
||||
BoostID string `json:"boost_id"`
|
||||
Source ChatBoostSource `json:"source"`
|
||||
AddDate int `json:"add_date"`
|
||||
ExpirationDate int `json:"expiration_date"`
|
||||
Source ChatBoostSource `json:"source"`
|
||||
}
|
||||
|
||||
// ChatBoostSourceType is a custom type for the various chat boost sources.
|
||||
@@ -1392,8 +1594,8 @@ const (
|
||||
|
||||
// ChatBoostSource describes the source of a chat boost.
|
||||
type ChatBoostSource struct {
|
||||
Source ChatBoostSourceType `json:"source"`
|
||||
User *User `json:"user,omitempty"`
|
||||
Source ChatBoostSourceType `json:"source"`
|
||||
GiveawayMessageID int `json:"giveaway_message_id,omitempty"`
|
||||
IsUnclaimed bool `json:"is_unclaimed,omitempty"`
|
||||
}
|
||||
@@ -1406,10 +1608,10 @@ type ChatBoostUpdated struct {
|
||||
|
||||
// ChatBoostRemoved represents a boost removed from a chat.
|
||||
type ChatBoostRemoved struct {
|
||||
Chat Chat `json:"chat"`
|
||||
BoostID string `json:"boost_id"`
|
||||
RemoveDate int `json:"remove_date"`
|
||||
Chat Chat `json:"chat"`
|
||||
Source ChatBoostSource `json:"source"`
|
||||
RemoveDate int `json:"remove_date"`
|
||||
}
|
||||
|
||||
// UserChatBoosts represents a list of boosts added to a chat by a user.
|
||||
@@ -1417,39 +1619,57 @@ type UserChatBoosts struct {
|
||||
Boosts []ChatBoost `json:"boosts"`
|
||||
}
|
||||
|
||||
// BusinessConnection describes the connection of the bot with a business account.
|
||||
type BusinessConnection struct {
|
||||
ID string `json:"id"`
|
||||
User User `json:"user"`
|
||||
UserChatID int64 `json:"user_chat_id"`
|
||||
Date int64 `json:"date"`
|
||||
CanReply bool `json:"can_reply"`
|
||||
IsEnabled bool `json:"is_enabled"`
|
||||
}
|
||||
|
||||
// BusinessMessagesDeleted is received when messages are deleted from a connected business account.
|
||||
type BusinessMessagesDeleted struct {
|
||||
BusinessConnectionID string `json:"business_connection_id"`
|
||||
MessageIDs []int `json:"message_ids"`
|
||||
Chat Chat `json:"chat"`
|
||||
}
|
||||
|
||||
// Giveaway represents a message about a scheduled giveaway.
|
||||
type Giveaway struct {
|
||||
CountryCodes *[]string `json:"country_codes,omitempty"`
|
||||
PrizeDescription string `json:"prize_description,omitempty"`
|
||||
Chats []Chat `json:"chats"`
|
||||
WinnersSelectionDate int `json:"winners_selection_date"`
|
||||
WinnerCount int `json:"winner_count"`
|
||||
PremiumSubscriptionMonthCount int `json:"premium_subscription_month_count,omitempty"`
|
||||
OnlyNewMembers bool `json:"only_new_members,omitempty"`
|
||||
HasPublicWinners bool `json:"has_public_winners,omitempty"`
|
||||
PrizeDescription string `json:"prize_description,omitempty"`
|
||||
CountryCodes *[]string `json:"country_codes,omitempty"`
|
||||
PremiumSubscriptionMonthCount int `json:"premium_subscription_month_count,omitempty"`
|
||||
}
|
||||
|
||||
// GiveawayCreated represents a service message about the creation of a scheduled giveaway. Currently holds no information.
|
||||
// GiveawayCreated represents a service message about the creation of a scheduled giveaway.
|
||||
// Currently holds no information.
|
||||
type GiveawayCreated struct{}
|
||||
|
||||
// GiveawayWinners represents a message about the completion of a giveaway with public winners.
|
||||
type GiveawayWinners struct {
|
||||
PrizeDescription string `json:"prize_description,omitempty"`
|
||||
Chats []Chat `json:"chats"`
|
||||
Winners []User `json:"winners"`
|
||||
GiveawayMessageID int `json:"giveaway_message_id"`
|
||||
WinnersSelectionDate int `json:"winners_selection_date"`
|
||||
WinnerCount int `json:"winner_count"`
|
||||
Winners []User `json:"winners"`
|
||||
AdditionalChatCount int `json:"additional_chat_count,omitempty"`
|
||||
PremiumSubscriptionMonthCount int `json:"premium_subscription_month_count,omitempty"`
|
||||
UnclaimedPrizeCount int `json:"unclaimed_prize_count,omitempty"`
|
||||
OnlyNewMembers bool `json:"only_new_members,omitempty"`
|
||||
WasRefunded bool `json:"was_refunded,omitempty"`
|
||||
PrizeDescription string `json:"prize_description,omitempty"`
|
||||
}
|
||||
|
||||
// GiveawayCompleted represents a service message about the completion of a giveaway without public winners.
|
||||
type GiveawayCompleted struct {
|
||||
GiveawayMessage *Message `json:"giveaway_message,omitempty"`
|
||||
WinnerCount int `json:"winner_count"`
|
||||
UnclaimedPrizeCount int `json:"unclaimed_prize_count,omitempty"`
|
||||
GiveawayMessage *Message `json:"giveaway_message,omitempty"`
|
||||
}
|
||||
|
||||
2
vendor/github.com/NicoNex/echotron/v3/webapp.go
generated
vendored
2
vendor/github.com/NicoNex/echotron/v3/webapp.go
generated
vendored
@@ -53,5 +53,5 @@ func (a API) AnswerWebAppQuery(webAppQueryID string, result InlineQueryResult) (
|
||||
|
||||
vals.Set("web_app_query_id", webAppQueryID)
|
||||
vals.Set("result", string(resultJson))
|
||||
return get[APIResponseSentWebAppMessage](a.base, "answerWebAppQuery", vals)
|
||||
return res, a.client.get(a.base, "answerWebAppQuery", vals, &res)
|
||||
}
|
||||
|
||||
2
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
2
vendor/github.com/cespare/xxhash/v2/README.md
generated
vendored
@@ -70,3 +70,5 @@ benchstat <(go test -benchtime 500ms -count 15 -bench 'Sum64$')
|
||||
- [VictoriaMetrics](https://github.com/VictoriaMetrics/VictoriaMetrics)
|
||||
- [FreeCache](https://github.com/coocood/freecache)
|
||||
- [FastCache](https://github.com/VictoriaMetrics/fastcache)
|
||||
- [Ristretto](https://github.com/dgraph-io/ristretto)
|
||||
- [Badger](https://github.com/dgraph-io/badger)
|
||||
|
||||
29
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
29
vendor/github.com/cespare/xxhash/v2/xxhash.go
generated
vendored
@@ -19,10 +19,13 @@ const (
|
||||
// Store the primes in an array as well.
|
||||
//
|
||||
// The consts are used when possible in Go code to avoid MOVs but we need a
|
||||
// contiguous array of the assembly code.
|
||||
// contiguous array for the assembly code.
|
||||
var primes = [...]uint64{prime1, prime2, prime3, prime4, prime5}
|
||||
|
||||
// Digest implements hash.Hash64.
|
||||
//
|
||||
// Note that a zero-valued Digest is not ready to receive writes.
|
||||
// Call Reset or create a Digest using New before calling other methods.
|
||||
type Digest struct {
|
||||
v1 uint64
|
||||
v2 uint64
|
||||
@@ -33,19 +36,31 @@ type Digest struct {
|
||||
n int // how much of mem is used
|
||||
}
|
||||
|
||||
// New creates a new Digest that computes the 64-bit xxHash algorithm.
|
||||
// New creates a new Digest with a zero seed.
|
||||
func New() *Digest {
|
||||
return NewWithSeed(0)
|
||||
}
|
||||
|
||||
// NewWithSeed creates a new Digest with the given seed.
|
||||
func NewWithSeed(seed uint64) *Digest {
|
||||
var d Digest
|
||||
d.Reset()
|
||||
d.ResetWithSeed(seed)
|
||||
return &d
|
||||
}
|
||||
|
||||
// Reset clears the Digest's state so that it can be reused.
|
||||
// It uses a seed value of zero.
|
||||
func (d *Digest) Reset() {
|
||||
d.v1 = primes[0] + prime2
|
||||
d.v2 = prime2
|
||||
d.v3 = 0
|
||||
d.v4 = -primes[0]
|
||||
d.ResetWithSeed(0)
|
||||
}
|
||||
|
||||
// ResetWithSeed clears the Digest's state so that it can be reused.
|
||||
// It uses the given seed to initialize the state.
|
||||
func (d *Digest) ResetWithSeed(seed uint64) {
|
||||
d.v1 = seed + prime1 + prime2
|
||||
d.v2 = seed + prime2
|
||||
d.v3 = seed
|
||||
d.v4 = seed - prime1
|
||||
d.total = 0
|
||||
d.n = 0
|
||||
}
|
||||
|
||||
2
vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
generated
vendored
2
vendor/github.com/cespare/xxhash/v2/xxhash_asm.go
generated
vendored
@@ -6,7 +6,7 @@
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64 computes the 64-bit xxHash digest of b.
|
||||
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||
//
|
||||
//go:noescape
|
||||
func Sum64(b []byte) uint64
|
||||
|
||||
2
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
2
vendor/github.com/cespare/xxhash/v2/xxhash_other.go
generated
vendored
@@ -3,7 +3,7 @@
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64 computes the 64-bit xxHash digest of b.
|
||||
// Sum64 computes the 64-bit xxHash digest of b with a zero seed.
|
||||
func Sum64(b []byte) uint64 {
|
||||
// A simpler version would be
|
||||
// d := New()
|
||||
|
||||
2
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
2
vendor/github.com/cespare/xxhash/v2/xxhash_safe.go
generated
vendored
@@ -5,7 +5,7 @@
|
||||
|
||||
package xxhash
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s.
|
||||
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||
func Sum64String(s string) uint64 {
|
||||
return Sum64([]byte(s))
|
||||
}
|
||||
|
||||
2
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
2
vendor/github.com/cespare/xxhash/v2/xxhash_unsafe.go
generated
vendored
@@ -33,7 +33,7 @@ import (
|
||||
//
|
||||
// See https://github.com/golang/go/issues/42739 for discussion.
|
||||
|
||||
// Sum64String computes the 64-bit xxHash digest of s.
|
||||
// Sum64String computes the 64-bit xxHash digest of s with a zero seed.
|
||||
// It may be faster than Sum64([]byte(s)) by avoiding a copy.
|
||||
func Sum64String(s string) uint64 {
|
||||
b := *(*[]byte)(unsafe.Pointer(&sliceHeader{s, len(s)}))
|
||||
|
||||
2
vendor/github.com/cockroachdb/errors/contexttags/contexttags.go
generated
vendored
2
vendor/github.com/cockroachdb/errors/contexttags/contexttags.go
generated
vendored
@@ -25,7 +25,7 @@ import (
|
||||
// WithContextTags captures the k/v pairs stored in the context via the
|
||||
// `logtags` package and annotates them on the error.
|
||||
//
|
||||
// Only the stromg representation of values remains available. This is
|
||||
// Only the strong representation of values remains available. This is
|
||||
// because the library cannot guarantee that the underlying value is
|
||||
// preserved across the network. To avoid creating a stateful interface
|
||||
// (where the user code needs to know whether an error has traveled
|
||||
|
||||
2
vendor/github.com/cockroachdb/errors/errutil/doc.go
generated
vendored
2
vendor/github.com/cockroachdb/errors/errutil/doc.go
generated
vendored
@@ -14,6 +14,6 @@
|
||||
|
||||
// Package errutil combines primitives from the library, the Go errors
|
||||
// package and github.com/pkg/errors. It aims to serve as drop-in
|
||||
// replacement to gitub.com/pkg/errors and replace the legacy
|
||||
// replacement to github.com/pkg/errors and replace the legacy
|
||||
// implementation of `pgerrors`.
|
||||
package errutil
|
||||
|
||||
7
vendor/github.com/cockroachdb/errors/markers/markers.go
generated
vendored
7
vendor/github.com/cockroachdb/errors/markers/markers.go
generated
vendored
@@ -179,6 +179,13 @@ func IsAny(err error, references ...error) bool {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Recursively try multi-error causes, if applicable.
|
||||
for _, me := range errbase.UnwrapMulti(c) {
|
||||
if IsAny(me, references...) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try harder with marks.
|
||||
|
||||
25
vendor/github.com/cockroachdb/fifo/.gitignore
generated
vendored
Normal file
25
vendor/github.com/cockroachdb/fifo/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work
|
||||
go.work.sum
|
||||
|
||||
.idea/
|
||||
|
||||
201
vendor/github.com/cockroachdb/fifo/LICENSE
generated
vendored
Normal file
201
vendor/github.com/cockroachdb/fifo/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
21
vendor/github.com/cockroachdb/fifo/invariants_off.go
generated
vendored
Normal file
21
vendor/github.com/cockroachdb/fifo/invariants_off.go
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
// implied. See the License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
//go:build !fifo_invariants
|
||||
|
||||
package fifo
|
||||
|
||||
// invariants is false if we were not built with the "fifo_invariants" build
|
||||
// tag.
|
||||
const invariants = false
|
||||
20
vendor/github.com/cockroachdb/fifo/invariants_on.go
generated
vendored
Normal file
20
vendor/github.com/cockroachdb/fifo/invariants_on.go
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
// implied. See the License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
//go:build fifo_invariants
|
||||
|
||||
package fifo
|
||||
|
||||
// invariants is true if we were built with the "fifo_invariants" build tag.
|
||||
const invariants = true
|
||||
162
vendor/github.com/cockroachdb/fifo/queue.go
generated
vendored
Normal file
162
vendor/github.com/cockroachdb/fifo/queue.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
// implied. See the License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
package fifo
|
||||
|
||||
import "sync"
|
||||
|
||||
// Queue implements an allocation efficient FIFO queue. It is not safe for
|
||||
// concurrent access.
|
||||
//
|
||||
// Note that the queue provides pointer access to the internal storage (via
|
||||
// PeekFront and PushBack) so it must be used with care. These pointers must not
|
||||
// be used once the respective element is popped out of the queue.
|
||||
//
|
||||
// -- Implementation --
|
||||
//
|
||||
// The queue is implemented as a linked list of nodes, where each node is a
|
||||
// small ring buffer. The nodes are allocated using a sync.Pool (a single pool
|
||||
// is created for any given type and is used for all queues of that type).
|
||||
type Queue[T any] struct {
|
||||
len int
|
||||
head, tail *queueNode[T]
|
||||
|
||||
pool *QueueBackingPool[T]
|
||||
}
|
||||
|
||||
// MakeQueue constructs a new Queue.
|
||||
//
|
||||
// The pool should be a singleton object initialized with MakeQueueBackingPool.
|
||||
// A single pool can and should be used by all queues of that type.
|
||||
func MakeQueue[T any](pool *QueueBackingPool[T]) Queue[T] {
|
||||
return Queue[T]{
|
||||
pool: pool,
|
||||
}
|
||||
}
|
||||
|
||||
// Len returns the current length of the queue.
|
||||
func (q *Queue[T]) Len() int {
|
||||
return q.len
|
||||
}
|
||||
|
||||
// PushBack adds t to the end of the queue.
|
||||
//
|
||||
// The returned pointer can be used to modify the element while it is in the
|
||||
// queue; it is valid until the element is removed from the queue.
|
||||
func (q *Queue[T]) PushBack(t T) *T {
|
||||
if q.head == nil {
|
||||
q.head = q.pool.get()
|
||||
q.tail = q.head
|
||||
} else if q.tail.IsFull() {
|
||||
newTail := q.pool.get()
|
||||
q.tail.next = newTail
|
||||
q.tail = newTail
|
||||
}
|
||||
q.len++
|
||||
return q.tail.PushBack(t)
|
||||
}
|
||||
|
||||
// PeekFront returns the current head of the queue, or nil if the queue is
|
||||
// empty.
|
||||
//
|
||||
// The result is only valid until the next call to PopFront.
|
||||
func (q *Queue[T]) PeekFront() *T {
|
||||
if q.len == 0 {
|
||||
return nil
|
||||
}
|
||||
return q.head.PeekFront()
|
||||
}
|
||||
|
||||
// PopFront removes the current head of the queue.
|
||||
//
|
||||
// It is illegal to call PopFront on an empty queue.
|
||||
func (q *Queue[T]) PopFront() {
|
||||
q.head.PopFront()
|
||||
// If this is the only node, we don't want to release it; otherwise we would
|
||||
// allocate/free a node every time we transition between the queue being empty
|
||||
// and non-empty.
|
||||
if q.head.len == 0 && q.head.next != nil {
|
||||
oldHead := q.head
|
||||
q.head = oldHead.next
|
||||
q.pool.put(oldHead)
|
||||
}
|
||||
q.len--
|
||||
}
|
||||
|
||||
// QueueBackingPool is a sync.Pool that used to allocate internal nodes
|
||||
// for Queue[T].
|
||||
type QueueBackingPool[T any] struct {
|
||||
pool sync.Pool
|
||||
}
|
||||
|
||||
// MakeQueueBackingPool makes a queue backing pool. It is intented to be used to
|
||||
// initialize a singleton (global) variable. A single pool can and should be
|
||||
// used by all queues of that type.
|
||||
func MakeQueueBackingPool[T any]() QueueBackingPool[T] {
|
||||
return QueueBackingPool[T]{
|
||||
pool: sync.Pool{
|
||||
New: func() interface{} { return &queueNode[T]{} },
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (qp *QueueBackingPool[T]) get() *queueNode[T] {
|
||||
return qp.pool.Get().(*queueNode[T])
|
||||
}
|
||||
|
||||
func (qp *QueueBackingPool[T]) put(n *queueNode[T]) {
|
||||
*n = queueNode[T]{}
|
||||
qp.pool.Put(n)
|
||||
}
|
||||
|
||||
// We batch the allocation of this many queue objects. The value was chosen
|
||||
// without experimentation - it provides a reasonable amount of amortization
|
||||
// without a very large increase in memory overhead if T is large.
|
||||
const queueNodeSize = 8
|
||||
|
||||
type queueNode[T any] struct {
|
||||
buf [queueNodeSize]T
|
||||
head, len int32
|
||||
next *queueNode[T]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) IsFull() bool {
|
||||
return qn.len == queueNodeSize
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PushBack(t T) *T {
|
||||
if invariants && qn.len >= queueNodeSize {
|
||||
panic("cannot push back into a full node")
|
||||
}
|
||||
i := (qn.head + qn.len) % queueNodeSize
|
||||
qn.buf[i] = t
|
||||
qn.len++
|
||||
return &qn.buf[i]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PeekFront() *T {
|
||||
return &qn.buf[qn.head]
|
||||
}
|
||||
|
||||
func (qn *queueNode[T]) PopFront() T {
|
||||
if invariants && qn.len == 0 {
|
||||
panic("cannot pop from empty queue")
|
||||
}
|
||||
t := qn.buf[qn.head]
|
||||
var zero T
|
||||
qn.buf[qn.head] = zero
|
||||
qn.head = (qn.head + 1) % queueNodeSize
|
||||
qn.len--
|
||||
return t
|
||||
}
|
||||
239
vendor/github.com/cockroachdb/fifo/semaphore.go
generated
vendored
Normal file
239
vendor/github.com/cockroachdb/fifo/semaphore.go
generated
vendored
Normal file
@@ -0,0 +1,239 @@
|
||||
// Copyright 2024 The Cockroach Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
// implied. See the License for the specific language governing
|
||||
// permissions and limitations under the License.
|
||||
|
||||
package fifo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// Semaphore implements a weighted, dynamically reconfigurable semaphore which
|
||||
// respects context cancellation.
|
||||
//
|
||||
// The semaphore implements a FIFO policy, where Acquire requests are satisfied
|
||||
// in order. This policy provides fairness and prevents starvation but is
|
||||
// susceptible to head-of-line blocking, where a large request that can't be
|
||||
// satisfied blocks many other small requests that could be.
|
||||
type Semaphore struct {
|
||||
mu struct {
|
||||
sync.Mutex
|
||||
|
||||
capacity int64
|
||||
// outstanding can exceed capacity if the capacity is dynamically decreased.
|
||||
outstanding int64
|
||||
|
||||
waiters Queue[semaWaiter]
|
||||
|
||||
// numCanceled is the number of waiters in the waiters queue which have been
|
||||
// canceled. It is used to determine the current number of active waiters in
|
||||
// the queue which is waiters.Len() minus this value.
|
||||
numCanceled int
|
||||
|
||||
// numHadToWait accumulates the total number of Acquire requests which had
|
||||
// to wait because the semaphore was exhausted.
|
||||
numHadToWait int64
|
||||
}
|
||||
}
|
||||
|
||||
// NewSemaphore creates a new semaphore with the given capacity.
|
||||
func NewSemaphore(capacity int64) *Semaphore {
|
||||
if capacity <= 0 {
|
||||
panic("invalid capacity")
|
||||
}
|
||||
s := &Semaphore{}
|
||||
s.mu.capacity = capacity
|
||||
s.mu.waiters = MakeQueue[semaWaiter](&semaQueuePool)
|
||||
return s
|
||||
}
|
||||
|
||||
var semaQueuePool = MakeQueueBackingPool[semaWaiter]()
|
||||
|
||||
var ErrRequestExceedsCapacity = errors.New("request exceeds semaphore capacity")
|
||||
|
||||
// TryAcquire attempts to acquire n units from the semaphore without waiting. On
|
||||
// success, returns true and the caller must later Release the units.
|
||||
func (s *Semaphore) TryAcquire(n int64) bool {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
if s.numWaitersLocked() == 0 && s.mu.outstanding+n <= s.mu.capacity {
|
||||
s.mu.outstanding += n
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Acquire n units from the semaphore, waiting if necessary.
|
||||
//
|
||||
// If the context is canceled while we are waiting, returns the context error.
|
||||
// If n exceeds the current capacity, returns ErrRequestExceedsCapacity.
|
||||
// On success, the caller must later Release the units.
|
||||
func (s *Semaphore) Acquire(ctx context.Context, n int64) error {
|
||||
s.mu.Lock()
|
||||
|
||||
// Fast path.
|
||||
if s.numWaitersLocked() == 0 && s.mu.outstanding+n <= s.mu.capacity {
|
||||
s.mu.outstanding += n
|
||||
s.mu.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
if n > s.mu.capacity {
|
||||
s.mu.Unlock()
|
||||
return ErrRequestExceedsCapacity
|
||||
}
|
||||
|
||||
c := chanSyncPool.Get().(chan error)
|
||||
defer chanSyncPool.Put(c)
|
||||
w := s.mu.waiters.PushBack(semaWaiter{n: n, c: c})
|
||||
s.mu.numHadToWait++
|
||||
s.mu.Unlock()
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
// We need to check if we raced with a channel notify (which happens under
|
||||
// the lock).
|
||||
select {
|
||||
case err := <-c:
|
||||
// We actually fulfilled or failed the request.
|
||||
return err
|
||||
default:
|
||||
}
|
||||
// Mark the request as canceled.
|
||||
w.c = nil
|
||||
s.mu.numCanceled++
|
||||
// If we are the head of the queue, we may be able to fulfill other waiters.
|
||||
s.processWaitersLocked()
|
||||
return ctx.Err()
|
||||
|
||||
case err := <-c:
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Release n units back. These must be units that were acquired by a previous
|
||||
// Acquire call. It is legal to split up or coalesce units when releasing.
|
||||
func (s *Semaphore) Release(n int64) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
s.mu.outstanding -= n
|
||||
if s.mu.outstanding < 0 {
|
||||
panic("releasing more than was acquired")
|
||||
}
|
||||
s.processWaitersLocked()
|
||||
}
|
||||
|
||||
// UpdateCapacity changes the capacity of the semaphore. If the new capacity is
|
||||
// smaller, the already outstanding acquisitions might exceed the new capacity
|
||||
// until they are released.
|
||||
//
|
||||
// If there are Acquire calls that are waiting which are requesting more than
|
||||
// the new capacity, they will error out with ErrRequestExceedsCapacity.
|
||||
func (s *Semaphore) UpdateCapacity(capacity int64) {
|
||||
if capacity <= 0 {
|
||||
panic("invalid capacity")
|
||||
}
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
s.mu.capacity = capacity
|
||||
s.processWaitersLocked()
|
||||
}
|
||||
|
||||
// Stats returns the current state of the semaphore.
|
||||
func (s *Semaphore) Stats() SemaphoreStats {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return SemaphoreStats{
|
||||
Capacity: s.mu.capacity,
|
||||
Outstanding: s.mu.outstanding,
|
||||
NumHadToWait: s.mu.numHadToWait,
|
||||
}
|
||||
}
|
||||
|
||||
// SemaphoreStats contains information about the current state of the semaphore.
|
||||
type SemaphoreStats struct {
|
||||
// Capacity is the current capacity of the semaphore.
|
||||
Capacity int64
|
||||
// Outstanding is the number of units that have been acquired. Note that this
|
||||
// can exceed Capacity if the capacity was recently decreased.
|
||||
Outstanding int64
|
||||
// NumHadToWait is the total number of Acquire calls (since the semaphore was
|
||||
// created) that had to wait because the semaphore was exhausted. Useful for
|
||||
// cumulative metrics.
|
||||
NumHadToWait int64
|
||||
|
||||
// TODO(radu): consider keeping track of the total amount of time the
|
||||
// semaphore was exhausted (i.e. there were waiters queued).
|
||||
}
|
||||
|
||||
func (ss SemaphoreStats) String() string {
|
||||
return fmt.Sprintf("capacity: %d, outstanding: %d, num-had-to-wait: %d",
|
||||
ss.Capacity, ss.Outstanding, ss.NumHadToWait)
|
||||
}
|
||||
|
||||
type semaWaiter struct {
|
||||
// n is the amount that the waiter is trying to acquire.
|
||||
n int64
|
||||
// c is the channel on which Acquire is blocked. If the request is canceled,
|
||||
// it is set to nil.
|
||||
c chan error
|
||||
}
|
||||
|
||||
// numWaitersLocked returns how many requests (that have not been canceled) are
|
||||
// waiting in the queue.
|
||||
func (s *Semaphore) numWaitersLocked() int {
|
||||
return s.mu.waiters.Len() - s.mu.numCanceled
|
||||
}
|
||||
|
||||
// processWaitersLocked processes and notifies as many waiters from the head of
|
||||
// the queue as possible.
|
||||
func (s *Semaphore) processWaitersLocked() {
|
||||
for ; s.mu.waiters.Len() > 0; s.mu.waiters.PopFront() {
|
||||
switch w := s.mu.waiters.PeekFront(); {
|
||||
case w.c == nil:
|
||||
// Request was canceled, we can just clean it up.
|
||||
s.mu.numCanceled--
|
||||
if invariants && s.mu.numCanceled < 0 {
|
||||
panic("negative numCanceled")
|
||||
}
|
||||
|
||||
case s.mu.outstanding+w.n <= s.mu.capacity:
|
||||
// Request can be fulfilled.
|
||||
s.mu.outstanding += w.n
|
||||
w.c <- nil
|
||||
|
||||
case w.n > s.mu.capacity:
|
||||
// Request must be failed. This can happen if the capacity was decreased
|
||||
// while the element was queued.
|
||||
w.c <- ErrRequestExceedsCapacity
|
||||
|
||||
default:
|
||||
// Head of the queue needs to wait some more.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// chanSyncPool is used to pool allocations of the channels used to notify
|
||||
// goroutines waiting in Acquire.
|
||||
var chanSyncPool = sync.Pool{
|
||||
New: func() interface{} { return make(chan error, 1) },
|
||||
}
|
||||
1
vendor/github.com/cockroachdb/pebble/compaction.go
generated
vendored
1
vendor/github.com/cockroachdb/pebble/compaction.go
generated
vendored
@@ -2142,7 +2142,6 @@ func (d *DB) flush1() (bytesFlushed uint64, err error) {
|
||||
// calculation even when the WAL is disabled.
|
||||
metrics.BytesIn = metrics.BytesFlushed
|
||||
} else {
|
||||
metrics := c.metrics[0]
|
||||
for i := 0; i < n; i++ {
|
||||
metrics.BytesIn += d.mu.mem.queue[i].logSize
|
||||
}
|
||||
|
||||
20
vendor/github.com/cockroachdb/pebble/db.go
generated
vendored
20
vendor/github.com/cockroachdb/pebble/db.go
generated
vendored
@@ -377,7 +377,7 @@ type DB struct {
|
||||
queue []fileInfo
|
||||
// The number of input bytes to the log. This is the raw size of the
|
||||
// batches written to the WAL, without the overhead of the record
|
||||
// envelopes.
|
||||
// envelopes. Requires DB.mu to be held when read or written.
|
||||
bytesIn uint64
|
||||
// The LogWriter is protected by commitPipeline.mu. This allows log
|
||||
// writes to be performed without holding DB.mu, but requires both
|
||||
@@ -2471,7 +2471,7 @@ func (d *DB) makeRoomForWrite(b *Batch) error {
|
||||
var prevLogSize uint64
|
||||
if !d.opts.DisableWAL {
|
||||
now := time.Now()
|
||||
newLogNum, prevLogSize = d.recycleWAL()
|
||||
newLogNum, prevLogSize = d.rotateWAL()
|
||||
if b != nil {
|
||||
b.commitStats.WALRotationDuration += time.Since(now)
|
||||
}
|
||||
@@ -2543,15 +2543,29 @@ func (d *DB) rotateMemtable(newLogNum FileNum, logSeqNum uint64, prev *memTable)
|
||||
var entry *flushableEntry
|
||||
d.mu.mem.mutable, entry = d.newMemTable(newLogNum, logSeqNum)
|
||||
d.mu.mem.queue = append(d.mu.mem.queue, entry)
|
||||
// d.logSize tracks the log size of the WAL file corresponding to the most
|
||||
// recent flushable. The log size of the previous mutable memtable no longer
|
||||
// applies to the current mutable memtable.
|
||||
//
|
||||
// It's tempting to perform this update in rotateWAL, but that would not be
|
||||
// atomic with the enqueue of the new flushable. A call to DB.Metrics()
|
||||
// could acquire DB.mu after the WAL has been rotated but before the new
|
||||
// memtable has been appended; this would result in omitting the log size of
|
||||
// the most recent flushable.
|
||||
d.logSize.Store(0)
|
||||
d.updateReadStateLocked(nil)
|
||||
if prev.writerUnref() {
|
||||
d.maybeScheduleFlush()
|
||||
}
|
||||
}
|
||||
|
||||
// rotateWAL creates a new write-ahead log, possibly recycling a previous WAL's
|
||||
// files. It returns the file number assigned to the new WAL, and the size of
|
||||
// the previous WAL file.
|
||||
//
|
||||
// Both DB.mu and commitPipeline.mu must be held by the caller. Note that DB.mu
|
||||
// may be released and reacquired.
|
||||
func (d *DB) recycleWAL() (newLogNum FileNum, prevLogSize uint64) {
|
||||
func (d *DB) rotateWAL() (newLogNum FileNum, prevLogSize uint64) {
|
||||
if d.opts.DisableWAL {
|
||||
panic("pebble: invalid function call")
|
||||
}
|
||||
|
||||
22
vendor/github.com/cockroachdb/pebble/ingest.go
generated
vendored
22
vendor/github.com/cockroachdb/pebble/ingest.go
generated
vendored
@@ -1223,7 +1223,12 @@ func (d *DB) handleIngestAsFlushable(meta []*fileMetadata, seqNum uint64) error
|
||||
// We create a new WAL for the flushable instead of reusing the end of
|
||||
// the previous WAL. This simplifies the increment of the minimum
|
||||
// unflushed log number, and also simplifies WAL replay.
|
||||
logNum, _ = d.recycleWAL()
|
||||
var prevLogSize uint64
|
||||
logNum, prevLogSize = d.rotateWAL()
|
||||
// As the rotator of the WAL, we're responsible for updating the
|
||||
// previous flushable queue tail's log size.
|
||||
d.mu.mem.queue[len(d.mu.mem.queue)-1].logSize = prevLogSize
|
||||
|
||||
d.mu.Unlock()
|
||||
err := d.commit.directWrite(b)
|
||||
if err != nil {
|
||||
@@ -1243,13 +1248,14 @@ func (d *DB) handleIngestAsFlushable(meta []*fileMetadata, seqNum uint64) error
|
||||
// the appropriate value below.
|
||||
newLogNum := d.mu.mem.queue[len(d.mu.mem.queue)-1].logNum
|
||||
if !d.opts.DisableWAL {
|
||||
// This is WAL num of the next mutable memtable which comes after the
|
||||
// ingestedFlushable in the flushable queue. The mutable memtable
|
||||
// will be created below.
|
||||
newLogNum, _ = d.recycleWAL()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// newLogNum will be the WAL num of the next mutable memtable which
|
||||
// comes after the ingestedFlushable in the flushable queue. The mutable
|
||||
// memtable will be created below.
|
||||
//
|
||||
// The prevLogSize returned by rotateWAL is the WAL to which the
|
||||
// flushable ingest keys were appended. This intermediary WAL is only
|
||||
// used to record the flushable ingest and nothing else.
|
||||
newLogNum, entry.logSize = d.rotateWAL()
|
||||
}
|
||||
|
||||
currMem := d.mu.mem.mutable
|
||||
|
||||
35
vendor/github.com/cockroachdb/pebble/internal/base/iterator.go
generated
vendored
35
vendor/github.com/cockroachdb/pebble/internal/base/iterator.go
generated
vendored
@@ -7,6 +7,9 @@ package base
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/pebble/internal/humanize"
|
||||
"github.com/cockroachdb/redact"
|
||||
)
|
||||
|
||||
// InternalIterator iterates over a DB's key/value pairs in key order. Unlike
|
||||
@@ -407,3 +410,35 @@ func (s *InternalIteratorStats) Merge(from InternalIteratorStats) {
|
||||
s.SeparatedPointValue.ValueBytes += from.SeparatedPointValue.ValueBytes
|
||||
s.SeparatedPointValue.ValueBytesFetched += from.SeparatedPointValue.ValueBytesFetched
|
||||
}
|
||||
|
||||
func (s *InternalIteratorStats) String() string {
|
||||
return redact.StringWithoutMarkers(s)
|
||||
}
|
||||
|
||||
// SafeFormat implements the redact.SafeFormatter interface.
|
||||
func (s *InternalIteratorStats) SafeFormat(p redact.SafePrinter, verb rune) {
|
||||
p.Printf("blocks: %s cached",
|
||||
humanize.Bytes.Uint64(s.BlockBytesInCache),
|
||||
)
|
||||
if s.BlockBytes != s.BlockBytesInCache || s.BlockReadDuration != 0 {
|
||||
p.Printf(", %s not cached (read time: %s)",
|
||||
humanize.Bytes.Uint64(s.BlockBytes-s.BlockBytesInCache),
|
||||
humanize.FormattedString(s.BlockReadDuration.String()),
|
||||
)
|
||||
}
|
||||
p.Printf("; points: %s", humanize.Count.Uint64(s.PointCount))
|
||||
|
||||
if s.PointsCoveredByRangeTombstones != 0 {
|
||||
p.Printf("(%s tombstoned)", humanize.Count.Uint64(s.PointsCoveredByRangeTombstones))
|
||||
}
|
||||
p.Printf(" (%s keys, %s values)",
|
||||
humanize.Bytes.Uint64(s.KeyBytes),
|
||||
humanize.Bytes.Uint64(s.ValueBytes),
|
||||
)
|
||||
if s.SeparatedPointValue.Count != 0 {
|
||||
p.Printf("; separated: %s (%s, %s fetched)",
|
||||
humanize.Count.Uint64(s.SeparatedPointValue.Count),
|
||||
humanize.Bytes.Uint64(s.SeparatedPointValue.ValueBytes),
|
||||
humanize.Bytes.Uint64(s.SeparatedPointValue.ValueBytesFetched))
|
||||
}
|
||||
}
|
||||
|
||||
82
vendor/github.com/cockroachdb/pebble/iterator.go
generated
vendored
82
vendor/github.com/cockroachdb/pebble/iterator.go
generated
vendored
@@ -154,6 +154,18 @@ func (s *RangeKeyIteratorStats) Merge(o RangeKeyIteratorStats) {
|
||||
s.SkippedPoints += o.SkippedPoints
|
||||
}
|
||||
|
||||
func (s *RangeKeyIteratorStats) String() string {
|
||||
return redact.StringWithoutMarkers(s)
|
||||
}
|
||||
|
||||
// SafeFormat implements the redact.SafeFormatter interface.
|
||||
func (s *RangeKeyIteratorStats) SafeFormat(p redact.SafePrinter, verb rune) {
|
||||
p.Printf("range keys: %s, contained points: %s (%s skipped)",
|
||||
humanize.Count.Uint64(uint64(s.Count)),
|
||||
humanize.Count.Uint64(uint64(s.ContainedPoints)),
|
||||
humanize.Count.Uint64(uint64(s.SkippedPoints)))
|
||||
}
|
||||
|
||||
// LazyValue is a lazy value. See the long comment in base.LazyValue.
|
||||
type LazyValue = base.LazyValue
|
||||
|
||||
@@ -2788,44 +2800,44 @@ func (stats *IteratorStats) String() string {
|
||||
|
||||
// SafeFormat implements the redact.SafeFormatter interface.
|
||||
func (stats *IteratorStats) SafeFormat(s redact.SafePrinter, verb rune) {
|
||||
for i := range stats.ForwardStepCount {
|
||||
switch IteratorStatsKind(i) {
|
||||
case InterfaceCall:
|
||||
s.SafeString("(interface (dir, seek, step): ")
|
||||
case InternalIterCall:
|
||||
s.SafeString(", (internal (dir, seek, step): ")
|
||||
}
|
||||
s.Printf("(fwd, %d, %d), (rev, %d, %d))",
|
||||
redact.Safe(stats.ForwardSeekCount[i]), redact.Safe(stats.ForwardStepCount[i]),
|
||||
redact.Safe(stats.ReverseSeekCount[i]), redact.Safe(stats.ReverseStepCount[i]))
|
||||
}
|
||||
if stats.InternalStats != (InternalIteratorStats{}) {
|
||||
s.SafeString(",\n(internal-stats: ")
|
||||
s.Printf("(block-bytes: (total %s, cached %s, read-time %s)), "+
|
||||
"(points: (count %s, key-bytes %s, value-bytes %s, tombstoned %s))",
|
||||
humanize.Bytes.Uint64(stats.InternalStats.BlockBytes),
|
||||
humanize.Bytes.Uint64(stats.InternalStats.BlockBytesInCache),
|
||||
humanize.FormattedString(stats.InternalStats.BlockReadDuration.String()),
|
||||
humanize.Count.Uint64(stats.InternalStats.PointCount),
|
||||
humanize.Bytes.Uint64(stats.InternalStats.KeyBytes),
|
||||
humanize.Bytes.Uint64(stats.InternalStats.ValueBytes),
|
||||
humanize.Count.Uint64(stats.InternalStats.PointsCoveredByRangeTombstones),
|
||||
if stats.ReverseSeekCount[InterfaceCall] == 0 && stats.ReverseSeekCount[InternalIterCall] == 0 {
|
||||
s.Printf("seeked %s times (%s internal)",
|
||||
humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InternalIterCall])),
|
||||
)
|
||||
if stats.InternalStats.SeparatedPointValue.Count != 0 {
|
||||
s.Printf(", (separated: (count %s, bytes %s, fetched %s)))",
|
||||
humanize.Count.Uint64(stats.InternalStats.SeparatedPointValue.Count),
|
||||
humanize.Bytes.Uint64(stats.InternalStats.SeparatedPointValue.ValueBytes),
|
||||
humanize.Bytes.Uint64(stats.InternalStats.SeparatedPointValue.ValueBytesFetched))
|
||||
} else {
|
||||
s.Printf(")")
|
||||
}
|
||||
} else {
|
||||
s.Printf("seeked %s times (%s fwd/%s rev, internal: %s fwd/%s rev)",
|
||||
humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall]+stats.ReverseSeekCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ReverseSeekCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardSeekCount[InternalIterCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ReverseSeekCount[InternalIterCall])),
|
||||
)
|
||||
}
|
||||
s.SafeString("; ")
|
||||
|
||||
if stats.ReverseStepCount[InterfaceCall] == 0 && stats.ReverseStepCount[InternalIterCall] == 0 {
|
||||
s.Printf("stepped %s times (%s internal)",
|
||||
humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardStepCount[InternalIterCall])),
|
||||
)
|
||||
} else {
|
||||
s.Printf("stepped %s times (%s fwd/%s rev, internal: %s fwd/%s rev)",
|
||||
humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall]+stats.ReverseStepCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardStepCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ReverseStepCount[InterfaceCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ForwardStepCount[InternalIterCall])),
|
||||
humanize.Count.Uint64(uint64(stats.ReverseStepCount[InternalIterCall])),
|
||||
)
|
||||
}
|
||||
|
||||
if stats.InternalStats != (InternalIteratorStats{}) {
|
||||
s.SafeString("; ")
|
||||
stats.InternalStats.SafeFormat(s, verb)
|
||||
}
|
||||
if stats.RangeKeyStats != (RangeKeyIteratorStats{}) {
|
||||
s.SafeString(",\n(range-key-stats: ")
|
||||
s.Printf("(count %d), (contained points: (count %d, skipped %d)))",
|
||||
stats.RangeKeyStats.Count,
|
||||
stats.RangeKeyStats.ContainedPoints,
|
||||
stats.RangeKeyStats.SkippedPoints)
|
||||
s.SafeString(", ")
|
||||
stats.RangeKeyStats.SafeFormat(s, verb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
48
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/provider.go
generated
vendored
48
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/provider.go
generated
vendored
@@ -92,6 +92,17 @@ type Settings struct {
|
||||
// out a large chunk of dirty filesystem buffers.
|
||||
BytesPerSync int
|
||||
|
||||
// Local contains fields that are only relevant for files stored on the local
|
||||
// filesystem.
|
||||
Local struct {
|
||||
// TODO(radu): move FSCleaner, NoSyncOnClose, BytesPerSync here.
|
||||
|
||||
// ReadaheadConfigFn is a function used to retrieve the current readahead
|
||||
// mode. This function is run whenever a local object is open for reading.
|
||||
// If it is nil, DefaultReadaheadConfig is used.
|
||||
ReadaheadConfigFn func() ReadaheadConfig
|
||||
}
|
||||
|
||||
// Fields here are set only if the provider is to support remote objects
|
||||
// (experimental).
|
||||
Remote struct {
|
||||
@@ -129,6 +140,43 @@ type Settings struct {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadaheadConfig controls the use of read-ahead.
|
||||
type ReadaheadConfig struct {
|
||||
// Informed is the type of read-ahead for operations that are known to read a
|
||||
// large consecutive chunk of a file.
|
||||
Informed ReadaheadMode
|
||||
|
||||
// Speculative is the type of read-ahead used automatically, when consecutive
|
||||
// reads are detected.
|
||||
Speculative ReadaheadMode
|
||||
}
|
||||
|
||||
// DefaultReadaheadConfig is the readahead config used when ReadaheadConfigFn is
|
||||
// not specified.
|
||||
var DefaultReadaheadConfig = ReadaheadConfig{
|
||||
Informed: FadviseSequential,
|
||||
Speculative: FadviseSequential,
|
||||
}
|
||||
|
||||
// ReadaheadMode indicates the type of read-ahead to use, either for informed
|
||||
// read-ahead (e.g. compactions) or speculative read-ahead.
|
||||
type ReadaheadMode uint8
|
||||
|
||||
const (
|
||||
// NoReadahead disables readahead altogether.
|
||||
NoReadahead ReadaheadMode = iota
|
||||
|
||||
// SysReadahead enables the use of SYS_READAHEAD call to prefetch data.
|
||||
// The prefetch window grows dynamically as consecutive writes are detected.
|
||||
SysReadahead
|
||||
|
||||
// FadviseSequential enables to use of FADV_SEQUENTIAL. For informed
|
||||
// read-ahead, FADV_SEQUENTIAL is used from the beginning. For speculative
|
||||
// read-ahead SYS_READAHEAD is first used until the window reaches the maximum
|
||||
// size, then we siwtch to FADV_SEQUENTIAL.
|
||||
FadviseSequential
|
||||
)
|
||||
|
||||
// DefaultSettings initializes default settings (with no remote storage),
|
||||
// suitable for tests and tools.
|
||||
func DefaultSettings(fs vfs.FS, dirName string) Settings {
|
||||
|
||||
5
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/readahead.go
generated
vendored
5
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/readahead.go
generated
vendored
@@ -4,6 +4,8 @@
|
||||
|
||||
package objstorageprovider
|
||||
|
||||
import "github.com/cockroachdb/pebble/internal/invariants"
|
||||
|
||||
const (
|
||||
// Constants for dynamic readahead of data blocks. Note that the size values
|
||||
// make sense as some multiple of the default block size; and they should
|
||||
@@ -81,6 +83,9 @@ func (rs *readaheadState) recordCacheHit(offset, blockLength int64) {
|
||||
// Returns a size value (greater than 0) that should be prefetched if readahead
|
||||
// would be beneficial.
|
||||
func (rs *readaheadState) maybeReadahead(offset, blockLength int64) int64 {
|
||||
if invariants.Enabled && rs.maxReadaheadSize == 0 {
|
||||
panic("readaheadState not initialized")
|
||||
}
|
||||
currentReadEnd := offset + blockLength
|
||||
if rs.numReads >= minFileReadsForReadahead {
|
||||
// The minimum threshold of sequential reads to justify reading ahead
|
||||
|
||||
6
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/vfs.go
generated
vendored
6
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/vfs.go
generated
vendored
@@ -31,7 +31,11 @@ func (p *provider) vfsOpenForReading(
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
return newFileReadable(file, p.st.FS, filename)
|
||||
readaheadConfig := DefaultReadaheadConfig
|
||||
if f := p.st.Local.ReadaheadConfigFn; f != nil {
|
||||
readaheadConfig = f()
|
||||
}
|
||||
return newFileReadable(file, p.st.FS, readaheadConfig, filename)
|
||||
}
|
||||
|
||||
func (p *provider) vfsCreate(
|
||||
|
||||
64
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/vfs_readable.go
generated
vendored
64
vendor/github.com/cockroachdb/pebble/objstorage/objstorageprovider/vfs_readable.go
generated
vendored
@@ -27,22 +27,26 @@ type fileReadable struct {
|
||||
|
||||
// The following fields are used to possibly open the file again using the
|
||||
// sequential reads option (see vfsReadHandle).
|
||||
filename string
|
||||
fs vfs.FS
|
||||
filename string
|
||||
fs vfs.FS
|
||||
readaheadConfig ReadaheadConfig
|
||||
}
|
||||
|
||||
var _ objstorage.Readable = (*fileReadable)(nil)
|
||||
|
||||
func newFileReadable(file vfs.File, fs vfs.FS, filename string) (*fileReadable, error) {
|
||||
func newFileReadable(
|
||||
file vfs.File, fs vfs.FS, readaheadConfig ReadaheadConfig, filename string,
|
||||
) (*fileReadable, error) {
|
||||
info, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r := &fileReadable{
|
||||
file: file,
|
||||
size: info.Size(),
|
||||
filename: filename,
|
||||
fs: fs,
|
||||
file: file,
|
||||
size: info.Size(),
|
||||
filename: filename,
|
||||
fs: fs,
|
||||
readaheadConfig: readaheadConfig,
|
||||
}
|
||||
invariants.SetFinalizer(r, func(obj interface{}) {
|
||||
if obj.(*fileReadable).file != nil {
|
||||
@@ -76,14 +80,14 @@ func (r *fileReadable) Size() int64 {
|
||||
// NewReadHandle is part of the objstorage.Readable interface.
|
||||
func (r *fileReadable) NewReadHandle(_ context.Context) objstorage.ReadHandle {
|
||||
rh := readHandlePool.Get().(*vfsReadHandle)
|
||||
rh.r = r
|
||||
rh.rs = makeReadaheadState(fileMaxReadaheadSize)
|
||||
rh.init(r)
|
||||
return rh
|
||||
}
|
||||
|
||||
type vfsReadHandle struct {
|
||||
r *fileReadable
|
||||
rs readaheadState
|
||||
r *fileReadable
|
||||
rs readaheadState
|
||||
readaheadMode ReadaheadMode
|
||||
|
||||
// sequentialFile holds a file descriptor to the same underlying File,
|
||||
// except with fadvise(FADV_SEQUENTIAL) called on it to take advantage of
|
||||
@@ -108,6 +112,14 @@ var readHandlePool = sync.Pool{
|
||||
},
|
||||
}
|
||||
|
||||
func (rh *vfsReadHandle) init(r *fileReadable) {
|
||||
*rh = vfsReadHandle{
|
||||
r: r,
|
||||
rs: makeReadaheadState(fileMaxReadaheadSize),
|
||||
readaheadMode: r.readaheadConfig.Speculative,
|
||||
}
|
||||
}
|
||||
|
||||
// Close is part of the objstorage.ReadHandle interface.
|
||||
func (rh *vfsReadHandle) Close() error {
|
||||
var err error
|
||||
@@ -121,14 +133,17 @@ func (rh *vfsReadHandle) Close() error {
|
||||
|
||||
// ReadAt is part of the objstorage.ReadHandle interface.
|
||||
func (rh *vfsReadHandle) ReadAt(_ context.Context, p []byte, offset int64) error {
|
||||
var n int
|
||||
var err error
|
||||
if rh.sequentialFile != nil {
|
||||
// Use OS-level read-ahead.
|
||||
n, err = rh.sequentialFile.ReadAt(p, offset)
|
||||
} else {
|
||||
n, err := rh.sequentialFile.ReadAt(p, offset)
|
||||
if invariants.Enabled && err == nil && n != len(p) {
|
||||
panic("short read")
|
||||
}
|
||||
return err
|
||||
}
|
||||
if rh.readaheadMode != NoReadahead {
|
||||
if readaheadSize := rh.rs.maybeReadahead(offset, int64(len(p))); readaheadSize > 0 {
|
||||
if readaheadSize >= fileMaxReadaheadSize {
|
||||
if rh.readaheadMode == FadviseSequential && readaheadSize >= fileMaxReadaheadSize {
|
||||
// We've reached the maximum readahead size. Beyond this point, rely on
|
||||
// OS-level readahead.
|
||||
rh.switchToOSReadahead()
|
||||
@@ -136,8 +151,8 @@ func (rh *vfsReadHandle) ReadAt(_ context.Context, p []byte, offset int64) error
|
||||
_ = rh.r.file.Prefetch(offset, readaheadSize)
|
||||
}
|
||||
}
|
||||
n, err = rh.r.file.ReadAt(p, offset)
|
||||
}
|
||||
n, err := rh.r.file.ReadAt(p, offset)
|
||||
if invariants.Enabled && err == nil && n != len(p) {
|
||||
panic("short read")
|
||||
}
|
||||
@@ -146,10 +161,16 @@ func (rh *vfsReadHandle) ReadAt(_ context.Context, p []byte, offset int64) error
|
||||
|
||||
// SetupForCompaction is part of the objstorage.ReadHandle interface.
|
||||
func (rh *vfsReadHandle) SetupForCompaction() {
|
||||
rh.switchToOSReadahead()
|
||||
rh.readaheadMode = rh.r.readaheadConfig.Informed
|
||||
if rh.readaheadMode == FadviseSequential {
|
||||
rh.switchToOSReadahead()
|
||||
}
|
||||
}
|
||||
|
||||
func (rh *vfsReadHandle) switchToOSReadahead() {
|
||||
if invariants.Enabled && rh.readaheadMode != FadviseSequential {
|
||||
panic("readheadMode not respected")
|
||||
}
|
||||
if rh.sequentialFile != nil {
|
||||
return
|
||||
}
|
||||
@@ -164,8 +185,8 @@ func (rh *vfsReadHandle) switchToOSReadahead() {
|
||||
|
||||
// RecordCacheHit is part of the objstorage.ReadHandle interface.
|
||||
func (rh *vfsReadHandle) RecordCacheHit(_ context.Context, offset, size int64) {
|
||||
if rh.sequentialFile != nil {
|
||||
// Using OS-level readahead, so do nothing.
|
||||
if rh.sequentialFile != nil || rh.readaheadMode == NoReadahead {
|
||||
// Using OS-level or no readahead, so do nothing.
|
||||
return
|
||||
}
|
||||
rh.rs.recordCacheHit(offset, size)
|
||||
@@ -208,8 +229,7 @@ func UsePreallocatedReadHandle(
|
||||
ctx context.Context, readable objstorage.Readable, rh *PreallocatedReadHandle,
|
||||
) objstorage.ReadHandle {
|
||||
if r, ok := readable.(*fileReadable); ok {
|
||||
// See fileReadable.NewReadHandle.
|
||||
rh.vfsReadHandle = vfsReadHandle{r: r}
|
||||
rh.init(r)
|
||||
return rh
|
||||
}
|
||||
return readable.NewReadHandle(ctx)
|
||||
|
||||
1
vendor/github.com/cockroachdb/pebble/open.go
generated
vendored
1
vendor/github.com/cockroachdb/pebble/open.go
generated
vendored
@@ -310,6 +310,7 @@ func Open(dirname string, opts *Options) (db *DB, _ error) {
|
||||
NoSyncOnClose: opts.NoSyncOnClose,
|
||||
BytesPerSync: opts.BytesPerSync,
|
||||
}
|
||||
providerSettings.Local.ReadaheadConfigFn = opts.Local.ReadaheadConfigFn
|
||||
providerSettings.Remote.StorageFactory = opts.Experimental.RemoteStorage
|
||||
providerSettings.Remote.CreateOnShared = opts.Experimental.CreateOnShared
|
||||
providerSettings.Remote.CreateOnSharedLocator = opts.Experimental.CreateOnSharedLocator
|
||||
|
||||
20
vendor/github.com/cockroachdb/pebble/options.go
generated
vendored
20
vendor/github.com/cockroachdb/pebble/options.go
generated
vendored
@@ -14,11 +14,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cockroachdb/errors"
|
||||
"github.com/cockroachdb/fifo"
|
||||
"github.com/cockroachdb/pebble/internal/base"
|
||||
"github.com/cockroachdb/pebble/internal/cache"
|
||||
"github.com/cockroachdb/pebble/internal/humanize"
|
||||
"github.com/cockroachdb/pebble/internal/keyspan"
|
||||
"github.com/cockroachdb/pebble/internal/manifest"
|
||||
"github.com/cockroachdb/pebble/objstorage/objstorageprovider"
|
||||
"github.com/cockroachdb/pebble/objstorage/remote"
|
||||
"github.com/cockroachdb/pebble/rangekey"
|
||||
"github.com/cockroachdb/pebble/sstable"
|
||||
@@ -481,11 +483,25 @@ type Options struct {
|
||||
// The default cache size is 8 MB.
|
||||
Cache *cache.Cache
|
||||
|
||||
// LoadBlockSema, if set, is used to limit the number of blocks that can be
|
||||
// loaded (i.e. read from the filesystem) in parallel. Each load acquires one
|
||||
// unit from the semaphore for the duration of the read.
|
||||
LoadBlockSema *fifo.Semaphore
|
||||
|
||||
// Cleaner cleans obsolete files.
|
||||
//
|
||||
// The default cleaner uses the DeleteCleaner.
|
||||
Cleaner Cleaner
|
||||
|
||||
// Local contains option that pertain to files stored on the local filesystem.
|
||||
Local struct {
|
||||
// ReadaheadConfigFn is a function used to retrieve the current readahead
|
||||
// mode. This function is consulted when a table enters the table cache.
|
||||
ReadaheadConfigFn func() ReadaheadConfig
|
||||
|
||||
// TODO(radu): move BytesPerSync, LoadBlockSema, Cleaner here.
|
||||
}
|
||||
|
||||
// Comparer defines a total ordering over the space of []byte keys: a 'less
|
||||
// than' relationship. The same comparison algorithm must be used for reads
|
||||
// and writes over the lifetime of the DB.
|
||||
@@ -996,6 +1012,9 @@ type Options struct {
|
||||
}
|
||||
}
|
||||
|
||||
// ReadaheadConfig controls the use of read-ahead.
|
||||
type ReadaheadConfig = objstorageprovider.ReadaheadConfig
|
||||
|
||||
// DebugCheckLevels calls CheckLevels on the provided database.
|
||||
// It may be set in the DebugCheck field of Options to check
|
||||
// level invariants whenever a new version is installed.
|
||||
@@ -1713,6 +1732,7 @@ func (o *Options) MakeReaderOptions() sstable.ReaderOptions {
|
||||
var readerOpts sstable.ReaderOptions
|
||||
if o != nil {
|
||||
readerOpts.Cache = o.Cache
|
||||
readerOpts.LoadBlockSema = o.LoadBlockSema
|
||||
readerOpts.Comparer = o.Comparer
|
||||
readerOpts.Filters = o.Filters
|
||||
if o.Merger != nil {
|
||||
|
||||
6
vendor/github.com/cockroachdb/pebble/sstable/options.go
generated
vendored
6
vendor/github.com/cockroachdb/pebble/sstable/options.go
generated
vendored
@@ -5,6 +5,7 @@
|
||||
package sstable
|
||||
|
||||
import (
|
||||
"github.com/cockroachdb/fifo"
|
||||
"github.com/cockroachdb/pebble/internal/base"
|
||||
"github.com/cockroachdb/pebble/internal/cache"
|
||||
)
|
||||
@@ -111,6 +112,11 @@ type ReaderOptions struct {
|
||||
// The default cache size is a zero-size cache.
|
||||
Cache *cache.Cache
|
||||
|
||||
// LoadBlockSema, if set, is used to limit the number of blocks that can be
|
||||
// loaded (i.e. read from the filesystem) in parallel. Each load acquires one
|
||||
// unit from the semaphore for the duration of the read.
|
||||
LoadBlockSema *fifo.Semaphore
|
||||
|
||||
// User properties specified in this map will not be added to sst.Properties.UserProperties.
|
||||
DeniedUserProperties map[string]struct{}
|
||||
|
||||
|
||||
13
vendor/github.com/cockroachdb/pebble/sstable/reader.go
generated
vendored
13
vendor/github.com/cockroachdb/pebble/sstable/reader.go
generated
vendored
@@ -539,6 +539,15 @@ func (r *Reader) readBlock(
|
||||
}
|
||||
|
||||
// Cache miss.
|
||||
|
||||
if sema := r.opts.LoadBlockSema; sema != nil {
|
||||
if err := sema.Acquire(ctx, 1); err != nil {
|
||||
// An error here can only come from the context.
|
||||
return bufferHandle{}, err
|
||||
}
|
||||
defer sema.Release(1)
|
||||
}
|
||||
|
||||
var compressed cacheValueOrBuf
|
||||
if bufferPool != nil {
|
||||
compressed = cacheValueOrBuf{
|
||||
@@ -571,6 +580,7 @@ func (r *Reader) readBlock(
|
||||
int(bh.Length+blockTrailerLen), readDuration.String())
|
||||
}
|
||||
if stats != nil {
|
||||
stats.BlockBytes += bh.Length
|
||||
stats.BlockReadDuration += readDuration
|
||||
}
|
||||
if err != nil {
|
||||
@@ -628,9 +638,6 @@ func (r *Reader) readBlock(
|
||||
decompressed = transformed
|
||||
}
|
||||
|
||||
if stats != nil {
|
||||
stats.BlockBytes += bh.Length
|
||||
}
|
||||
if decompressed.buf.Valid() {
|
||||
return bufferHandle{b: decompressed.buf}, nil
|
||||
}
|
||||
|
||||
3
vendor/github.com/cockroachdb/pebble/sstable/reader_iter_two_lvl.go
generated
vendored
3
vendor/github.com/cockroachdb/pebble/sstable/reader_iter_two_lvl.go
generated
vendored
@@ -9,6 +9,7 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cockroachdb/pebble/internal/base"
|
||||
"github.com/cockroachdb/pebble/objstorage/objstorageprovider"
|
||||
"github.com/cockroachdb/pebble/objstorage/objstorageprovider/objiotracing"
|
||||
)
|
||||
|
||||
@@ -177,7 +178,7 @@ func (i *twoLevelIterator) init(
|
||||
_ = i.topLevelIndex.Close()
|
||||
return err
|
||||
}
|
||||
i.dataRH = r.readable.NewReadHandle(ctx)
|
||||
i.dataRH = objstorageprovider.UsePreallocatedReadHandle(ctx, r.readable, &i.dataRHPrealloc)
|
||||
if r.tableFormat >= TableFormatPebblev3 {
|
||||
if r.Properties.NumValueBlocks > 0 {
|
||||
i.vbReader = &valueBlockReader{
|
||||
|
||||
11
vendor/github.com/cockroachdb/pebble/vfs/logging_fs.go
generated
vendored
11
vendor/github.com/cockroachdb/pebble/vfs/logging_fs.go
generated
vendored
@@ -5,6 +5,7 @@
|
||||
package vfs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
@@ -38,7 +39,15 @@ func (fs *loggingFS) Create(name string) (File, error) {
|
||||
}
|
||||
|
||||
func (fs *loggingFS) Open(name string, opts ...OpenOption) (File, error) {
|
||||
fs.logFn("open: %s", name)
|
||||
var optsStr string
|
||||
if len(opts) > 0 {
|
||||
optsStr = " (options:"
|
||||
for i := range opts {
|
||||
optsStr += fmt.Sprintf(" %T", opts[i])
|
||||
}
|
||||
optsStr += ")"
|
||||
}
|
||||
fs.logFn("open: %s%s", name, optsStr)
|
||||
f, err := fs.FS.Open(name, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
29
vendor/github.com/getsentry/sentry-go/CHANGELOG.md
generated
vendored
29
vendor/github.com/getsentry/sentry-go/CHANGELOG.md
generated
vendored
@@ -1,5 +1,34 @@
|
||||
# Changelog
|
||||
|
||||
## 0.28.1
|
||||
|
||||
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.1.
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Implement `http.ResponseWriter` to hook into various parts of the response process ([#837](https://github.com/getsentry/sentry-go/pull/837))
|
||||
|
||||
## 0.28.0
|
||||
|
||||
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.28.0.
|
||||
|
||||
### Features
|
||||
|
||||
- Add a `Fiber` performance tracing & error reporting integration ([#795](https://github.com/getsentry/sentry-go/pull/795))
|
||||
- Add performance tracing to the `Echo` integration ([#722](https://github.com/getsentry/sentry-go/pull/722))
|
||||
- Add performance tracing to the `FastHTTP` integration ([#732](https://github.com/getsentry/sentry-go/pull/723))
|
||||
- Add performance tracing to the `Iris` integration ([#809](https://github.com/getsentry/sentry-go/pull/809))
|
||||
- Add performance tracing to the `Negroni` integration ([#808](https://github.com/getsentry/sentry-go/pull/808))
|
||||
- Add `FailureIssueThreshold` & `RecoveryThreshold` to `MonitorConfig` ([#775](https://github.com/getsentry/sentry-go/pull/775))
|
||||
- Use `errors.Unwrap()` to create exception groups ([#792](https://github.com/getsentry/sentry-go/pull/792))
|
||||
- Add support for matching on strings for `ClientOptions.IgnoreErrors` & `ClientOptions.IgnoreTransactions` ([#819](https://github.com/getsentry/sentry-go/pull/819))
|
||||
- Add `http.request.method` attribute for performance span data ([#786](https://github.com/getsentry/sentry-go/pull/786))
|
||||
- Accept `interface{}` for span data values ([#784](https://github.com/getsentry/sentry-go/pull/784))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
- Fix missing stack trace for parsing error in `logrusentry` ([#689](https://github.com/getsentry/sentry-go/pull/689))
|
||||
|
||||
## 0.27.0
|
||||
|
||||
The Sentry SDK team is happy to announce the immediate availability of Sentry Go SDK v0.27.0.
|
||||
|
||||
2
vendor/github.com/getsentry/sentry-go/README.md
generated
vendored
2
vendor/github.com/getsentry/sentry-go/README.md
generated
vendored
@@ -13,7 +13,6 @@
|
||||
[](https://github.com/getsentry/sentry-go/actions?query=workflow%3Ago-workflow)
|
||||
[](https://goreportcard.com/report/github.com/getsentry/sentry-go)
|
||||
[](https://discord.gg/Ww9hbqr)
|
||||
[](https://godoc.org/github.com/getsentry/sentry-go)
|
||||
[](https://pkg.go.dev/github.com/getsentry/sentry-go)
|
||||
|
||||
`sentry-go` provides a Sentry client implementation for the Go programming
|
||||
@@ -85,7 +84,6 @@ checkout the official documentation:
|
||||
|
||||
- [Bug Tracker](https://github.com/getsentry/sentry-go/issues)
|
||||
- [GitHub Project](https://github.com/getsentry/sentry-go)
|
||||
- [](https://godoc.org/github.com/getsentry/sentry-go)
|
||||
- [](https://pkg.go.dev/github.com/getsentry/sentry-go)
|
||||
- [](https://docs.sentry.io/platforms/go/)
|
||||
- [](https://github.com/getsentry/sentry-go/discussions)
|
||||
|
||||
4
vendor/github.com/getsentry/sentry-go/check_in.go
generated
vendored
4
vendor/github.com/getsentry/sentry-go/check_in.go
generated
vendored
@@ -87,6 +87,10 @@ type MonitorConfig struct { //nolint: maligned // prefer readability over optima
|
||||
// A tz database string representing the timezone which the monitor's execution schedule is in.
|
||||
// See: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
|
||||
Timezone string `json:"timezone,omitempty"`
|
||||
// The number of consecutive failed check-ins it takes before an issue is created.
|
||||
FailureIssueThreshold int64 `json:"failure_issue_threshold,omitempty"`
|
||||
// The number of consecutive OK check-ins it takes before an issue is resolved.
|
||||
RecoveryThreshold int64 `json:"recovery_threshold,omitempty"`
|
||||
}
|
||||
|
||||
type CheckIn struct { //nolint: maligned // prefer readability over optimal memory layout
|
||||
|
||||
3
vendor/github.com/getsentry/sentry-go/dsn.go
generated
vendored
3
vendor/github.com/getsentry/sentry-go/dsn.go
generated
vendored
@@ -90,11 +90,10 @@ func NewDsn(rawURL string) (*Dsn, error) {
|
||||
// Port
|
||||
var port int
|
||||
if parsedURL.Port() != "" {
|
||||
parsedPort, err := strconv.Atoi(parsedURL.Port())
|
||||
port, err = strconv.Atoi(parsedURL.Port())
|
||||
if err != nil {
|
||||
return nil, &DsnParseError{"invalid port"}
|
||||
}
|
||||
port = parsedPort
|
||||
} else {
|
||||
port = scheme.defaultPort()
|
||||
}
|
||||
|
||||
4
vendor/github.com/getsentry/sentry-go/integrations.go
generated
vendored
4
vendor/github.com/getsentry/sentry-go/integrations.go
generated
vendored
@@ -140,7 +140,7 @@ func (iei *ignoreErrorsIntegration) processor(event *Event, _ *EventHint) *Event
|
||||
|
||||
for _, suspect := range suspects {
|
||||
for _, pattern := range iei.ignoreErrors {
|
||||
if pattern.Match([]byte(suspect)) {
|
||||
if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) {
|
||||
Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+
|
||||
"| Value matched: %s | Filter used: %s", suspect, pattern)
|
||||
return nil
|
||||
@@ -202,7 +202,7 @@ func (iei *ignoreTransactionsIntegration) processor(event *Event, _ *EventHint)
|
||||
}
|
||||
|
||||
for _, pattern := range iei.ignoreTransactions {
|
||||
if pattern.Match([]byte(suspect)) {
|
||||
if pattern.Match([]byte(suspect)) || strings.Contains(suspect, pattern.String()) {
|
||||
Logger.Printf("Transaction dropped due to being matched by `IgnoreTransactions` option."+
|
||||
"| Value matched: %s | Filter used: %s", suspect, pattern)
|
||||
return nil
|
||||
|
||||
92
vendor/github.com/getsentry/sentry-go/interfaces.go
generated
vendored
92
vendor/github.com/getsentry/sentry-go/interfaces.go
generated
vendored
@@ -3,6 +3,7 @@ package sentry
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
@@ -24,6 +25,9 @@ const profileType = "profile"
|
||||
// checkInType is the type of a check in event.
|
||||
const checkInType = "check_in"
|
||||
|
||||
// metricType is the type of a metric event.
|
||||
const metricType = "statsd"
|
||||
|
||||
// Level marks the severity of the event.
|
||||
type Level string
|
||||
|
||||
@@ -36,15 +40,6 @@ const (
|
||||
LevelFatal Level = "fatal"
|
||||
)
|
||||
|
||||
func getSensitiveHeaders() map[string]bool {
|
||||
return map[string]bool{
|
||||
"Authorization": true,
|
||||
"Cookie": true,
|
||||
"X-Forwarded-For": true,
|
||||
"X-Real-Ip": true,
|
||||
}
|
||||
}
|
||||
|
||||
// SdkInfo contains all metadata about about the SDK being used.
|
||||
type SdkInfo struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
@@ -170,6 +165,13 @@ type Request struct {
|
||||
Env map[string]string `json:"env,omitempty"`
|
||||
}
|
||||
|
||||
var sensitiveHeaders = map[string]struct{}{
|
||||
"Authorization": {},
|
||||
"Cookie": {},
|
||||
"X-Forwarded-For": {},
|
||||
"X-Real-Ip": {},
|
||||
}
|
||||
|
||||
// NewRequest returns a new Sentry Request from the given http.Request.
|
||||
//
|
||||
// NewRequest avoids operations that depend on network access. In particular, it
|
||||
@@ -200,7 +202,6 @@ func NewRequest(r *http.Request) *Request {
|
||||
env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
|
||||
}
|
||||
} else {
|
||||
sensitiveHeaders := getSensitiveHeaders()
|
||||
for k, v := range r.Header {
|
||||
if _, ok := sensitiveHeaders[k]; !ok {
|
||||
headers[k] = strings.Join(v, ",")
|
||||
@@ -222,11 +223,15 @@ func NewRequest(r *http.Request) *Request {
|
||||
|
||||
// Mechanism is the mechanism by which an exception was generated and handled.
|
||||
type Mechanism struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
HelpLink string `json:"help_link,omitempty"`
|
||||
Handled *bool `json:"handled,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
HelpLink string `json:"help_link,omitempty"`
|
||||
Source string `json:"source,omitempty"`
|
||||
Handled *bool `json:"handled,omitempty"`
|
||||
ParentID *int `json:"parent_id,omitempty"`
|
||||
ExceptionID int `json:"exception_id"`
|
||||
IsExceptionGroup bool `json:"is_exception_group,omitempty"`
|
||||
Data map[string]any `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
// SetUnhandled indicates that the exception is an unhandled exception, i.e.
|
||||
@@ -318,6 +323,7 @@ type Event struct {
|
||||
Exception []Exception `json:"exception,omitempty"`
|
||||
DebugMeta *DebugMeta `json:"debug_meta,omitempty"`
|
||||
Attachments []*Attachment `json:"-"`
|
||||
Metrics []Metric `json:"-"`
|
||||
|
||||
// The fields below are only relevant for transactions.
|
||||
|
||||
@@ -339,27 +345,43 @@ type Event struct {
|
||||
// SetException appends the unwrapped errors to the event's exception list.
|
||||
//
|
||||
// maxErrorDepth is the maximum depth of the error chain we will look
|
||||
// into while unwrapping the errors.
|
||||
// into while unwrapping the errors. If maxErrorDepth is -1, we will
|
||||
// unwrap all errors in the chain.
|
||||
func (e *Event) SetException(exception error, maxErrorDepth int) {
|
||||
err := exception
|
||||
if err == nil {
|
||||
if exception == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for i := 0; i < maxErrorDepth && err != nil; i++ {
|
||||
err := exception
|
||||
|
||||
for i := 0; err != nil && (i < maxErrorDepth || maxErrorDepth == -1); i++ {
|
||||
// Add the current error to the exception slice with its details
|
||||
e.Exception = append(e.Exception, Exception{
|
||||
Value: err.Error(),
|
||||
Type: reflect.TypeOf(err).String(),
|
||||
Stacktrace: ExtractStacktrace(err),
|
||||
})
|
||||
switch previous := err.(type) {
|
||||
case interface{ Unwrap() error }:
|
||||
err = previous.Unwrap()
|
||||
case interface{ Cause() error }:
|
||||
err = previous.Cause()
|
||||
default:
|
||||
err = nil
|
||||
|
||||
// Attempt to unwrap the error using the standard library's Unwrap method.
|
||||
// If errors.Unwrap returns nil, it means either there is no error to unwrap,
|
||||
// or the error does not implement the Unwrap method.
|
||||
unwrappedErr := errors.Unwrap(err)
|
||||
|
||||
if unwrappedErr != nil {
|
||||
// The error was successfully unwrapped using the standard library's Unwrap method.
|
||||
err = unwrappedErr
|
||||
continue
|
||||
}
|
||||
|
||||
cause, ok := err.(interface{ Cause() error })
|
||||
if !ok {
|
||||
// We cannot unwrap the error further.
|
||||
break
|
||||
}
|
||||
|
||||
// The error implements the Cause method, indicating it may have been wrapped
|
||||
// using the github.com/pkg/errors package.
|
||||
err = cause.Cause()
|
||||
}
|
||||
|
||||
// Add a trace of the current stack to the most recent error in a chain if
|
||||
@@ -370,8 +392,23 @@ func (e *Event) SetException(exception error, maxErrorDepth int) {
|
||||
e.Exception[0].Stacktrace = NewStacktrace()
|
||||
}
|
||||
|
||||
if len(e.Exception) <= 1 {
|
||||
return
|
||||
}
|
||||
|
||||
// event.Exception should be sorted such that the most recent error is last.
|
||||
reverse(e.Exception)
|
||||
|
||||
for i := range e.Exception {
|
||||
e.Exception[i].Mechanism = &Mechanism{
|
||||
IsExceptionGroup: true,
|
||||
ExceptionID: i,
|
||||
}
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
e.Exception[i].Mechanism.ParentID = Pointer(i - 1)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Event.Contexts map[string]interface{} => map[string]EventContext,
|
||||
@@ -492,13 +529,12 @@ func (e *Event) checkInMarshalJSON() ([]byte, error) {
|
||||
|
||||
// NewEvent creates a new Event.
|
||||
func NewEvent() *Event {
|
||||
event := Event{
|
||||
return &Event{
|
||||
Contexts: make(map[string]Context),
|
||||
Extra: make(map[string]interface{}),
|
||||
Tags: make(map[string]string),
|
||||
Modules: make(map[string]string),
|
||||
}
|
||||
return &event
|
||||
}
|
||||
|
||||
// Thread specifies threads that were running at the time of an event.
|
||||
|
||||
17
vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go
generated
vendored
17
vendor/github.com/getsentry/sentry-go/internal/ratelimit/category.go
generated
vendored
@@ -32,15 +32,14 @@ var knownCategories = map[Category]struct{}{
|
||||
|
||||
// String returns the category formatted for debugging.
|
||||
func (c Category) String() string {
|
||||
switch c {
|
||||
case "":
|
||||
if c == "" {
|
||||
return "CategoryAll"
|
||||
default:
|
||||
caser := cases.Title(language.English)
|
||||
rv := "Category"
|
||||
for _, w := range strings.Fields(string(c)) {
|
||||
rv += caser.String(w)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
caser := cases.Title(language.English)
|
||||
rv := "Category"
|
||||
for _, w := range strings.Fields(string(c)) {
|
||||
rv += caser.String(w)
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
427
vendor/github.com/getsentry/sentry-go/metrics.go
generated
vendored
Normal file
427
vendor/github.com/getsentry/sentry-go/metrics.go
generated
vendored
Normal file
@@ -0,0 +1,427 @@
|
||||
package sentry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hash/crc32"
|
||||
"math"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type (
|
||||
NumberOrString interface {
|
||||
int | string
|
||||
}
|
||||
|
||||
void struct{}
|
||||
)
|
||||
|
||||
var (
|
||||
member void
|
||||
keyRegex = regexp.MustCompile(`[^a-zA-Z0-9_/.-]+`)
|
||||
valueRegex = regexp.MustCompile(`[^\w\d\s_:/@\.{}\[\]$-]+`)
|
||||
unitRegex = regexp.MustCompile(`[^a-z]+`)
|
||||
)
|
||||
|
||||
type MetricUnit struct {
|
||||
unit string
|
||||
}
|
||||
|
||||
func (m MetricUnit) toString() string {
|
||||
return m.unit
|
||||
}
|
||||
|
||||
func NanoSecond() MetricUnit {
|
||||
return MetricUnit{
|
||||
"nanosecond",
|
||||
}
|
||||
}
|
||||
|
||||
func MicroSecond() MetricUnit {
|
||||
return MetricUnit{
|
||||
"microsecond",
|
||||
}
|
||||
}
|
||||
|
||||
func MilliSecond() MetricUnit {
|
||||
return MetricUnit{
|
||||
"millisecond",
|
||||
}
|
||||
}
|
||||
|
||||
func Second() MetricUnit {
|
||||
return MetricUnit{
|
||||
"second",
|
||||
}
|
||||
}
|
||||
|
||||
func Minute() MetricUnit {
|
||||
return MetricUnit{
|
||||
"minute",
|
||||
}
|
||||
}
|
||||
|
||||
func Hour() MetricUnit {
|
||||
return MetricUnit{
|
||||
"hour",
|
||||
}
|
||||
}
|
||||
|
||||
func Day() MetricUnit {
|
||||
return MetricUnit{
|
||||
"day",
|
||||
}
|
||||
}
|
||||
|
||||
func Week() MetricUnit {
|
||||
return MetricUnit{
|
||||
"week",
|
||||
}
|
||||
}
|
||||
|
||||
func Bit() MetricUnit {
|
||||
return MetricUnit{
|
||||
"bit",
|
||||
}
|
||||
}
|
||||
|
||||
func Byte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"byte",
|
||||
}
|
||||
}
|
||||
|
||||
func KiloByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"kilobyte",
|
||||
}
|
||||
}
|
||||
|
||||
func KibiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"kibibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func MegaByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"megabyte",
|
||||
}
|
||||
}
|
||||
|
||||
func MebiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"mebibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func GigaByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"gigabyte",
|
||||
}
|
||||
}
|
||||
|
||||
func GibiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"gibibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func TeraByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"terabyte",
|
||||
}
|
||||
}
|
||||
|
||||
func TebiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"tebibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func PetaByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"petabyte",
|
||||
}
|
||||
}
|
||||
|
||||
func PebiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"pebibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func ExaByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"exabyte",
|
||||
}
|
||||
}
|
||||
|
||||
func ExbiByte() MetricUnit {
|
||||
return MetricUnit{
|
||||
"exbibyte",
|
||||
}
|
||||
}
|
||||
|
||||
func Ratio() MetricUnit {
|
||||
return MetricUnit{
|
||||
"ratio",
|
||||
}
|
||||
}
|
||||
|
||||
func Percent() MetricUnit {
|
||||
return MetricUnit{
|
||||
"percent",
|
||||
}
|
||||
}
|
||||
|
||||
func CustomUnit(unit string) MetricUnit {
|
||||
return MetricUnit{
|
||||
unitRegex.ReplaceAllString(unit, ""),
|
||||
}
|
||||
}
|
||||
|
||||
type Metric interface {
|
||||
GetType() string
|
||||
GetTags() map[string]string
|
||||
GetKey() string
|
||||
GetUnit() string
|
||||
GetTimestamp() int64
|
||||
SerializeValue() string
|
||||
SerializeTags() string
|
||||
}
|
||||
|
||||
type abstractMetric struct {
|
||||
key string
|
||||
unit MetricUnit
|
||||
tags map[string]string
|
||||
// A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
|
||||
timestamp int64
|
||||
}
|
||||
|
||||
func (am abstractMetric) GetTags() map[string]string {
|
||||
return am.tags
|
||||
}
|
||||
|
||||
func (am abstractMetric) GetKey() string {
|
||||
return am.key
|
||||
}
|
||||
|
||||
func (am abstractMetric) GetUnit() string {
|
||||
return am.unit.toString()
|
||||
}
|
||||
|
||||
func (am abstractMetric) GetTimestamp() int64 {
|
||||
return am.timestamp
|
||||
}
|
||||
|
||||
func (am abstractMetric) SerializeTags() string {
|
||||
var sb strings.Builder
|
||||
|
||||
values := make([]string, 0, len(am.tags))
|
||||
for k := range am.tags {
|
||||
values = append(values, k)
|
||||
}
|
||||
sortSlice(values)
|
||||
|
||||
for _, key := range values {
|
||||
val := sanitizeValue(am.tags[key])
|
||||
key = sanitizeKey(key)
|
||||
sb.WriteString(fmt.Sprintf("%s:%s,", key, val))
|
||||
}
|
||||
s := sb.String()
|
||||
if len(s) > 0 {
|
||||
s = s[:len(s)-1]
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// Counter Metric.
|
||||
type CounterMetric struct {
|
||||
value float64
|
||||
abstractMetric
|
||||
}
|
||||
|
||||
func (c *CounterMetric) Add(value float64) {
|
||||
c.value += value
|
||||
}
|
||||
|
||||
func (c CounterMetric) GetType() string {
|
||||
return "c"
|
||||
}
|
||||
|
||||
func (c CounterMetric) SerializeValue() string {
|
||||
return fmt.Sprintf(":%v", c.value)
|
||||
}
|
||||
|
||||
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
|
||||
func NewCounterMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) CounterMetric {
|
||||
am := abstractMetric{
|
||||
key,
|
||||
unit,
|
||||
tags,
|
||||
timestamp,
|
||||
}
|
||||
|
||||
return CounterMetric{
|
||||
value,
|
||||
am,
|
||||
}
|
||||
}
|
||||
|
||||
// Distribution Metric.
|
||||
type DistributionMetric struct {
|
||||
values []float64
|
||||
abstractMetric
|
||||
}
|
||||
|
||||
func (d *DistributionMetric) Add(value float64) {
|
||||
d.values = append(d.values, value)
|
||||
}
|
||||
|
||||
func (d DistributionMetric) GetType() string {
|
||||
return "d"
|
||||
}
|
||||
|
||||
func (d DistributionMetric) SerializeValue() string {
|
||||
var sb strings.Builder
|
||||
for _, el := range d.values {
|
||||
sb.WriteString(fmt.Sprintf(":%v", el))
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
|
||||
func NewDistributionMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) DistributionMetric {
|
||||
am := abstractMetric{
|
||||
key,
|
||||
unit,
|
||||
tags,
|
||||
timestamp,
|
||||
}
|
||||
|
||||
return DistributionMetric{
|
||||
[]float64{value},
|
||||
am,
|
||||
}
|
||||
}
|
||||
|
||||
// Gauge Metric.
|
||||
type GaugeMetric struct {
|
||||
last float64
|
||||
min float64
|
||||
max float64
|
||||
sum float64
|
||||
count float64
|
||||
abstractMetric
|
||||
}
|
||||
|
||||
func (g *GaugeMetric) Add(value float64) {
|
||||
g.last = value
|
||||
g.min = math.Min(g.min, value)
|
||||
g.max = math.Max(g.max, value)
|
||||
g.sum += value
|
||||
g.count++
|
||||
}
|
||||
|
||||
func (g GaugeMetric) GetType() string {
|
||||
return "g"
|
||||
}
|
||||
|
||||
func (g GaugeMetric) SerializeValue() string {
|
||||
return fmt.Sprintf(":%v:%v:%v:%v:%v", g.last, g.min, g.max, g.sum, g.count)
|
||||
}
|
||||
|
||||
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
|
||||
func NewGaugeMetric(key string, unit MetricUnit, tags map[string]string, timestamp int64, value float64) GaugeMetric {
|
||||
am := abstractMetric{
|
||||
key,
|
||||
unit,
|
||||
tags,
|
||||
timestamp,
|
||||
}
|
||||
|
||||
return GaugeMetric{
|
||||
value, // last
|
||||
value, // min
|
||||
value, // max
|
||||
value, // sum
|
||||
value, // count
|
||||
am,
|
||||
}
|
||||
}
|
||||
|
||||
// Set Metric.
|
||||
type SetMetric[T NumberOrString] struct {
|
||||
values map[T]void
|
||||
abstractMetric
|
||||
}
|
||||
|
||||
func (s *SetMetric[T]) Add(value T) {
|
||||
s.values[value] = member
|
||||
}
|
||||
|
||||
func (s SetMetric[T]) GetType() string {
|
||||
return "s"
|
||||
}
|
||||
|
||||
func (s SetMetric[T]) SerializeValue() string {
|
||||
_hash := func(s string) uint32 {
|
||||
return crc32.ChecksumIEEE([]byte(s))
|
||||
}
|
||||
|
||||
values := make([]T, 0, len(s.values))
|
||||
for k := range s.values {
|
||||
values = append(values, k)
|
||||
}
|
||||
sortSlice(values)
|
||||
|
||||
var sb strings.Builder
|
||||
for _, el := range values {
|
||||
switch any(el).(type) {
|
||||
case int:
|
||||
sb.WriteString(fmt.Sprintf(":%v", el))
|
||||
case string:
|
||||
s := fmt.Sprintf("%v", el)
|
||||
sb.WriteString(fmt.Sprintf(":%d", _hash(s)))
|
||||
}
|
||||
}
|
||||
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// timestamp: A unix timestamp (full seconds elapsed since 1970-01-01 00:00 UTC).
|
||||
func NewSetMetric[T NumberOrString](key string, unit MetricUnit, tags map[string]string, timestamp int64, value T) SetMetric[T] {
|
||||
am := abstractMetric{
|
||||
key,
|
||||
unit,
|
||||
tags,
|
||||
timestamp,
|
||||
}
|
||||
|
||||
return SetMetric[T]{
|
||||
map[T]void{
|
||||
value: member,
|
||||
},
|
||||
am,
|
||||
}
|
||||
}
|
||||
|
||||
func sanitizeKey(s string) string {
|
||||
return keyRegex.ReplaceAllString(s, "_")
|
||||
}
|
||||
|
||||
func sanitizeValue(s string) string {
|
||||
return valueRegex.ReplaceAllString(s, "")
|
||||
}
|
||||
|
||||
type Ordered interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 | ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr | ~float32 | ~float64 | ~string
|
||||
}
|
||||
|
||||
func sortSlice[T Ordered](s []T) {
|
||||
sort.Slice(s, func(i, j int) bool {
|
||||
return s[i] < s[j]
|
||||
})
|
||||
}
|
||||
23
vendor/github.com/getsentry/sentry-go/sentry.go
generated
vendored
23
vendor/github.com/getsentry/sentry-go/sentry.go
generated
vendored
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// The version of the SDK.
|
||||
const SDKVersion = "0.27.0"
|
||||
const SDKVersion = "0.28.1"
|
||||
|
||||
// apiVersion is the minimum version of the Sentry API compatible with the
|
||||
// sentry-go SDK.
|
||||
@@ -72,18 +72,17 @@ func Recover() *EventID {
|
||||
|
||||
// RecoverWithContext captures a panic and passes relevant context object.
|
||||
func RecoverWithContext(ctx context.Context) *EventID {
|
||||
if err := recover(); err != nil {
|
||||
var hub *Hub
|
||||
|
||||
if HasHubOnContext(ctx) {
|
||||
hub = GetHubFromContext(ctx)
|
||||
} else {
|
||||
hub = CurrentHub()
|
||||
}
|
||||
|
||||
return hub.RecoverWithContext(ctx, err)
|
||||
err := recover()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
|
||||
hub := GetHubFromContext(ctx)
|
||||
if hub == nil {
|
||||
hub = CurrentHub()
|
||||
}
|
||||
|
||||
return hub.RecoverWithContext(ctx, err)
|
||||
}
|
||||
|
||||
// WithScope is a shorthand for CurrentHub().WithScope.
|
||||
|
||||
35
vendor/github.com/getsentry/sentry-go/traces_profiler.go
generated
vendored
35
vendor/github.com/getsentry/sentry-go/traces_profiler.go
generated
vendored
@@ -7,8 +7,8 @@ import (
|
||||
|
||||
// Checks whether the transaction should be profiled (according to ProfilesSampleRate)
|
||||
// and starts a profiler if so.
|
||||
func (span *Span) sampleTransactionProfile() {
|
||||
var sampleRate = span.clientOptions().ProfilesSampleRate
|
||||
func (s *Span) sampleTransactionProfile() {
|
||||
var sampleRate = s.clientOptions().ProfilesSampleRate
|
||||
switch {
|
||||
case sampleRate < 0.0 || sampleRate > 1.0:
|
||||
Logger.Printf("Skipping transaction profiling: ProfilesSampleRate out of range [0.0, 1.0]: %f\n", sampleRate)
|
||||
@@ -19,7 +19,7 @@ func (span *Span) sampleTransactionProfile() {
|
||||
if globalProfiler == nil {
|
||||
Logger.Println("Skipping transaction profiling: the profiler couldn't be started")
|
||||
} else {
|
||||
span.collectProfile = collectTransactionProfile
|
||||
s.collectProfile = collectTransactionProfile
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,22 +69,27 @@ func (info *profileInfo) UpdateFromEvent(event *Event) {
|
||||
info.Dist = event.Dist
|
||||
info.Transaction.ID = event.EventID
|
||||
|
||||
getStringFromContext := func(context map[string]interface{}, originalValue, key string) string {
|
||||
v, ok := context[key]
|
||||
if !ok {
|
||||
return originalValue
|
||||
}
|
||||
|
||||
if s, ok := v.(string); ok {
|
||||
return s
|
||||
}
|
||||
|
||||
return originalValue
|
||||
}
|
||||
|
||||
if runtimeContext, ok := event.Contexts["runtime"]; ok {
|
||||
if value, ok := runtimeContext["name"]; !ok {
|
||||
info.Runtime.Name = value.(string)
|
||||
}
|
||||
if value, ok := runtimeContext["version"]; !ok {
|
||||
info.Runtime.Version = value.(string)
|
||||
}
|
||||
info.Runtime.Name = getStringFromContext(runtimeContext, info.Runtime.Name, "name")
|
||||
info.Runtime.Version = getStringFromContext(runtimeContext, info.Runtime.Version, "version")
|
||||
}
|
||||
if osContext, ok := event.Contexts["os"]; ok {
|
||||
if value, ok := osContext["name"]; !ok {
|
||||
info.OS.Name = value.(string)
|
||||
}
|
||||
info.OS.Name = getStringFromContext(osContext, info.OS.Name, "name")
|
||||
}
|
||||
if deviceContext, ok := event.Contexts["device"]; ok {
|
||||
if value, ok := deviceContext["arch"]; !ok {
|
||||
info.Device.Architecture = value.(string)
|
||||
}
|
||||
info.Device.Architecture = getStringFromContext(deviceContext, info.Device.Architecture, "arch")
|
||||
}
|
||||
}
|
||||
|
||||
10
vendor/github.com/getsentry/sentry-go/tracing.go
generated
vendored
10
vendor/github.com/getsentry/sentry-go/tracing.go
generated
vendored
@@ -169,11 +169,11 @@ func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Sp
|
||||
|
||||
span.Sampled = span.sample()
|
||||
|
||||
span.recorder = &spanRecorder{}
|
||||
if hasParent {
|
||||
span.recorder = parent.spanRecorder()
|
||||
} else {
|
||||
span.recorder = &spanRecorder{}
|
||||
}
|
||||
|
||||
span.recorder.record(&span)
|
||||
|
||||
hub := hubFromContext(ctx)
|
||||
@@ -226,7 +226,11 @@ func (s *Span) SetTag(name, value string) {
|
||||
// SetData sets a data on the span. It is recommended to use SetData instead of
|
||||
// accessing the data map directly as SetData takes care of initializing the map
|
||||
// when necessary.
|
||||
func (s *Span) SetData(name, value string) {
|
||||
func (s *Span) SetData(name string, value interface{}) {
|
||||
if value == nil {
|
||||
return
|
||||
}
|
||||
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
|
||||
|
||||
108
vendor/github.com/getsentry/sentry-go/transport.go
generated
vendored
108
vendor/github.com/getsentry/sentry-go/transport.go
generated
vendored
@@ -2,6 +2,7 @@ package sentry
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -94,6 +95,55 @@ func getRequestBodyFromEvent(event *Event) []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func marshalMetrics(metrics []Metric) []byte {
|
||||
var b bytes.Buffer
|
||||
for i, metric := range metrics {
|
||||
b.WriteString(metric.GetKey())
|
||||
if unit := metric.GetUnit(); unit != "" {
|
||||
b.WriteString(fmt.Sprintf("@%s", unit))
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("%s|%s", metric.SerializeValue(), metric.GetType()))
|
||||
if serializedTags := metric.SerializeTags(); serializedTags != "" {
|
||||
b.WriteString(fmt.Sprintf("|#%s", serializedTags))
|
||||
}
|
||||
b.WriteString(fmt.Sprintf("|T%d", metric.GetTimestamp()))
|
||||
|
||||
if i < len(metrics)-1 {
|
||||
b.WriteString("\n")
|
||||
}
|
||||
}
|
||||
return b.Bytes()
|
||||
}
|
||||
|
||||
func encodeMetric(enc *json.Encoder, b io.Writer, metrics []Metric) error {
|
||||
body := marshalMetrics(metrics)
|
||||
// Item header
|
||||
err := enc.Encode(struct {
|
||||
Type string `json:"type"`
|
||||
Length int `json:"length"`
|
||||
}{
|
||||
Type: metricType,
|
||||
Length: len(body),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// metric payload
|
||||
if _, err = b.Write(body); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// "Envelopes should be terminated with a trailing newline."
|
||||
//
|
||||
// [1]: https://develop.sentry.dev/sdk/envelopes/#envelopes
|
||||
if _, err := b.Write([]byte("\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func encodeAttachment(enc *json.Encoder, b io.Writer, attachment *Attachment) error {
|
||||
// Attachment header
|
||||
err := enc.Encode(struct {
|
||||
@@ -175,11 +225,15 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if event.Type == transactionType || event.Type == checkInType {
|
||||
switch event.Type {
|
||||
case transactionType, checkInType:
|
||||
err = encodeEnvelopeItem(enc, event.Type, body)
|
||||
} else {
|
||||
case metricType:
|
||||
err = encodeMetric(enc, &b, event.Metrics)
|
||||
default:
|
||||
err = encodeEnvelopeItem(enc, eventType, body)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -206,7 +260,7 @@ func envelopeFromBody(event *Event, dsn *Dsn, sentAt time.Time, body json.RawMes
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) {
|
||||
func getRequestFromEvent(ctx context.Context, event *Event, dsn *Dsn) (r *http.Request, err error) {
|
||||
defer func() {
|
||||
if r != nil {
|
||||
r.Header.Set("User-Agent", fmt.Sprintf("%s/%s", event.Sdk.Name, event.Sdk.Version))
|
||||
@@ -233,7 +287,13 @@ func getRequestFromEvent(event *Event, dsn *Dsn) (r *http.Request, err error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return http.NewRequest(
|
||||
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
|
||||
return http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodPost,
|
||||
dsn.GetAPIURL().String(),
|
||||
envelope,
|
||||
@@ -344,8 +404,13 @@ func (t *HTTPTransport) Configure(options ClientOptions) {
|
||||
})
|
||||
}
|
||||
|
||||
// SendEvent assembles a new packet out of Event and sends it to remote server.
|
||||
// SendEvent assembles a new packet out of Event and sends it to the remote server.
|
||||
func (t *HTTPTransport) SendEvent(event *Event) {
|
||||
t.SendEventWithContext(context.Background(), event)
|
||||
}
|
||||
|
||||
// SendEventWithContext assembles a new packet out of Event and sends it to the remote server.
|
||||
func (t *HTTPTransport) SendEventWithContext(ctx context.Context, event *Event) {
|
||||
if t.dsn == nil {
|
||||
return
|
||||
}
|
||||
@@ -356,7 +421,7 @@ func (t *HTTPTransport) SendEvent(event *Event) {
|
||||
return
|
||||
}
|
||||
|
||||
request, err := getRequestFromEvent(event, t.dsn)
|
||||
request, err := getRequestFromEvent(ctx, event, t.dsn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
@@ -478,6 +543,13 @@ func (t *HTTPTransport) worker() {
|
||||
Logger.Printf("There was an issue with sending an event: %v", err)
|
||||
continue
|
||||
}
|
||||
if response.StatusCode >= 400 && response.StatusCode <= 599 {
|
||||
b, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
Logger.Printf("Error while reading response code: %v", err)
|
||||
}
|
||||
Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b))
|
||||
}
|
||||
t.mu.Lock()
|
||||
t.limits.Merge(ratelimit.FromResponse(response))
|
||||
t.mu.Unlock()
|
||||
@@ -567,8 +639,13 @@ func (t *HTTPSyncTransport) Configure(options ClientOptions) {
|
||||
}
|
||||
}
|
||||
|
||||
// SendEvent assembles a new packet out of Event and sends it to remote server.
|
||||
// SendEvent assembles a new packet out of Event and sends it to the remote server.
|
||||
func (t *HTTPSyncTransport) SendEvent(event *Event) {
|
||||
t.SendEventWithContext(context.Background(), event)
|
||||
}
|
||||
|
||||
// SendEventWithContext assembles a new packet out of Event and sends it to the remote server.
|
||||
func (t *HTTPSyncTransport) SendEventWithContext(ctx context.Context, event *Event) {
|
||||
if t.dsn == nil {
|
||||
return
|
||||
}
|
||||
@@ -577,15 +654,18 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) {
|
||||
return
|
||||
}
|
||||
|
||||
request, err := getRequestFromEvent(event, t.dsn)
|
||||
request, err := getRequestFromEvent(ctx, event, t.dsn)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var eventType string
|
||||
if event.Type == transactionType {
|
||||
switch {
|
||||
case event.Type == transactionType:
|
||||
eventType = "transaction"
|
||||
} else {
|
||||
case event.Type == metricType:
|
||||
eventType = metricType
|
||||
default:
|
||||
eventType = fmt.Sprintf("%s event", event.Level)
|
||||
}
|
||||
Logger.Printf(
|
||||
@@ -601,6 +681,14 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) {
|
||||
Logger.Printf("There was an issue with sending an event: %v", err)
|
||||
return
|
||||
}
|
||||
if response.StatusCode >= 400 && response.StatusCode <= 599 {
|
||||
b, err := io.ReadAll(response.Body)
|
||||
if err != nil {
|
||||
Logger.Printf("Error while reading response code: %v", err)
|
||||
}
|
||||
Logger.Printf("Sending %s failed with the following error: %s", eventType, string(b))
|
||||
}
|
||||
|
||||
t.mu.Lock()
|
||||
t.limits.Merge(ratelimit.FromResponse(response))
|
||||
t.mu.Unlock()
|
||||
|
||||
4
vendor/github.com/getsentry/sentry-go/util.go
generated
vendored
4
vendor/github.com/getsentry/sentry-go/util.go
generated
vendored
@@ -112,3 +112,7 @@ func revisionFromBuildInfo(info *debug.BuildInfo) string {
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func Pointer[T any](v T) *T {
|
||||
return &v
|
||||
}
|
||||
|
||||
7
vendor/github.com/klauspost/compress/README.md
generated
vendored
7
vendor/github.com/klauspost/compress/README.md
generated
vendored
@@ -55,6 +55,10 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
|
||||
* s2: Do 2 overlapping match checks https://github.com/klauspost/compress/pull/839
|
||||
* flate: Add amd64 assembly matchlen https://github.com/klauspost/compress/pull/837
|
||||
* gzip: Copy bufio.Reader on Reset by @thatguystone in https://github.com/klauspost/compress/pull/860
|
||||
|
||||
<details>
|
||||
<summary>See changes to v1.16.x</summary>
|
||||
|
||||
|
||||
* July 1st, 2023 - [v1.16.7](https://github.com/klauspost/compress/releases/tag/v1.16.7)
|
||||
* zstd: Fix default level first dictionary encode https://github.com/klauspost/compress/pull/829
|
||||
@@ -93,6 +97,7 @@ https://github.com/klauspost/compress/pull/919 https://github.com/klauspost/comp
|
||||
* s2: Add LZ4 block converter. https://github.com/klauspost/compress/pull/748
|
||||
* s2: Support io.ReaderAt in ReadSeeker. https://github.com/klauspost/compress/pull/747
|
||||
* s2c/s2sx: Use concurrent decoding. https://github.com/klauspost/compress/pull/746
|
||||
</details>
|
||||
|
||||
<details>
|
||||
<summary>See changes to v1.15.x</summary>
|
||||
@@ -560,6 +565,8 @@ the stateless compress described below.
|
||||
|
||||
For compression performance, see: [this spreadsheet](https://docs.google.com/spreadsheets/d/1nuNE2nPfuINCZJRMt6wFWhKpToF95I47XjSsc-1rbPQ/edit?usp=sharing).
|
||||
|
||||
To disable all assembly add `-tags=noasm`. This works across all packages.
|
||||
|
||||
# Stateless compression
|
||||
|
||||
This package offers stateless compression as a special option for gzip/deflate.
|
||||
|
||||
2
vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
generated
vendored
2
vendor/github.com/klauspost/compress/internal/snapref/encode_other.go
generated
vendored
@@ -51,7 +51,7 @@ func emitCopy(dst []byte, offset, length int) int {
|
||||
i := 0
|
||||
// The maximum length for a single tagCopy1 or tagCopy2 op is 64 bytes. The
|
||||
// threshold for this loop is a little higher (at 68 = 64 + 4), and the
|
||||
// length emitted down below is is a little lower (at 60 = 64 - 4), because
|
||||
// length emitted down below is a little lower (at 60 = 64 - 4), because
|
||||
// it's shorter to encode a length 67 copy as a length 60 tagCopy2 followed
|
||||
// by a length 7 tagCopy1 (which encodes as 3+2 bytes) than to encode it as
|
||||
// a length 64 tagCopy2 followed by a length 3 tagCopy2 (which encodes as
|
||||
|
||||
3
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
3
vendor/github.com/klauspost/compress/zstd/blockdec.go
generated
vendored
@@ -554,6 +554,9 @@ func (b *blockDec) prepareSequences(in []byte, hist *history) (err error) {
|
||||
if debugDecoder {
|
||||
printf("Compression modes: 0b%b", compMode)
|
||||
}
|
||||
if compMode&3 != 0 {
|
||||
return errors.New("corrupt block: reserved bits not zero")
|
||||
}
|
||||
for i := uint(0); i < 3; i++ {
|
||||
mode := seqCompMode((compMode >> (6 - i*2)) & 3)
|
||||
if debugDecoder {
|
||||
|
||||
20
vendor/github.com/klauspost/compress/zstd/blockenc.go
generated
vendored
20
vendor/github.com/klauspost/compress/zstd/blockenc.go
generated
vendored
@@ -427,6 +427,16 @@ func (b *blockEnc) encodeLits(lits []byte, raw bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// encodeRLE will encode an RLE block.
|
||||
func (b *blockEnc) encodeRLE(val byte, length uint32) {
|
||||
var bh blockHeader
|
||||
bh.setLast(b.last)
|
||||
bh.setSize(length)
|
||||
bh.setType(blockTypeRLE)
|
||||
b.output = bh.appendTo(b.output)
|
||||
b.output = append(b.output, val)
|
||||
}
|
||||
|
||||
// fuzzFseEncoder can be used to fuzz the FSE encoder.
|
||||
func fuzzFseEncoder(data []byte) int {
|
||||
if len(data) > maxSequences || len(data) < 2 {
|
||||
@@ -479,6 +489,16 @@ func (b *blockEnc) encode(org []byte, raw, rawAllLits bool) error {
|
||||
if len(b.sequences) == 0 {
|
||||
return b.encodeLits(b.literals, rawAllLits)
|
||||
}
|
||||
if len(b.sequences) == 1 && len(org) > 0 && len(b.literals) <= 1 {
|
||||
// Check common RLE cases.
|
||||
seq := b.sequences[0]
|
||||
if seq.litLen == uint32(len(b.literals)) && seq.offset-3 == 1 {
|
||||
// Offset == 1 and 0 or 1 literals.
|
||||
b.encodeRLE(org[0], b.sequences[0].matchLen+zstdMinMatch+seq.litLen)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// We want some difference to at least account for the headers.
|
||||
saved := b.size - len(b.literals) - (b.size >> 6)
|
||||
if saved < 16 {
|
||||
|
||||
2
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
2
vendor/github.com/klauspost/compress/zstd/decoder.go
generated
vendored
@@ -82,7 +82,7 @@ var (
|
||||
// can run multiple concurrent stateless decodes. It is even possible to
|
||||
// use stateless decodes while a stream is being decoded.
|
||||
//
|
||||
// The Reset function can be used to initiate a new stream, which is will considerably
|
||||
// The Reset function can be used to initiate a new stream, which will considerably
|
||||
// reduce the allocations normally caused by NewReader.
|
||||
func NewReader(r io.Reader, opts ...DOption) (*Decoder, error) {
|
||||
initPredefined()
|
||||
|
||||
31
vendor/github.com/klauspost/compress/zstd/dict.go
generated
vendored
31
vendor/github.com/klauspost/compress/zstd/dict.go
generated
vendored
@@ -273,6 +273,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
enc.Encode(&block, b)
|
||||
addValues(&remain, block.literals)
|
||||
litTotal += len(block.literals)
|
||||
if len(block.sequences) == 0 {
|
||||
continue
|
||||
}
|
||||
seqs += len(block.sequences)
|
||||
block.genCodes()
|
||||
addHist(&ll, block.coders.llEnc.Histogram())
|
||||
@@ -286,6 +289,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
if offset == 0 {
|
||||
continue
|
||||
}
|
||||
if int(offset) >= len(o.History) {
|
||||
continue
|
||||
}
|
||||
if offset > 3 {
|
||||
newOffsets[offset-3]++
|
||||
} else {
|
||||
@@ -336,6 +342,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
if seqs/nUsed < 512 {
|
||||
// Use 512 as minimum.
|
||||
nUsed = seqs / 512
|
||||
if nUsed == 0 {
|
||||
nUsed = 1
|
||||
}
|
||||
}
|
||||
copyHist := func(dst *fseEncoder, src *[256]int) ([]byte, error) {
|
||||
hist := dst.Histogram()
|
||||
@@ -358,6 +367,28 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
fakeLength += v
|
||||
hist[i] = uint32(v)
|
||||
}
|
||||
|
||||
// Ensure we aren't trying to represent RLE.
|
||||
if maxCount == fakeLength {
|
||||
for i := range hist {
|
||||
if uint8(i) == maxSym {
|
||||
fakeLength++
|
||||
maxSym++
|
||||
hist[i+1] = 1
|
||||
if maxSym > 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
if hist[0] == 0 {
|
||||
fakeLength++
|
||||
hist[i] = 1
|
||||
if maxSym > 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dst.HistogramFinished(maxSym, maxCount)
|
||||
dst.reUsed = false
|
||||
dst.useRLE = false
|
||||
|
||||
12
vendor/github.com/klauspost/compress/zstd/enc_best.go
generated
vendored
12
vendor/github.com/klauspost/compress/zstd/enc_best.go
generated
vendored
@@ -135,8 +135,20 @@ func (e *bestFastEncoder) Encode(blk *blockEnc, src []byte) {
|
||||
break
|
||||
}
|
||||
|
||||
// Add block to history
|
||||
s := e.addBlock(src)
|
||||
blk.size = len(src)
|
||||
|
||||
// Check RLE first
|
||||
if len(src) > zstdMinMatch {
|
||||
ml := matchLen(src[1:], src)
|
||||
if ml == len(src)-1 {
|
||||
blk.literals = append(blk.literals, src[0])
|
||||
blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(src) < minNonLiteralBlockSize {
|
||||
blk.extraLits = len(src)
|
||||
blk.literals = blk.literals[:len(src)]
|
||||
|
||||
13
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
13
vendor/github.com/klauspost/compress/zstd/enc_better.go
generated
vendored
@@ -102,9 +102,20 @@ func (e *betterFastEncoder) Encode(blk *blockEnc, src []byte) {
|
||||
e.cur = e.maxMatchOff
|
||||
break
|
||||
}
|
||||
|
||||
// Add block to history
|
||||
s := e.addBlock(src)
|
||||
blk.size = len(src)
|
||||
|
||||
// Check RLE first
|
||||
if len(src) > zstdMinMatch {
|
||||
ml := matchLen(src[1:], src)
|
||||
if ml == len(src)-1 {
|
||||
blk.literals = append(blk.literals, src[0])
|
||||
blk.sequences = append(blk.sequences, seq{litLen: 1, matchLen: uint32(len(src)-1) - zstdMinMatch, offset: 1 + 3})
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if len(src) < minNonLiteralBlockSize {
|
||||
blk.extraLits = len(src)
|
||||
blk.literals = blk.literals[:len(src)]
|
||||
|
||||
4
vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s
generated
vendored
4
vendor/github.com/klauspost/compress/zstd/internal/xxhash/xxhash_arm64.s
generated
vendored
@@ -162,12 +162,12 @@ finalize:
|
||||
MOVD h, ret+24(FP)
|
||||
RET
|
||||
|
||||
// func writeBlocks(d *Digest, b []byte) int
|
||||
// func writeBlocks(s *Digest, b []byte) int
|
||||
TEXT ·writeBlocks(SB), NOSPLIT|NOFRAME, $0-40
|
||||
LDP ·primes+0(SB), (prime1, prime2)
|
||||
|
||||
// Load state. Assume v[1-4] are stored contiguously.
|
||||
MOVD d+0(FP), digest
|
||||
MOVD s+0(FP), digest
|
||||
LDP 0(digest), (v1, v2)
|
||||
LDP 16(digest), (v3, v4)
|
||||
|
||||
|
||||
10
vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s
generated
vendored
10
vendor/github.com/klauspost/compress/zstd/matchlen_amd64.s
generated
vendored
@@ -5,7 +5,6 @@
|
||||
#include "textflag.h"
|
||||
|
||||
// func matchLen(a []byte, b []byte) int
|
||||
// Requires: BMI
|
||||
TEXT ·matchLen(SB), NOSPLIT, $0-56
|
||||
MOVQ a_base+0(FP), AX
|
||||
MOVQ b_base+24(FP), CX
|
||||
@@ -17,17 +16,16 @@ TEXT ·matchLen(SB), NOSPLIT, $0-56
|
||||
JB matchlen_match4_standalone
|
||||
|
||||
matchlen_loopback_standalone:
|
||||
MOVQ (AX)(SI*1), BX
|
||||
XORQ (CX)(SI*1), BX
|
||||
TESTQ BX, BX
|
||||
JZ matchlen_loop_standalone
|
||||
MOVQ (AX)(SI*1), BX
|
||||
XORQ (CX)(SI*1), BX
|
||||
JZ matchlen_loop_standalone
|
||||
|
||||
#ifdef GOAMD64_v3
|
||||
TZCNTQ BX, BX
|
||||
#else
|
||||
BSFQ BX, BX
|
||||
#endif
|
||||
SARQ $0x03, BX
|
||||
SHRL $0x03, BX
|
||||
LEAL (SI)(BX*1), SI
|
||||
JMP gen_match_len_end
|
||||
|
||||
|
||||
31
vendor/github.com/munnerz/goautoneg/LICENSE
generated
vendored
Normal file
31
vendor/github.com/munnerz/goautoneg/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
13
vendor/github.com/munnerz/goautoneg/Makefile
generated
vendored
Normal file
13
vendor/github.com/munnerz/goautoneg/Makefile
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
include $(GOROOT)/src/Make.inc
|
||||
|
||||
TARG=bitbucket.org/ww/goautoneg
|
||||
GOFILES=autoneg.go
|
||||
|
||||
include $(GOROOT)/src/Make.pkg
|
||||
|
||||
format:
|
||||
gofmt -w *.go
|
||||
|
||||
docs:
|
||||
gomake clean
|
||||
godoc ${TARG} > README.txt
|
||||
@@ -1,28 +1,28 @@
|
||||
/*
|
||||
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||
All rights reserved.
|
||||
|
||||
HTTP Content-Type Autonegotiation.
|
||||
|
||||
The functions in this package implement the behaviour specified in
|
||||
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
|
||||
|
||||
Copyright (c) 2011, Open Knowledge Foundation Ltd.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
Neither the name of the Open Knowledge Foundation Ltd. nor the
|
||||
names of its contributors may be used to endorse or promote
|
||||
products derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
@@ -36,6 +36,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
package goautoneg
|
||||
|
||||
import (
|
||||
@@ -51,16 +52,14 @@ type Accept struct {
|
||||
Params map[string]string
|
||||
}
|
||||
|
||||
// For internal use, so that we can use the sort interface
|
||||
type accept_slice []Accept
|
||||
// acceptSlice is defined to implement sort interface.
|
||||
type acceptSlice []Accept
|
||||
|
||||
func (accept accept_slice) Len() int {
|
||||
slice := []Accept(accept)
|
||||
func (slice acceptSlice) Len() int {
|
||||
return len(slice)
|
||||
}
|
||||
|
||||
func (accept accept_slice) Less(i, j int) bool {
|
||||
slice := []Accept(accept)
|
||||
func (slice acceptSlice) Less(i, j int) bool {
|
||||
ai, aj := slice[i], slice[j]
|
||||
if ai.Q > aj.Q {
|
||||
return true
|
||||
@@ -74,63 +73,93 @@ func (accept accept_slice) Less(i, j int) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (accept accept_slice) Swap(i, j int) {
|
||||
slice := []Accept(accept)
|
||||
func (slice acceptSlice) Swap(i, j int) {
|
||||
slice[i], slice[j] = slice[j], slice[i]
|
||||
}
|
||||
|
||||
func stringTrimSpaceCutset(r rune) bool {
|
||||
return r == ' '
|
||||
}
|
||||
|
||||
func nextSplitElement(s, sep string) (item string, remaining string) {
|
||||
if index := strings.Index(s, sep); index != -1 {
|
||||
return s[:index], s[index+1:]
|
||||
}
|
||||
return s, ""
|
||||
}
|
||||
|
||||
// Parse an Accept Header string returning a sorted list
|
||||
// of clauses
|
||||
func ParseAccept(header string) (accept []Accept) {
|
||||
parts := strings.Split(header, ",")
|
||||
accept = make([]Accept, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
part := strings.Trim(part, " ")
|
||||
func ParseAccept(header string) acceptSlice {
|
||||
partsCount := 0
|
||||
remaining := header
|
||||
for len(remaining) > 0 {
|
||||
partsCount++
|
||||
_, remaining = nextSplitElement(remaining, ",")
|
||||
}
|
||||
accept := make(acceptSlice, 0, partsCount)
|
||||
|
||||
a := Accept{}
|
||||
a.Params = make(map[string]string)
|
||||
a.Q = 1.0
|
||||
remaining = header
|
||||
var part string
|
||||
for len(remaining) > 0 {
|
||||
part, remaining = nextSplitElement(remaining, ",")
|
||||
part = strings.TrimFunc(part, stringTrimSpaceCutset)
|
||||
|
||||
mrp := strings.Split(part, ";")
|
||||
|
||||
media_range := mrp[0]
|
||||
sp := strings.Split(media_range, "/")
|
||||
a.Type = strings.Trim(sp[0], " ")
|
||||
|
||||
switch {
|
||||
case len(sp) == 1 && a.Type == "*":
|
||||
a.SubType = "*"
|
||||
case len(sp) == 2:
|
||||
a.SubType = strings.Trim(sp[1], " ")
|
||||
default:
|
||||
continue
|
||||
a := Accept{
|
||||
Q: 1.0,
|
||||
}
|
||||
|
||||
if len(mrp) == 1 {
|
||||
sp, remainingPart := nextSplitElement(part, ";")
|
||||
|
||||
sp0, spRemaining := nextSplitElement(sp, "/")
|
||||
a.Type = strings.TrimFunc(sp0, stringTrimSpaceCutset)
|
||||
|
||||
switch {
|
||||
case len(spRemaining) == 0:
|
||||
if a.Type == "*" {
|
||||
a.SubType = "*"
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
default:
|
||||
var sp1 string
|
||||
sp1, spRemaining = nextSplitElement(spRemaining, "/")
|
||||
if len(spRemaining) > 0 {
|
||||
continue
|
||||
}
|
||||
a.SubType = strings.TrimFunc(sp1, stringTrimSpaceCutset)
|
||||
}
|
||||
|
||||
if len(remainingPart) == 0 {
|
||||
accept = append(accept, a)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, param := range mrp[1:] {
|
||||
sp := strings.SplitN(param, "=", 2)
|
||||
if len(sp) != 2 {
|
||||
a.Params = make(map[string]string)
|
||||
for len(remainingPart) > 0 {
|
||||
sp, remainingPart = nextSplitElement(remainingPart, ";")
|
||||
sp0, spRemaining = nextSplitElement(sp, "=")
|
||||
if len(spRemaining) == 0 {
|
||||
continue
|
||||
}
|
||||
token := strings.Trim(sp[0], " ")
|
||||
var sp1 string
|
||||
sp1, spRemaining = nextSplitElement(spRemaining, "=")
|
||||
if len(spRemaining) != 0 {
|
||||
continue
|
||||
}
|
||||
token := strings.TrimFunc(sp0, stringTrimSpaceCutset)
|
||||
if token == "q" {
|
||||
a.Q, _ = strconv.ParseFloat(sp[1], 32)
|
||||
a.Q, _ = strconv.ParseFloat(sp1, 32)
|
||||
} else {
|
||||
a.Params[token] = strings.Trim(sp[1], " ")
|
||||
a.Params[token] = strings.TrimFunc(sp1, stringTrimSpaceCutset)
|
||||
}
|
||||
}
|
||||
|
||||
accept = append(accept, a)
|
||||
}
|
||||
|
||||
slice := accept_slice(accept)
|
||||
sort.Sort(slice)
|
||||
|
||||
return
|
||||
sort.Sort(accept)
|
||||
return accept
|
||||
}
|
||||
|
||||
// Negotiate the most appropriate content_type given the accept header
|
||||
6
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
6
vendor/github.com/prometheus/common/expfmt/decode.go
generated
vendored
@@ -75,14 +75,14 @@ func ResponseFormat(h http.Header) Format {
|
||||
func NewDecoder(r io.Reader, format Format) Decoder {
|
||||
switch format.FormatType() {
|
||||
case TypeProtoDelim:
|
||||
return &protoDecoder{r: r}
|
||||
return &protoDecoder{r: bufio.NewReader(r)}
|
||||
}
|
||||
return &textDecoder{r: r}
|
||||
}
|
||||
|
||||
// protoDecoder implements the Decoder interface for protocol buffers.
|
||||
type protoDecoder struct {
|
||||
r io.Reader
|
||||
r protodelim.Reader
|
||||
}
|
||||
|
||||
// Decode implements the Decoder interface.
|
||||
@@ -90,7 +90,7 @@ func (d *protoDecoder) Decode(v *dto.MetricFamily) error {
|
||||
opts := protodelim.UnmarshalOptions{
|
||||
MaxSize: -1,
|
||||
}
|
||||
if err := opts.UnmarshalFrom(bufio.NewReader(d.r), v); err != nil {
|
||||
if err := opts.UnmarshalFrom(d.r, v); err != nil {
|
||||
return err
|
||||
}
|
||||
if !model.IsValidMetricName(model.LabelValue(v.GetName())) {
|
||||
|
||||
13
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
13
vendor/github.com/prometheus/common/expfmt/encode.go
generated
vendored
@@ -21,9 +21,10 @@ import (
|
||||
"google.golang.org/protobuf/encoding/protodelim"
|
||||
"google.golang.org/protobuf/encoding/prototext"
|
||||
|
||||
"github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg"
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
"github.com/munnerz/goautoneg"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
@@ -139,7 +140,13 @@ func NegotiateIncludingOpenMetrics(h http.Header) Format {
|
||||
// interface is kept for backwards compatibility.
|
||||
// In cases where the Format does not allow for UTF-8 names, the global
|
||||
// NameEscapingScheme will be applied.
|
||||
func NewEncoder(w io.Writer, format Format) Encoder {
|
||||
//
|
||||
// NewEncoder can be called with additional options to customize the OpenMetrics text output.
|
||||
// For example:
|
||||
// NewEncoder(w, FmtOpenMetrics_1_0_0, WithCreatedLines())
|
||||
//
|
||||
// Extra options are ignored for all other formats.
|
||||
func NewEncoder(w io.Writer, format Format, options ...EncoderOption) Encoder {
|
||||
escapingScheme := format.ToEscapingScheme()
|
||||
|
||||
switch format.FormatType() {
|
||||
@@ -178,7 +185,7 @@ func NewEncoder(w io.Writer, format Format) Encoder {
|
||||
case TypeOpenMetrics:
|
||||
return encoderCloser{
|
||||
encode: func(v *dto.MetricFamily) error {
|
||||
_, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme))
|
||||
_, err := MetricFamilyToOpenMetrics(w, model.EscapeMetricFamily(v, escapingScheme), options...)
|
||||
return err
|
||||
},
|
||||
close: func() error {
|
||||
|
||||
22
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
22
vendor/github.com/prometheus/common/expfmt/expfmt.go
generated
vendored
@@ -15,6 +15,7 @@
|
||||
package expfmt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
@@ -63,7 +64,7 @@ const (
|
||||
type FormatType int
|
||||
|
||||
const (
|
||||
TypeUnknown = iota
|
||||
TypeUnknown FormatType = iota
|
||||
TypeProtoCompact
|
||||
TypeProtoDelim
|
||||
TypeProtoText
|
||||
@@ -73,7 +74,8 @@ const (
|
||||
|
||||
// NewFormat generates a new Format from the type provided. Mostly used for
|
||||
// tests, most Formats should be generated as part of content negotiation in
|
||||
// encode.go.
|
||||
// encode.go. If a type has more than one version, the latest version will be
|
||||
// returned.
|
||||
func NewFormat(t FormatType) Format {
|
||||
switch t {
|
||||
case TypeProtoCompact:
|
||||
@@ -91,13 +93,21 @@ func NewFormat(t FormatType) Format {
|
||||
}
|
||||
}
|
||||
|
||||
// NewOpenMetricsFormat generates a new OpenMetrics format matching the
|
||||
// specified version number.
|
||||
func NewOpenMetricsFormat(version string) (Format, error) {
|
||||
if version == OpenMetricsVersion_0_0_1 {
|
||||
return fmtOpenMetrics_0_0_1, nil
|
||||
}
|
||||
if version == OpenMetricsVersion_1_0_0 {
|
||||
return fmtOpenMetrics_1_0_0, nil
|
||||
}
|
||||
return fmtUnknown, fmt.Errorf("unknown open metrics version string")
|
||||
}
|
||||
|
||||
// FormatType deduces an overall FormatType for the given format.
|
||||
func (f Format) FormatType() FormatType {
|
||||
toks := strings.Split(string(f), ";")
|
||||
if len(toks) < 2 {
|
||||
return TypeUnknown
|
||||
}
|
||||
|
||||
params := make(map[string]string)
|
||||
for i, t := range toks {
|
||||
if i == 0 {
|
||||
|
||||
202
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
202
vendor/github.com/prometheus/common/expfmt/openmetrics_create.go
generated
vendored
@@ -22,11 +22,47 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
|
||||
"github.com/prometheus/common/model"
|
||||
|
||||
dto "github.com/prometheus/client_model/go"
|
||||
)
|
||||
|
||||
type encoderOption struct {
|
||||
withCreatedLines bool
|
||||
withUnit bool
|
||||
}
|
||||
|
||||
type EncoderOption func(*encoderOption)
|
||||
|
||||
// WithCreatedLines is an EncoderOption that configures the OpenMetrics encoder
|
||||
// to include _created lines (See
|
||||
// https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#counter-1).
|
||||
// Created timestamps can improve the accuracy of series reset detection, but
|
||||
// come with a bandwidth cost.
|
||||
//
|
||||
// At the time of writing, created timestamp ingestion is still experimental in
|
||||
// Prometheus and need to be enabled with the feature-flag
|
||||
// `--feature-flag=created-timestamp-zero-ingestion`, and breaking changes are
|
||||
// still possible. Therefore, it is recommended to use this feature with caution.
|
||||
func WithCreatedLines() EncoderOption {
|
||||
return func(t *encoderOption) {
|
||||
t.withCreatedLines = true
|
||||
}
|
||||
}
|
||||
|
||||
// WithUnit is an EncoderOption enabling a set unit to be written to the output
|
||||
// and to be added to the metric name, if it's not there already, as a suffix.
|
||||
// Without opting in this way, the unit will not be added to the metric name and,
|
||||
// on top of that, the unit will not be passed onto the output, even if it
|
||||
// were declared in the *dto.MetricFamily struct, i.e. even if in.Unit !=nil.
|
||||
func WithUnit() EncoderOption {
|
||||
return func(t *encoderOption) {
|
||||
t.withUnit = true
|
||||
}
|
||||
}
|
||||
|
||||
// MetricFamilyToOpenMetrics converts a MetricFamily proto message into the
|
||||
// OpenMetrics text format and writes the resulting lines to 'out'. It returns
|
||||
// the number of bytes written and any error encountered. The output will have
|
||||
@@ -59,20 +95,34 @@ import (
|
||||
// Prometheus to OpenMetrics or vice versa:
|
||||
//
|
||||
// - Counters are expected to have the `_total` suffix in their metric name. In
|
||||
// the output, the suffix will be truncated from the `# TYPE` and `# HELP`
|
||||
// line. A counter with a missing `_total` suffix is not an error. However,
|
||||
// the output, the suffix will be truncated from the `# TYPE`, `# HELP` and `# UNIT`
|
||||
// lines. A counter with a missing `_total` suffix is not an error. However,
|
||||
// its type will be set to `unknown` in that case to avoid invalid OpenMetrics
|
||||
// output.
|
||||
//
|
||||
// - No support for the following (optional) features: `# UNIT` line, `_created`
|
||||
// line, info type, stateset type, gaugehistogram type.
|
||||
// - According to the OM specs, the `# UNIT` line is optional, but if populated,
|
||||
// the unit has to be present in the metric name as its suffix:
|
||||
// (see https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#unit).
|
||||
// However, in order to accommodate any potential scenario where such a change in the
|
||||
// metric name is not desirable, the users are here given the choice of either explicitly
|
||||
// opt in, in case they wish for the unit to be included in the output AND in the metric name
|
||||
// as a suffix (see the description of the WithUnit function above),
|
||||
// or not to opt in, in case they don't want for any of that to happen.
|
||||
//
|
||||
// - No support for the following (optional) features: info type,
|
||||
// stateset type, gaugehistogram type.
|
||||
//
|
||||
// - The size of exemplar labels is not checked (i.e. it's possible to create
|
||||
// exemplars that are larger than allowed by the OpenMetrics specification).
|
||||
//
|
||||
// - The value of Counters is not checked. (OpenMetrics doesn't allow counters
|
||||
// with a `NaN` value.)
|
||||
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int, err error) {
|
||||
func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily, options ...EncoderOption) (written int, err error) {
|
||||
toOM := encoderOption{}
|
||||
for _, option := range options {
|
||||
option(&toOM)
|
||||
}
|
||||
|
||||
name := in.GetName()
|
||||
if name == "" {
|
||||
return 0, fmt.Errorf("MetricFamily has no name: %s", in)
|
||||
@@ -95,12 +145,15 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
}
|
||||
|
||||
var (
|
||||
n int
|
||||
metricType = in.GetType()
|
||||
shortName = name
|
||||
n int
|
||||
metricType = in.GetType()
|
||||
compliantName = name
|
||||
)
|
||||
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(shortName, "_total") {
|
||||
shortName = name[:len(name)-6]
|
||||
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(compliantName, "_total") {
|
||||
compliantName = name[:len(name)-6]
|
||||
}
|
||||
if toOM.withUnit && in.Unit != nil && !strings.HasSuffix(compliantName, fmt.Sprintf("_%s", *in.Unit)) {
|
||||
compliantName = compliantName + fmt.Sprintf("_%s", *in.Unit)
|
||||
}
|
||||
|
||||
// Comments, first HELP, then TYPE.
|
||||
@@ -110,7 +163,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = writeName(w, shortName)
|
||||
n, err = writeName(w, compliantName)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -136,7 +189,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = writeName(w, shortName)
|
||||
n, err = writeName(w, compliantName)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
@@ -163,55 +216,89 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if toOM.withUnit && in.Unit != nil {
|
||||
n, err = w.WriteString("# UNIT ")
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = writeName(w, compliantName)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = w.WriteByte(' ')
|
||||
written++
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
n, err = writeEscapedString(w, *in.Unit, true)
|
||||
written += n
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = w.WriteByte('\n')
|
||||
written++
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var createdTsBytesWritten int
|
||||
|
||||
// Finally the samples, one line for each.
|
||||
if metricType == dto.MetricType_COUNTER && strings.HasSuffix(name, "_total") {
|
||||
compliantName = compliantName + "_total"
|
||||
}
|
||||
for _, metric := range in.Metric {
|
||||
switch metricType {
|
||||
case dto.MetricType_COUNTER:
|
||||
if metric.Counter == nil {
|
||||
return written, fmt.Errorf(
|
||||
"expected counter in metric %s %s", name, metric,
|
||||
"expected counter in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
// Note that we have ensured above that either the name
|
||||
// ends on `_total` or that the rendered type is
|
||||
// `unknown`. Therefore, no `_total` must be added here.
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "", metric, "", 0,
|
||||
w, compliantName, "", metric, "", 0,
|
||||
metric.Counter.GetValue(), 0, false,
|
||||
metric.Counter.Exemplar,
|
||||
)
|
||||
if toOM.withCreatedLines && metric.Counter.CreatedTimestamp != nil {
|
||||
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "_total", metric, "", 0, metric.Counter.GetCreatedTimestamp())
|
||||
n += createdTsBytesWritten
|
||||
}
|
||||
case dto.MetricType_GAUGE:
|
||||
if metric.Gauge == nil {
|
||||
return written, fmt.Errorf(
|
||||
"expected gauge in metric %s %s", name, metric,
|
||||
"expected gauge in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "", metric, "", 0,
|
||||
w, compliantName, "", metric, "", 0,
|
||||
metric.Gauge.GetValue(), 0, false,
|
||||
nil,
|
||||
)
|
||||
case dto.MetricType_UNTYPED:
|
||||
if metric.Untyped == nil {
|
||||
return written, fmt.Errorf(
|
||||
"expected untyped in metric %s %s", name, metric,
|
||||
"expected untyped in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "", metric, "", 0,
|
||||
w, compliantName, "", metric, "", 0,
|
||||
metric.Untyped.GetValue(), 0, false,
|
||||
nil,
|
||||
)
|
||||
case dto.MetricType_SUMMARY:
|
||||
if metric.Summary == nil {
|
||||
return written, fmt.Errorf(
|
||||
"expected summary in metric %s %s", name, metric,
|
||||
"expected summary in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
for _, q := range metric.Summary.Quantile {
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "", metric,
|
||||
w, compliantName, "", metric,
|
||||
model.QuantileLabel, q.GetQuantile(),
|
||||
q.GetValue(), 0, false,
|
||||
nil,
|
||||
@@ -222,7 +309,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
}
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_sum", metric, "", 0,
|
||||
w, compliantName, "_sum", metric, "", 0,
|
||||
metric.Summary.GetSampleSum(), 0, false,
|
||||
nil,
|
||||
)
|
||||
@@ -231,20 +318,24 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
return
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_count", metric, "", 0,
|
||||
w, compliantName, "_count", metric, "", 0,
|
||||
0, metric.Summary.GetSampleCount(), true,
|
||||
nil,
|
||||
)
|
||||
if toOM.withCreatedLines && metric.Summary.CreatedTimestamp != nil {
|
||||
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Summary.GetCreatedTimestamp())
|
||||
n += createdTsBytesWritten
|
||||
}
|
||||
case dto.MetricType_HISTOGRAM:
|
||||
if metric.Histogram == nil {
|
||||
return written, fmt.Errorf(
|
||||
"expected histogram in metric %s %s", name, metric,
|
||||
"expected histogram in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
infSeen := false
|
||||
for _, b := range metric.Histogram.Bucket {
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_bucket", metric,
|
||||
w, compliantName, "_bucket", metric,
|
||||
model.BucketLabel, b.GetUpperBound(),
|
||||
0, b.GetCumulativeCount(), true,
|
||||
b.Exemplar,
|
||||
@@ -259,7 +350,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
}
|
||||
if !infSeen {
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_bucket", metric,
|
||||
w, compliantName, "_bucket", metric,
|
||||
model.BucketLabel, math.Inf(+1),
|
||||
0, metric.Histogram.GetSampleCount(), true,
|
||||
nil,
|
||||
@@ -270,7 +361,7 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
}
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_sum", metric, "", 0,
|
||||
w, compliantName, "_sum", metric, "", 0,
|
||||
metric.Histogram.GetSampleSum(), 0, false,
|
||||
nil,
|
||||
)
|
||||
@@ -279,13 +370,17 @@ func MetricFamilyToOpenMetrics(out io.Writer, in *dto.MetricFamily) (written int
|
||||
return
|
||||
}
|
||||
n, err = writeOpenMetricsSample(
|
||||
w, name, "_count", metric, "", 0,
|
||||
w, compliantName, "_count", metric, "", 0,
|
||||
0, metric.Histogram.GetSampleCount(), true,
|
||||
nil,
|
||||
)
|
||||
if toOM.withCreatedLines && metric.Histogram.CreatedTimestamp != nil {
|
||||
createdTsBytesWritten, err = writeOpenMetricsCreated(w, compliantName, "", metric, "", 0, metric.Histogram.GetCreatedTimestamp())
|
||||
n += createdTsBytesWritten
|
||||
}
|
||||
default:
|
||||
return written, fmt.Errorf(
|
||||
"unexpected type in metric %s %s", name, metric,
|
||||
"unexpected type in metric %s %s", compliantName, metric,
|
||||
)
|
||||
}
|
||||
written += n
|
||||
@@ -350,7 +445,7 @@ func writeOpenMetricsSample(
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
if exemplar != nil {
|
||||
if exemplar != nil && len(exemplar.Label) > 0 {
|
||||
n, err = writeExemplar(w, exemplar)
|
||||
written += n
|
||||
if err != nil {
|
||||
@@ -473,6 +568,49 @@ func writeOpenMetricsNameAndLabelPairs(
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// writeOpenMetricsCreated writes the created timestamp for a single time series
|
||||
// following OpenMetrics text format to w, given the metric name, the metric proto
|
||||
// message itself, optionally a suffix to be removed, e.g. '_total' for counters,
|
||||
// an additional label name with a float64 value (use empty string as label name if
|
||||
// not required) and the timestamp that represents the created timestamp.
|
||||
// The function returns the number of bytes written and any error encountered.
|
||||
func writeOpenMetricsCreated(w enhancedWriter,
|
||||
name, suffixToTrim string, metric *dto.Metric,
|
||||
additionalLabelName string, additionalLabelValue float64,
|
||||
createdTimestamp *timestamppb.Timestamp,
|
||||
) (int, error) {
|
||||
written := 0
|
||||
n, err := writeOpenMetricsNameAndLabelPairs(
|
||||
w, strings.TrimSuffix(name, suffixToTrim)+"_created", metric.Label, additionalLabelName, additionalLabelValue,
|
||||
)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
|
||||
err = w.WriteByte(' ')
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
|
||||
// TODO(beorn7): Format this directly from components of ts to
|
||||
// avoid overflow/underflow and precision issues of the float
|
||||
// conversion.
|
||||
n, err = writeOpenMetricsFloat(w, float64(createdTimestamp.AsTime().UnixNano())/1e9)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
|
||||
err = w.WriteByte('\n')
|
||||
written++
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
return written, nil
|
||||
}
|
||||
|
||||
// writeExemplar writes the provided exemplar in OpenMetrics format to w. The
|
||||
// function returns the number of bytes written and any error encountered.
|
||||
func writeExemplar(w enhancedWriter, e *dto.Exemplar) (int, error) {
|
||||
|
||||
27
vendor/github.com/prometheus/common/model/alert.go
generated
vendored
27
vendor/github.com/prometheus/common/model/alert.go
generated
vendored
@@ -75,7 +75,12 @@ func (a *Alert) ResolvedAt(ts time.Time) bool {
|
||||
|
||||
// Status returns the status of the alert.
|
||||
func (a *Alert) Status() AlertStatus {
|
||||
if a.Resolved() {
|
||||
return a.StatusAt(time.Now())
|
||||
}
|
||||
|
||||
// StatusAt returns the status of the alert at the given timestamp.
|
||||
func (a *Alert) StatusAt(ts time.Time) AlertStatus {
|
||||
if a.ResolvedAt(ts) {
|
||||
return AlertResolved
|
||||
}
|
||||
return AlertFiring
|
||||
@@ -127,6 +132,17 @@ func (as Alerts) HasFiring() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// HasFiringAt returns true iff one of the alerts is not resolved
|
||||
// at the time ts.
|
||||
func (as Alerts) HasFiringAt(ts time.Time) bool {
|
||||
for _, a := range as {
|
||||
if !a.ResolvedAt(ts) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Status returns StatusFiring iff at least one of the alerts is firing.
|
||||
func (as Alerts) Status() AlertStatus {
|
||||
if as.HasFiring() {
|
||||
@@ -134,3 +150,12 @@ func (as Alerts) Status() AlertStatus {
|
||||
}
|
||||
return AlertResolved
|
||||
}
|
||||
|
||||
// StatusAt returns StatusFiring iff at least one of the alerts is firing
|
||||
// at the time ts.
|
||||
func (as Alerts) StatusAt(ts time.Time) AlertStatus {
|
||||
if as.HasFiringAt(ts) {
|
||||
return AlertFiring
|
||||
}
|
||||
return AlertResolved
|
||||
}
|
||||
|
||||
11
vendor/github.com/prometheus/common/model/labelset.go
generated
vendored
11
vendor/github.com/prometheus/common/model/labelset.go
generated
vendored
@@ -17,7 +17,6 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// A LabelSet is a collection of LabelName and LabelValue pairs. The LabelSet
|
||||
@@ -129,16 +128,6 @@ func (l LabelSet) Merge(other LabelSet) LabelSet {
|
||||
return result
|
||||
}
|
||||
|
||||
func (l LabelSet) String() string {
|
||||
lstrs := make([]string, 0, len(l))
|
||||
for l, v := range l {
|
||||
lstrs = append(lstrs, fmt.Sprintf("%s=%q", l, v))
|
||||
}
|
||||
|
||||
sort.Strings(lstrs)
|
||||
return fmt.Sprintf("{%s}", strings.Join(lstrs, ", "))
|
||||
}
|
||||
|
||||
// Fingerprint returns the LabelSet's fingerprint.
|
||||
func (ls LabelSet) Fingerprint() Fingerprint {
|
||||
return labelSetToFingerprint(ls)
|
||||
|
||||
45
vendor/github.com/prometheus/common/model/labelset_string.go
generated
vendored
Normal file
45
vendor/github.com/prometheus/common/model/labelset_string.go
generated
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright 2024 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build go1.21
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"slices"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// String will look like `{foo="bar", more="less"}`. Names are sorted alphabetically.
|
||||
func (l LabelSet) String() string {
|
||||
var lna [32]string // On stack to avoid memory allocation for sorting names.
|
||||
labelNames := lna[:0]
|
||||
for name := range l {
|
||||
labelNames = append(labelNames, string(name))
|
||||
}
|
||||
slices.Sort(labelNames)
|
||||
var bytea [1024]byte // On stack to avoid memory allocation while building the output.
|
||||
b := bytes.NewBuffer(bytea[:0])
|
||||
b.WriteByte('{')
|
||||
for i, name := range labelNames {
|
||||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
b.WriteString(name)
|
||||
b.WriteByte('=')
|
||||
b.Write(strconv.AppendQuote(b.AvailableBuffer(), string(l[LabelName(name)])))
|
||||
}
|
||||
b.WriteByte('}')
|
||||
return b.String()
|
||||
}
|
||||
39
vendor/github.com/prometheus/common/model/labelset_string_go120.go
generated
vendored
Normal file
39
vendor/github.com/prometheus/common/model/labelset_string_go120.go
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2024 The Prometheus Authors
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:build !go1.21
|
||||
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// String was optimized using functions not available for go 1.20
|
||||
// or lower. We keep the old implementation for compatibility with client_golang.
|
||||
// Once client golang drops support for go 1.20 (scheduled for August 2024), this
|
||||
// file can be removed.
|
||||
func (l LabelSet) String() string {
|
||||
labelNames := make([]string, 0, len(l))
|
||||
for name := range l {
|
||||
labelNames = append(labelNames, string(name))
|
||||
}
|
||||
sort.Strings(labelNames)
|
||||
lstrs := make([]string, 0, len(l))
|
||||
for _, name := range labelNames {
|
||||
lstrs = append(lstrs, fmt.Sprintf("%s=%q", name, l[LabelName(name)]))
|
||||
}
|
||||
return fmt.Sprintf("{%s}", strings.Join(lstrs, ", "))
|
||||
}
|
||||
1
vendor/github.com/prometheus/common/model/metric.go
generated
vendored
1
vendor/github.com/prometheus/common/model/metric.go
generated
vendored
@@ -204,6 +204,7 @@ func EscapeMetricFamily(v *dto.MetricFamily, scheme EscapingScheme) *dto.MetricF
|
||||
out := &dto.MetricFamily{
|
||||
Help: v.Help,
|
||||
Type: v.Type,
|
||||
Unit: v.Unit,
|
||||
}
|
||||
|
||||
// If the name is nil, copy as-is, don't try to escape.
|
||||
|
||||
7
vendor/github.com/prometheus/procfs/.golangci.yml
generated
vendored
7
vendor/github.com/prometheus/procfs/.golangci.yml
generated
vendored
@@ -1,9 +1,16 @@
|
||||
---
|
||||
linters:
|
||||
enable:
|
||||
- errcheck
|
||||
- godot
|
||||
- gosimple
|
||||
- govet
|
||||
- ineffassign
|
||||
- misspell
|
||||
- revive
|
||||
- staticcheck
|
||||
- testifylint
|
||||
- unused
|
||||
|
||||
linter-settings:
|
||||
godot:
|
||||
|
||||
3
vendor/github.com/prometheus/procfs/MAINTAINERS.md
generated
vendored
3
vendor/github.com/prometheus/procfs/MAINTAINERS.md
generated
vendored
@@ -1,2 +1,3 @@
|
||||
* Johannes 'fish' Ziemke <github@freigeist.org> @discordianfish
|
||||
* Paul Gier <pgier@redhat.com> @pgier
|
||||
* Paul Gier <paulgier@gmail.com> @pgier
|
||||
* Ben Kochie <superq@gmail.com> @SuperQ
|
||||
|
||||
26
vendor/github.com/prometheus/procfs/Makefile.common
generated
vendored
26
vendor/github.com/prometheus/procfs/Makefile.common
generated
vendored
@@ -49,23 +49,23 @@ endif
|
||||
GOTEST := $(GO) test
|
||||
GOTEST_DIR :=
|
||||
ifneq ($(CIRCLE_JOB),)
|
||||
ifneq ($(shell command -v gotestsum > /dev/null),)
|
||||
ifneq ($(shell command -v gotestsum 2> /dev/null),)
|
||||
GOTEST_DIR := test-results
|
||||
GOTEST := gotestsum --junitfile $(GOTEST_DIR)/unit-tests.xml --
|
||||
endif
|
||||
endif
|
||||
|
||||
PROMU_VERSION ?= 0.15.0
|
||||
PROMU_VERSION ?= 0.17.0
|
||||
PROMU_URL := https://github.com/prometheus/promu/releases/download/v$(PROMU_VERSION)/promu-$(PROMU_VERSION).$(GO_BUILD_PLATFORM).tar.gz
|
||||
|
||||
SKIP_GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT :=
|
||||
GOLANGCI_LINT_OPTS ?=
|
||||
GOLANGCI_LINT_VERSION ?= v1.54.2
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64.
|
||||
GOLANGCI_LINT_VERSION ?= v1.59.0
|
||||
# golangci-lint only supports linux, darwin and windows platforms on i386/amd64/arm64.
|
||||
# windows isn't included here because of the path separator being different.
|
||||
ifeq ($(GOHOSTOS),$(filter $(GOHOSTOS),linux darwin))
|
||||
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386))
|
||||
ifeq ($(GOHOSTARCH),$(filter $(GOHOSTARCH),amd64 i386 arm64))
|
||||
# If we're in CI and there is an Actions file, that means the linter
|
||||
# is being run in Actions, so we don't need to run it here.
|
||||
ifneq (,$(SKIP_GOLANGCI_LINT))
|
||||
@@ -169,16 +169,20 @@ common-vet:
|
||||
common-lint: $(GOLANGCI_LINT)
|
||||
ifdef GOLANGCI_LINT
|
||||
@echo ">> running golangci-lint"
|
||||
# 'go list' needs to be executed before staticcheck to prepopulate the modules cache.
|
||||
# Otherwise staticcheck might fail randomly for some reason not yet explained.
|
||||
$(GO) list -e -compiled -test=true -export=false -deps=true -find=false -tags= -- ./... > /dev/null
|
||||
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_OPTS) $(pkgs)
|
||||
endif
|
||||
|
||||
.PHONY: common-lint-fix
|
||||
common-lint-fix: $(GOLANGCI_LINT)
|
||||
ifdef GOLANGCI_LINT
|
||||
@echo ">> running golangci-lint fix"
|
||||
$(GOLANGCI_LINT) run --fix $(GOLANGCI_LINT_OPTS) $(pkgs)
|
||||
endif
|
||||
|
||||
.PHONY: common-yamllint
|
||||
common-yamllint:
|
||||
@echo ">> running yamllint on all YAML files in the repository"
|
||||
ifeq (, $(shell command -v yamllint > /dev/null))
|
||||
ifeq (, $(shell command -v yamllint 2> /dev/null))
|
||||
@echo "yamllint not installed so skipping"
|
||||
else
|
||||
yamllint .
|
||||
@@ -204,6 +208,10 @@ common-tarball: promu
|
||||
@echo ">> building release tarball"
|
||||
$(PROMU) tarball --prefix $(PREFIX) $(BIN_DIR)
|
||||
|
||||
.PHONY: common-docker-repo-name
|
||||
common-docker-repo-name:
|
||||
@echo "$(DOCKER_REPO)/$(DOCKER_IMAGE_NAME)"
|
||||
|
||||
.PHONY: common-docker $(BUILD_DOCKER_ARCHS)
|
||||
common-docker: $(BUILD_DOCKER_ARCHS)
|
||||
$(BUILD_DOCKER_ARCHS): common-docker-%:
|
||||
|
||||
6
vendor/github.com/prometheus/procfs/arp.go
generated
vendored
6
vendor/github.com/prometheus/procfs/arp.go
generated
vendored
@@ -55,7 +55,7 @@ type ARPEntry struct {
|
||||
func (fs FS) GatherARPEntries() ([]ARPEntry, error) {
|
||||
data, err := os.ReadFile(fs.proc.Path("net/arp"))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err)
|
||||
return nil, fmt.Errorf("%w: error reading arp %s: %w", ErrFileRead, fs.proc.Path("net/arp"), err)
|
||||
}
|
||||
|
||||
return parseARPEntries(data)
|
||||
@@ -78,11 +78,11 @@ func parseARPEntries(data []byte) ([]ARPEntry, error) {
|
||||
} else if width == expectedDataWidth {
|
||||
entry, err := parseARPEntry(columns)
|
||||
if err != nil {
|
||||
return []ARPEntry{}, fmt.Errorf("%s: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err)
|
||||
return []ARPEntry{}, fmt.Errorf("%w: Failed to parse ARP entry: %v: %w", ErrFileParse, entry, err)
|
||||
}
|
||||
entries = append(entries, entry)
|
||||
} else {
|
||||
return []ARPEntry{}, fmt.Errorf("%s: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err)
|
||||
return []ARPEntry{}, fmt.Errorf("%w: %d columns found, but expected %d: %w", ErrFileParse, width, expectedDataWidth, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
6
vendor/github.com/prometheus/procfs/buddyinfo.go
generated
vendored
6
vendor/github.com/prometheus/procfs/buddyinfo.go
generated
vendored
@@ -58,8 +58,8 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
||||
return nil, fmt.Errorf("%w: Invalid number of fields, found: %v", ErrFileParse, parts)
|
||||
}
|
||||
|
||||
node := strings.TrimRight(parts[1], ",")
|
||||
zone := strings.TrimRight(parts[3], ",")
|
||||
node := strings.TrimSuffix(parts[1], ",")
|
||||
zone := strings.TrimSuffix(parts[3], ",")
|
||||
arraySize := len(parts[4:])
|
||||
|
||||
if bucketCount == -1 {
|
||||
@@ -74,7 +74,7 @@ func parseBuddyInfo(r io.Reader) ([]BuddyInfo, error) {
|
||||
for i := 0; i < arraySize; i++ {
|
||||
sizes[i], err = strconv.ParseFloat(parts[i+4], 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err)
|
||||
return nil, fmt.Errorf("%w: Invalid valid in buddyinfo: %f: %w", ErrFileParse, sizes[i], err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4
vendor/github.com/prometheus/procfs/cpuinfo.go
generated
vendored
4
vendor/github.com/prometheus/procfs/cpuinfo.go
generated
vendored
@@ -194,7 +194,7 @@ func parseCPUInfoARM(info []byte) ([]CPUInfo, error) {
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
match, err := regexp.MatchString("^[Pp]rocessor", firstLine)
|
||||
if !match || !strings.Contains(firstLine, ":") {
|
||||
return nil, fmt.Errorf("%s: Cannot parse line: %q: %w", ErrFileParse, firstLine, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse line: %q: %w", ErrFileParse, firstLine, err)
|
||||
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
@@ -386,7 +386,7 @@ func parseCPUInfoLoong(info []byte) ([]CPUInfo, error) {
|
||||
// find the first "processor" line
|
||||
firstLine := firstNonEmptyLine(scanner)
|
||||
if !strings.HasPrefix(firstLine, "system type") || !strings.Contains(firstLine, ":") {
|
||||
return nil, errors.New("invalid cpuinfo file: " + firstLine)
|
||||
return nil, fmt.Errorf("%w: %q", ErrFileParse, firstLine)
|
||||
}
|
||||
field := strings.SplitN(firstLine, ": ", 2)
|
||||
cpuinfo := []CPUInfo{}
|
||||
|
||||
6
vendor/github.com/prometheus/procfs/crypto.go
generated
vendored
6
vendor/github.com/prometheus/procfs/crypto.go
generated
vendored
@@ -55,13 +55,13 @@ func (fs FS) Crypto() ([]Crypto, error) {
|
||||
path := fs.proc.Path("crypto")
|
||||
b, err := util.ReadFileNoStat(path)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot read file %v: %w", ErrFileRead, b, err)
|
||||
return nil, fmt.Errorf("%w: Cannot read file %v: %w", ErrFileRead, b, err)
|
||||
|
||||
}
|
||||
|
||||
crypto, err := parseCrypto(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, crypto, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, crypto, err)
|
||||
}
|
||||
|
||||
return crypto, nil
|
||||
@@ -84,7 +84,7 @@ func parseCrypto(r io.Reader) ([]Crypto, error) {
|
||||
|
||||
kv := strings.Split(text, ":")
|
||||
if len(kv) != 2 {
|
||||
return nil, fmt.Errorf("%w: Cannot parae line: %q", ErrFileParse, text)
|
||||
return nil, fmt.Errorf("%w: Cannot parse line: %q", ErrFileParse, text)
|
||||
}
|
||||
|
||||
k := strings.TrimSpace(kv[0])
|
||||
|
||||
4
vendor/github.com/prometheus/procfs/fscache.go
generated
vendored
4
vendor/github.com/prometheus/procfs/fscache.go
generated
vendored
@@ -236,7 +236,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
|
||||
|
||||
m, err := parseFscacheinfo(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return Fscacheinfo{}, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, m, err)
|
||||
return Fscacheinfo{}, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, m, err)
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
@@ -245,7 +245,7 @@ func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
|
||||
func setFSCacheFields(fields []string, setFields ...*uint64) error {
|
||||
var err error
|
||||
if len(fields) < len(setFields) {
|
||||
return fmt.Errorf("%s: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err)
|
||||
return fmt.Errorf("%w: Expected %d, but got %d: %w", ErrFileParse, len(setFields), len(fields), err)
|
||||
}
|
||||
|
||||
for i := range setFields {
|
||||
|
||||
6
vendor/github.com/prometheus/procfs/ipvs.go
generated
vendored
6
vendor/github.com/prometheus/procfs/ipvs.go
generated
vendored
@@ -221,16 +221,16 @@ func parseIPPort(s string) (net.IP, uint16, error) {
|
||||
case 46:
|
||||
ip = net.ParseIP(s[1:40])
|
||||
if ip == nil {
|
||||
return nil, 0, fmt.Errorf("%s: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err)
|
||||
return nil, 0, fmt.Errorf("%w: Invalid IPv6 addr %s: %w", ErrFileParse, s[1:40], err)
|
||||
}
|
||||
default:
|
||||
return nil, 0, fmt.Errorf("%s: Unexpected IP:Port %s: %w", ErrFileParse, s, err)
|
||||
return nil, 0, fmt.Errorf("%w: Unexpected IP:Port %s: %w", ErrFileParse, s, err)
|
||||
}
|
||||
|
||||
portString := s[len(s)-4:]
|
||||
if len(portString) != 4 {
|
||||
return nil, 0,
|
||||
fmt.Errorf("%s: Unexpected port string format %s: %w", ErrFileParse, portString, err)
|
||||
fmt.Errorf("%w: Unexpected port string format %s: %w", ErrFileParse, portString, err)
|
||||
}
|
||||
port, err := strconv.ParseUint(portString, 16, 16)
|
||||
if err != nil {
|
||||
|
||||
2
vendor/github.com/prometheus/procfs/loadavg.go
generated
vendored
2
vendor/github.com/prometheus/procfs/loadavg.go
generated
vendored
@@ -51,7 +51,7 @@ func parseLoad(loadavgBytes []byte) (*LoadAvg, error) {
|
||||
for i, load := range parts[0:3] {
|
||||
loads[i], err = strconv.ParseFloat(load, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse load: %f: %w", ErrFileParse, loads[i], err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse load: %f: %w", ErrFileParse, loads[i], err)
|
||||
}
|
||||
}
|
||||
return &LoadAvg{
|
||||
|
||||
60
vendor/github.com/prometheus/procfs/mdstat.go
generated
vendored
60
vendor/github.com/prometheus/procfs/mdstat.go
generated
vendored
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
var (
|
||||
statusLineRE = regexp.MustCompile(`(\d+) blocks .*\[(\d+)/(\d+)\] \[([U_]+)\]`)
|
||||
recoveryLineBlocksRE = regexp.MustCompile(`\((\d+)/\d+\)`)
|
||||
recoveryLineBlocksRE = regexp.MustCompile(`\((\d+/\d+)\)`)
|
||||
recoveryLinePctRE = regexp.MustCompile(`= (.+)%`)
|
||||
recoveryLineFinishRE = regexp.MustCompile(`finish=(.+)min`)
|
||||
recoveryLineSpeedRE = regexp.MustCompile(`speed=(.+)[A-Z]`)
|
||||
@@ -50,6 +50,8 @@ type MDStat struct {
|
||||
BlocksTotal int64
|
||||
// Number of blocks on the device that are in sync.
|
||||
BlocksSynced int64
|
||||
// Number of blocks on the device that need to be synced.
|
||||
BlocksToBeSynced int64
|
||||
// progress percentage of current sync
|
||||
BlocksSyncedPct float64
|
||||
// estimated finishing time for current sync (in minutes)
|
||||
@@ -70,7 +72,7 @@ func (fs FS) MDStat() ([]MDStat, error) {
|
||||
}
|
||||
mdstat, err := parseMDStat(data)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse %v: %w", ErrFileParse, fs.proc.Path("mdstat"), err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse %v: %w", ErrFileParse, fs.proc.Path("mdstat"), err)
|
||||
}
|
||||
return mdstat, nil
|
||||
}
|
||||
@@ -90,7 +92,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
|
||||
deviceFields := strings.Fields(line)
|
||||
if len(deviceFields) < 3 {
|
||||
return nil, fmt.Errorf("%s: Expected 3+ lines, got %q", ErrFileParse, line)
|
||||
return nil, fmt.Errorf("%w: Expected 3+ lines, got %q", ErrFileParse, line)
|
||||
}
|
||||
mdName := deviceFields[0] // mdx
|
||||
state := deviceFields[2] // active or inactive
|
||||
@@ -105,7 +107,7 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
active, total, down, size, err := evalStatusLine(lines[i], lines[i+1])
|
||||
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse md device lines: %v: %w", ErrFileParse, active, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse md device lines: %v: %w", ErrFileParse, active, err)
|
||||
}
|
||||
|
||||
syncLineIdx := i + 2
|
||||
@@ -115,7 +117,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
|
||||
// If device is syncing at the moment, get the number of currently
|
||||
// synced bytes, otherwise that number equals the size of the device.
|
||||
syncedBlocks := size
|
||||
blocksSynced := size
|
||||
blocksToBeSynced := size
|
||||
speed := float64(0)
|
||||
finish := float64(0)
|
||||
pct := float64(0)
|
||||
@@ -136,11 +139,11 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
// Handle case when resync=PENDING or resync=DELAYED.
|
||||
if strings.Contains(lines[syncLineIdx], "PENDING") ||
|
||||
strings.Contains(lines[syncLineIdx], "DELAYED") {
|
||||
syncedBlocks = 0
|
||||
blocksSynced = 0
|
||||
} else {
|
||||
syncedBlocks, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
|
||||
blocksSynced, blocksToBeSynced, pct, finish, speed, err = evalRecoveryLine(lines[syncLineIdx])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse sync line in md device: %q: %w", ErrFileParse, mdName, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,7 +157,8 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
DisksSpare: spare,
|
||||
DisksTotal: total,
|
||||
BlocksTotal: size,
|
||||
BlocksSynced: syncedBlocks,
|
||||
BlocksSynced: blocksSynced,
|
||||
BlocksToBeSynced: blocksToBeSynced,
|
||||
BlocksSyncedPct: pct,
|
||||
BlocksSyncedFinishTime: finish,
|
||||
BlocksSyncedSpeed: speed,
|
||||
@@ -168,13 +172,13 @@ func parseMDStat(mdStatData []byte) ([]MDStat, error) {
|
||||
func evalStatusLine(deviceLine, statusLine string) (active, total, down, size int64, err error) {
|
||||
statusFields := strings.Fields(statusLine)
|
||||
if len(statusFields) < 1 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
}
|
||||
|
||||
sizeStr := statusFields[0]
|
||||
size, err = strconv.ParseInt(sizeStr, 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
}
|
||||
|
||||
if strings.Contains(deviceLine, "raid0") || strings.Contains(deviceLine, "linear") {
|
||||
@@ -189,65 +193,71 @@ func evalStatusLine(deviceLine, statusLine string) (active, total, down, size in
|
||||
|
||||
matches := statusLineRE.FindStringSubmatch(statusLine)
|
||||
if len(matches) != 5 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Could not fild all substring matches %s: %w", ErrFileParse, statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("%w: Could not fild all substring matches %s: %w", ErrFileParse, statusLine, err)
|
||||
}
|
||||
|
||||
total, err = strconv.ParseInt(matches[2], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected statusline %q: %w", ErrFileParse, statusLine, err)
|
||||
}
|
||||
|
||||
active, err = strconv.ParseInt(matches[3], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected active %d: %w", ErrFileParse, active, err)
|
||||
return 0, 0, 0, 0, fmt.Errorf("%w: Unexpected active %d: %w", ErrFileParse, active, err)
|
||||
}
|
||||
down = int64(strings.Count(matches[4], "_"))
|
||||
|
||||
return active, total, down, size, nil
|
||||
}
|
||||
|
||||
func evalRecoveryLine(recoveryLine string) (syncedBlocks int64, pct float64, finish float64, speed float64, err error) {
|
||||
func evalRecoveryLine(recoveryLine string) (blocksSynced int64, blocksToBeSynced int64, pct float64, finish float64, speed float64, err error) {
|
||||
matches := recoveryLineBlocksRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected recoveryLine %s: %w", ErrFileParse, recoveryLine, err)
|
||||
return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine blocks %s: %w", ErrFileParse, recoveryLine, err)
|
||||
}
|
||||
|
||||
syncedBlocks, err = strconv.ParseInt(matches[1], 10, 64)
|
||||
blocks := strings.Split(matches[1], "/")
|
||||
blocksSynced, err = strconv.ParseInt(blocks[0], 10, 64)
|
||||
if err != nil {
|
||||
return 0, 0, 0, 0, fmt.Errorf("%s: Unexpected parsing of recoveryLine %q: %w", ErrFileParse, recoveryLine, err)
|
||||
return 0, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery blocks synced %q: %w", ErrFileParse, matches[1], err)
|
||||
}
|
||||
|
||||
blocksToBeSynced, err = strconv.ParseInt(blocks[1], 10, 64)
|
||||
if err != nil {
|
||||
return blocksSynced, 0, 0, 0, 0, fmt.Errorf("%w: Unable to parse recovery to be synced blocks %q: %w", ErrFileParse, matches[2], err)
|
||||
}
|
||||
|
||||
// Get percentage complete
|
||||
matches = recoveryLinePctRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
|
||||
return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching percentage %s", ErrFileParse, recoveryLine)
|
||||
}
|
||||
pct, err = strconv.ParseFloat(strings.TrimSpace(matches[1]), 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
|
||||
return blocksSynced, blocksToBeSynced, 0, 0, 0, fmt.Errorf("%w: Error parsing float from recoveryLine %q", ErrFileParse, recoveryLine)
|
||||
}
|
||||
|
||||
// Get time expected left to complete
|
||||
matches = recoveryLineFinishRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
|
||||
return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unexpected recoveryLine matching est. finish time: %s", ErrFileParse, recoveryLine)
|
||||
}
|
||||
finish, err = strconv.ParseFloat(matches[1], 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
|
||||
return blocksSynced, blocksToBeSynced, pct, 0, 0, fmt.Errorf("%w: Unable to parse float from recoveryLine: %q", ErrFileParse, recoveryLine)
|
||||
}
|
||||
|
||||
// Get recovery speed
|
||||
matches = recoveryLineSpeedRE.FindStringSubmatch(recoveryLine)
|
||||
if len(matches) != 2 {
|
||||
return syncedBlocks, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
|
||||
return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Unexpected recoveryLine value: %s", ErrFileParse, recoveryLine)
|
||||
}
|
||||
speed, err = strconv.ParseFloat(matches[1], 64)
|
||||
if err != nil {
|
||||
return syncedBlocks, pct, finish, 0, fmt.Errorf("%s: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
|
||||
return blocksSynced, blocksToBeSynced, pct, finish, 0, fmt.Errorf("%w: Error parsing float from recoveryLine: %q: %w", ErrFileParse, recoveryLine, err)
|
||||
}
|
||||
|
||||
return syncedBlocks, pct, finish, speed, nil
|
||||
return blocksSynced, blocksToBeSynced, pct, finish, speed, nil
|
||||
}
|
||||
|
||||
func evalComponentDevices(deviceFields []string) []string {
|
||||
|
||||
220
vendor/github.com/prometheus/procfs/meminfo.go
generated
vendored
220
vendor/github.com/prometheus/procfs/meminfo.go
generated
vendored
@@ -126,6 +126,7 @@ type Meminfo struct {
|
||||
VmallocUsed *uint64
|
||||
// largest contiguous block of vmalloc area which is free
|
||||
VmallocChunk *uint64
|
||||
Percpu *uint64
|
||||
HardwareCorrupted *uint64
|
||||
AnonHugePages *uint64
|
||||
ShmemHugePages *uint64
|
||||
@@ -140,6 +141,55 @@ type Meminfo struct {
|
||||
DirectMap4k *uint64
|
||||
DirectMap2M *uint64
|
||||
DirectMap1G *uint64
|
||||
|
||||
// The struct fields below are the byte-normalized counterparts to the
|
||||
// existing struct fields. Values are normalized using the optional
|
||||
// unit field in the meminfo line.
|
||||
MemTotalBytes *uint64
|
||||
MemFreeBytes *uint64
|
||||
MemAvailableBytes *uint64
|
||||
BuffersBytes *uint64
|
||||
CachedBytes *uint64
|
||||
SwapCachedBytes *uint64
|
||||
ActiveBytes *uint64
|
||||
InactiveBytes *uint64
|
||||
ActiveAnonBytes *uint64
|
||||
InactiveAnonBytes *uint64
|
||||
ActiveFileBytes *uint64
|
||||
InactiveFileBytes *uint64
|
||||
UnevictableBytes *uint64
|
||||
MlockedBytes *uint64
|
||||
SwapTotalBytes *uint64
|
||||
SwapFreeBytes *uint64
|
||||
DirtyBytes *uint64
|
||||
WritebackBytes *uint64
|
||||
AnonPagesBytes *uint64
|
||||
MappedBytes *uint64
|
||||
ShmemBytes *uint64
|
||||
SlabBytes *uint64
|
||||
SReclaimableBytes *uint64
|
||||
SUnreclaimBytes *uint64
|
||||
KernelStackBytes *uint64
|
||||
PageTablesBytes *uint64
|
||||
NFSUnstableBytes *uint64
|
||||
BounceBytes *uint64
|
||||
WritebackTmpBytes *uint64
|
||||
CommitLimitBytes *uint64
|
||||
CommittedASBytes *uint64
|
||||
VmallocTotalBytes *uint64
|
||||
VmallocUsedBytes *uint64
|
||||
VmallocChunkBytes *uint64
|
||||
PercpuBytes *uint64
|
||||
HardwareCorruptedBytes *uint64
|
||||
AnonHugePagesBytes *uint64
|
||||
ShmemHugePagesBytes *uint64
|
||||
ShmemPmdMappedBytes *uint64
|
||||
CmaTotalBytes *uint64
|
||||
CmaFreeBytes *uint64
|
||||
HugepagesizeBytes *uint64
|
||||
DirectMap4kBytes *uint64
|
||||
DirectMap2MBytes *uint64
|
||||
DirectMap1GBytes *uint64
|
||||
}
|
||||
|
||||
// Meminfo returns an information about current kernel/system memory statistics.
|
||||
@@ -152,7 +202,7 @@ func (fs FS) Meminfo() (Meminfo, error) {
|
||||
|
||||
m, err := parseMemInfo(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return Meminfo{}, fmt.Errorf("%s: %w", ErrFileParse, err)
|
||||
return Meminfo{}, fmt.Errorf("%w: %w", ErrFileParse, err)
|
||||
}
|
||||
|
||||
return *m, nil
|
||||
@@ -162,114 +212,176 @@ func parseMemInfo(r io.Reader) (*Meminfo, error) {
|
||||
var m Meminfo
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
// Each line has at least a name and value; we ignore the unit.
|
||||
fields := strings.Fields(s.Text())
|
||||
if len(fields) < 2 {
|
||||
return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text())
|
||||
}
|
||||
var val, valBytes uint64
|
||||
|
||||
v, err := strconv.ParseUint(fields[1], 0, 64)
|
||||
val, err := strconv.ParseUint(fields[1], 0, 64)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch len(fields) {
|
||||
case 2:
|
||||
// No unit present, use the parsed the value as bytes directly.
|
||||
valBytes = val
|
||||
case 3:
|
||||
// Unit present in optional 3rd field, convert it to
|
||||
// bytes. The only unit supported within the Linux
|
||||
// kernel is `kB`.
|
||||
if fields[2] != "kB" {
|
||||
return nil, fmt.Errorf("%w: Unsupported unit in optional 3rd field %q", ErrFileParse, fields[2])
|
||||
}
|
||||
|
||||
valBytes = 1024 * val
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text())
|
||||
}
|
||||
|
||||
switch fields[0] {
|
||||
case "MemTotal:":
|
||||
m.MemTotal = &v
|
||||
m.MemTotal = &val
|
||||
m.MemTotalBytes = &valBytes
|
||||
case "MemFree:":
|
||||
m.MemFree = &v
|
||||
m.MemFree = &val
|
||||
m.MemFreeBytes = &valBytes
|
||||
case "MemAvailable:":
|
||||
m.MemAvailable = &v
|
||||
m.MemAvailable = &val
|
||||
m.MemAvailableBytes = &valBytes
|
||||
case "Buffers:":
|
||||
m.Buffers = &v
|
||||
m.Buffers = &val
|
||||
m.BuffersBytes = &valBytes
|
||||
case "Cached:":
|
||||
m.Cached = &v
|
||||
m.Cached = &val
|
||||
m.CachedBytes = &valBytes
|
||||
case "SwapCached:":
|
||||
m.SwapCached = &v
|
||||
m.SwapCached = &val
|
||||
m.SwapCachedBytes = &valBytes
|
||||
case "Active:":
|
||||
m.Active = &v
|
||||
m.Active = &val
|
||||
m.ActiveBytes = &valBytes
|
||||
case "Inactive:":
|
||||
m.Inactive = &v
|
||||
m.Inactive = &val
|
||||
m.InactiveBytes = &valBytes
|
||||
case "Active(anon):":
|
||||
m.ActiveAnon = &v
|
||||
m.ActiveAnon = &val
|
||||
m.ActiveAnonBytes = &valBytes
|
||||
case "Inactive(anon):":
|
||||
m.InactiveAnon = &v
|
||||
m.InactiveAnon = &val
|
||||
m.InactiveAnonBytes = &valBytes
|
||||
case "Active(file):":
|
||||
m.ActiveFile = &v
|
||||
m.ActiveFile = &val
|
||||
m.ActiveFileBytes = &valBytes
|
||||
case "Inactive(file):":
|
||||
m.InactiveFile = &v
|
||||
m.InactiveFile = &val
|
||||
m.InactiveFileBytes = &valBytes
|
||||
case "Unevictable:":
|
||||
m.Unevictable = &v
|
||||
m.Unevictable = &val
|
||||
m.UnevictableBytes = &valBytes
|
||||
case "Mlocked:":
|
||||
m.Mlocked = &v
|
||||
m.Mlocked = &val
|
||||
m.MlockedBytes = &valBytes
|
||||
case "SwapTotal:":
|
||||
m.SwapTotal = &v
|
||||
m.SwapTotal = &val
|
||||
m.SwapTotalBytes = &valBytes
|
||||
case "SwapFree:":
|
||||
m.SwapFree = &v
|
||||
m.SwapFree = &val
|
||||
m.SwapFreeBytes = &valBytes
|
||||
case "Dirty:":
|
||||
m.Dirty = &v
|
||||
m.Dirty = &val
|
||||
m.DirtyBytes = &valBytes
|
||||
case "Writeback:":
|
||||
m.Writeback = &v
|
||||
m.Writeback = &val
|
||||
m.WritebackBytes = &valBytes
|
||||
case "AnonPages:":
|
||||
m.AnonPages = &v
|
||||
m.AnonPages = &val
|
||||
m.AnonPagesBytes = &valBytes
|
||||
case "Mapped:":
|
||||
m.Mapped = &v
|
||||
m.Mapped = &val
|
||||
m.MappedBytes = &valBytes
|
||||
case "Shmem:":
|
||||
m.Shmem = &v
|
||||
m.Shmem = &val
|
||||
m.ShmemBytes = &valBytes
|
||||
case "Slab:":
|
||||
m.Slab = &v
|
||||
m.Slab = &val
|
||||
m.SlabBytes = &valBytes
|
||||
case "SReclaimable:":
|
||||
m.SReclaimable = &v
|
||||
m.SReclaimable = &val
|
||||
m.SReclaimableBytes = &valBytes
|
||||
case "SUnreclaim:":
|
||||
m.SUnreclaim = &v
|
||||
m.SUnreclaim = &val
|
||||
m.SUnreclaimBytes = &valBytes
|
||||
case "KernelStack:":
|
||||
m.KernelStack = &v
|
||||
m.KernelStack = &val
|
||||
m.KernelStackBytes = &valBytes
|
||||
case "PageTables:":
|
||||
m.PageTables = &v
|
||||
m.PageTables = &val
|
||||
m.PageTablesBytes = &valBytes
|
||||
case "NFS_Unstable:":
|
||||
m.NFSUnstable = &v
|
||||
m.NFSUnstable = &val
|
||||
m.NFSUnstableBytes = &valBytes
|
||||
case "Bounce:":
|
||||
m.Bounce = &v
|
||||
m.Bounce = &val
|
||||
m.BounceBytes = &valBytes
|
||||
case "WritebackTmp:":
|
||||
m.WritebackTmp = &v
|
||||
m.WritebackTmp = &val
|
||||
m.WritebackTmpBytes = &valBytes
|
||||
case "CommitLimit:":
|
||||
m.CommitLimit = &v
|
||||
m.CommitLimit = &val
|
||||
m.CommitLimitBytes = &valBytes
|
||||
case "Committed_AS:":
|
||||
m.CommittedAS = &v
|
||||
m.CommittedAS = &val
|
||||
m.CommittedASBytes = &valBytes
|
||||
case "VmallocTotal:":
|
||||
m.VmallocTotal = &v
|
||||
m.VmallocTotal = &val
|
||||
m.VmallocTotalBytes = &valBytes
|
||||
case "VmallocUsed:":
|
||||
m.VmallocUsed = &v
|
||||
m.VmallocUsed = &val
|
||||
m.VmallocUsedBytes = &valBytes
|
||||
case "VmallocChunk:":
|
||||
m.VmallocChunk = &v
|
||||
m.VmallocChunk = &val
|
||||
m.VmallocChunkBytes = &valBytes
|
||||
case "Percpu:":
|
||||
m.Percpu = &val
|
||||
m.PercpuBytes = &valBytes
|
||||
case "HardwareCorrupted:":
|
||||
m.HardwareCorrupted = &v
|
||||
m.HardwareCorrupted = &val
|
||||
m.HardwareCorruptedBytes = &valBytes
|
||||
case "AnonHugePages:":
|
||||
m.AnonHugePages = &v
|
||||
m.AnonHugePages = &val
|
||||
m.AnonHugePagesBytes = &valBytes
|
||||
case "ShmemHugePages:":
|
||||
m.ShmemHugePages = &v
|
||||
m.ShmemHugePages = &val
|
||||
m.ShmemHugePagesBytes = &valBytes
|
||||
case "ShmemPmdMapped:":
|
||||
m.ShmemPmdMapped = &v
|
||||
m.ShmemPmdMapped = &val
|
||||
m.ShmemPmdMappedBytes = &valBytes
|
||||
case "CmaTotal:":
|
||||
m.CmaTotal = &v
|
||||
m.CmaTotal = &val
|
||||
m.CmaTotalBytes = &valBytes
|
||||
case "CmaFree:":
|
||||
m.CmaFree = &v
|
||||
m.CmaFree = &val
|
||||
m.CmaFreeBytes = &valBytes
|
||||
case "HugePages_Total:":
|
||||
m.HugePagesTotal = &v
|
||||
m.HugePagesTotal = &val
|
||||
case "HugePages_Free:":
|
||||
m.HugePagesFree = &v
|
||||
m.HugePagesFree = &val
|
||||
case "HugePages_Rsvd:":
|
||||
m.HugePagesRsvd = &v
|
||||
m.HugePagesRsvd = &val
|
||||
case "HugePages_Surp:":
|
||||
m.HugePagesSurp = &v
|
||||
m.HugePagesSurp = &val
|
||||
case "Hugepagesize:":
|
||||
m.Hugepagesize = &v
|
||||
m.Hugepagesize = &val
|
||||
m.HugepagesizeBytes = &valBytes
|
||||
case "DirectMap4k:":
|
||||
m.DirectMap4k = &v
|
||||
m.DirectMap4k = &val
|
||||
m.DirectMap4kBytes = &valBytes
|
||||
case "DirectMap2M:":
|
||||
m.DirectMap2M = &v
|
||||
m.DirectMap2M = &val
|
||||
m.DirectMap2MBytes = &valBytes
|
||||
case "DirectMap1G:":
|
||||
m.DirectMap1G = &v
|
||||
m.DirectMap1G = &val
|
||||
m.DirectMap1GBytes = &valBytes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
2
vendor/github.com/prometheus/procfs/mountinfo.go
generated
vendored
2
vendor/github.com/prometheus/procfs/mountinfo.go
generated
vendored
@@ -109,7 +109,7 @@ func parseMountInfoString(mountString string) (*MountInfo, error) {
|
||||
if mountInfo[6] != "" {
|
||||
mount.OptionalFields, err = mountOptionsParseOptionalFields(mountInfo[6 : mountInfoLength-4])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: %w", ErrFileParse, err)
|
||||
return nil, fmt.Errorf("%w: %w", ErrFileParse, err)
|
||||
}
|
||||
}
|
||||
return mount, nil
|
||||
|
||||
11
vendor/github.com/prometheus/procfs/mountstats.go
generated
vendored
11
vendor/github.com/prometheus/procfs/mountstats.go
generated
vendored
@@ -88,7 +88,7 @@ type MountStatsNFS struct {
|
||||
// Statistics broken down by filesystem operation.
|
||||
Operations []NFSOperationStats
|
||||
// Statistics about the NFS RPC transport.
|
||||
Transport NFSTransportStats
|
||||
Transport []NFSTransportStats
|
||||
}
|
||||
|
||||
// mountStats implements MountStats.
|
||||
@@ -194,8 +194,6 @@ type NFSOperationStats struct {
|
||||
CumulativeTotalResponseMilliseconds uint64
|
||||
// Duration from when a request was enqueued to when it was completely handled.
|
||||
CumulativeTotalRequestMilliseconds uint64
|
||||
// The average time from the point the client sends RPC requests until it receives the response.
|
||||
AverageRTTMilliseconds float64
|
||||
// The count of operations that complete with tk_status < 0. These statuses usually indicate error conditions.
|
||||
Errors uint64
|
||||
}
|
||||
@@ -434,7 +432,7 @@ func parseMountStatsNFS(s *bufio.Scanner, statVersion string) (*MountStatsNFS, e
|
||||
return nil, err
|
||||
}
|
||||
|
||||
stats.Transport = *tstats
|
||||
stats.Transport = append(stats.Transport, *tstats)
|
||||
}
|
||||
|
||||
// When encountering "per-operation statistics", we must break this
|
||||
@@ -582,9 +580,6 @@ func parseNFSOperationStats(s *bufio.Scanner) ([]NFSOperationStats, error) {
|
||||
CumulativeTotalResponseMilliseconds: ns[6],
|
||||
CumulativeTotalRequestMilliseconds: ns[7],
|
||||
}
|
||||
if ns[0] != 0 {
|
||||
opStats.AverageRTTMilliseconds = float64(ns[6]) / float64(ns[0])
|
||||
}
|
||||
|
||||
if len(ns) > 8 {
|
||||
opStats.Errors = ns[8]
|
||||
@@ -632,7 +627,7 @@ func parseNFSTransportStats(ss []string, statVersion string) (*NFSTransportStats
|
||||
return nil, fmt.Errorf("%w: invalid NFS transport stats 1.1 statement: %v, protocol: %v", ErrFileParse, ss, protocol)
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: Unrecognized NFS transport stats version: %q, protocol: %v", ErrFileParse, statVersion, protocol)
|
||||
return nil, fmt.Errorf("%w: Unrecognized NFS transport stats version: %q, protocol: %v", ErrFileParse, statVersion, protocol)
|
||||
}
|
||||
|
||||
// Allocate enough for v1.1 stats since zero value for v1.1 stats will be okay
|
||||
|
||||
4
vendor/github.com/prometheus/procfs/net_conntrackstat.go
generated
vendored
4
vendor/github.com/prometheus/procfs/net_conntrackstat.go
generated
vendored
@@ -58,7 +58,7 @@ func readConntrackStat(path string) ([]ConntrackStatEntry, error) {
|
||||
|
||||
stat, err := parseConntrackStat(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot read file: %v: %w", ErrFileRead, path, err)
|
||||
return nil, fmt.Errorf("%w: Cannot read file: %v: %w", ErrFileRead, path, err)
|
||||
}
|
||||
|
||||
return stat, nil
|
||||
@@ -86,7 +86,7 @@ func parseConntrackStat(r io.Reader) ([]ConntrackStatEntry, error) {
|
||||
func parseConntrackStatEntry(fields []string) (*ConntrackStatEntry, error) {
|
||||
entries, err := util.ParseHexUint64s(fields)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse entry: %d: %w", ErrFileParse, entries, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse entry: %d: %w", ErrFileParse, entries, err)
|
||||
}
|
||||
numEntries := len(entries)
|
||||
if numEntries < 16 || numEntries > 17 {
|
||||
|
||||
46
vendor/github.com/prometheus/procfs/net_ip_socket.go
generated
vendored
46
vendor/github.com/prometheus/procfs/net_ip_socket.go
generated
vendored
@@ -50,10 +50,13 @@ type (
|
||||
// UsedSockets shows the total number of parsed lines representing the
|
||||
// number of used sockets.
|
||||
UsedSockets uint64
|
||||
// Drops shows the total number of dropped packets of all UPD sockets.
|
||||
Drops *uint64
|
||||
}
|
||||
|
||||
// netIPSocketLine represents the fields parsed from a single line
|
||||
// in /proc/net/{t,u}dp{,6}. Fields which are not used by IPSocket are skipped.
|
||||
// Drops is non-nil for udp{,6}, but nil for tcp{,6}.
|
||||
// For the proc file format details, see https://linux.die.net/man/5/proc.
|
||||
netIPSocketLine struct {
|
||||
Sl uint64
|
||||
@@ -66,6 +69,7 @@ type (
|
||||
RxQueue uint64
|
||||
UID uint64
|
||||
Inode uint64
|
||||
Drops *uint64
|
||||
}
|
||||
)
|
||||
|
||||
@@ -77,13 +81,14 @@ func newNetIPSocket(file string) (NetIPSocket, error) {
|
||||
defer f.Close()
|
||||
|
||||
var netIPSocket NetIPSocket
|
||||
isUDP := strings.Contains(file, "udp")
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetIPSocketLine(fields)
|
||||
line, err := parseNetIPSocketLine(fields, isUDP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -104,19 +109,25 @@ func newNetIPSocketSummary(file string) (*NetIPSocketSummary, error) {
|
||||
defer f.Close()
|
||||
|
||||
var netIPSocketSummary NetIPSocketSummary
|
||||
var udpPacketDrops uint64
|
||||
isUDP := strings.Contains(file, "udp")
|
||||
|
||||
lr := io.LimitReader(f, readLimit)
|
||||
s := bufio.NewScanner(lr)
|
||||
s.Scan() // skip first line with headers
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
line, err := parseNetIPSocketLine(fields)
|
||||
line, err := parseNetIPSocketLine(fields, isUDP)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
netIPSocketSummary.TxQueueLength += line.TxQueue
|
||||
netIPSocketSummary.RxQueueLength += line.RxQueue
|
||||
netIPSocketSummary.UsedSockets++
|
||||
if isUDP {
|
||||
udpPacketDrops += *line.Drops
|
||||
netIPSocketSummary.Drops = &udpPacketDrops
|
||||
}
|
||||
}
|
||||
if err := s.Err(); err != nil {
|
||||
return nil, err
|
||||
@@ -130,7 +141,7 @@ func parseIP(hexIP string) (net.IP, error) {
|
||||
var byteIP []byte
|
||||
byteIP, err := hex.DecodeString(hexIP)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse socket field in %q: %w", ErrFileParse, hexIP, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse socket field in %q: %w", ErrFileParse, hexIP, err)
|
||||
}
|
||||
switch len(byteIP) {
|
||||
case 4:
|
||||
@@ -144,12 +155,12 @@ func parseIP(hexIP string) (net.IP, error) {
|
||||
}
|
||||
return i, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("%s: Unable to parse IP %s: %w", ErrFileParse, hexIP, nil)
|
||||
return nil, fmt.Errorf("%w: Unable to parse IP %s: %v", ErrFileParse, hexIP, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// parseNetIPSocketLine parses a single line, represented by a list of fields.
|
||||
func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
func parseNetIPSocketLine(fields []string, isUDP bool) (*netIPSocketLine, error) {
|
||||
line := &netIPSocketLine{}
|
||||
if len(fields) < 10 {
|
||||
return nil, fmt.Errorf(
|
||||
@@ -167,7 +178,7 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
}
|
||||
|
||||
if line.Sl, err = strconv.ParseUint(s[0], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Unable to parse sl field in %q: %w", ErrFileParse, line.Sl, err)
|
||||
return nil, fmt.Errorf("%w: Unable to parse sl field in %q: %w", ErrFileParse, line.Sl, err)
|
||||
}
|
||||
// local_address
|
||||
l := strings.Split(fields[1], ":")
|
||||
@@ -178,7 +189,7 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
return nil, err
|
||||
}
|
||||
if line.LocalPort, err = strconv.ParseUint(l[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Unable to parse local_address port value line %q: %w", ErrFileParse, line.LocalPort, err)
|
||||
return nil, fmt.Errorf("%w: Unable to parse local_address port value line %q: %w", ErrFileParse, line.LocalPort, err)
|
||||
}
|
||||
|
||||
// remote_address
|
||||
@@ -190,12 +201,12 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
return nil, err
|
||||
}
|
||||
if line.RemPort, err = strconv.ParseUint(r[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse rem_address port value in %q: %w", ErrFileParse, line.RemPort, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse rem_address port value in %q: %w", ErrFileParse, line.RemPort, err)
|
||||
}
|
||||
|
||||
// st
|
||||
if line.St, err = strconv.ParseUint(fields[3], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse st value in %q: %w", ErrFileParse, line.St, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse st value in %q: %w", ErrFileParse, line.St, err)
|
||||
}
|
||||
|
||||
// tx_queue and rx_queue
|
||||
@@ -208,20 +219,29 @@ func parseNetIPSocketLine(fields []string) (*netIPSocketLine, error) {
|
||||
)
|
||||
}
|
||||
if line.TxQueue, err = strconv.ParseUint(q[0], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse tx_queue value in %q: %w", ErrFileParse, line.TxQueue, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse tx_queue value in %q: %w", ErrFileParse, line.TxQueue, err)
|
||||
}
|
||||
if line.RxQueue, err = strconv.ParseUint(q[1], 16, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse trx_queue value in %q: %w", ErrFileParse, line.RxQueue, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse trx_queue value in %q: %w", ErrFileParse, line.RxQueue, err)
|
||||
}
|
||||
|
||||
// uid
|
||||
if line.UID, err = strconv.ParseUint(fields[7], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse UID value in %q: %w", ErrFileParse, line.UID, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse UID value in %q: %w", ErrFileParse, line.UID, err)
|
||||
}
|
||||
|
||||
// inode
|
||||
if line.Inode, err = strconv.ParseUint(fields[9], 0, 64); err != nil {
|
||||
return nil, fmt.Errorf("%s: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err)
|
||||
return nil, fmt.Errorf("%w: Cannot parse inode value in %q: %w", ErrFileParse, line.Inode, err)
|
||||
}
|
||||
|
||||
// drops
|
||||
if isUDP {
|
||||
drops, err := strconv.ParseUint(fields[12], 0, 64)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: Cannot parse drops value in %q: %w", ErrFileParse, drops, err)
|
||||
}
|
||||
line.Drops = &drops
|
||||
}
|
||||
|
||||
return line, nil
|
||||
|
||||
4
vendor/github.com/prometheus/procfs/net_sockstat.go
generated
vendored
4
vendor/github.com/prometheus/procfs/net_sockstat.go
generated
vendored
@@ -69,7 +69,7 @@ func readSockstat(name string) (*NetSockstat, error) {
|
||||
|
||||
stat, err := parseSockstat(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: sockstats from %q: %w", ErrFileRead, name, err)
|
||||
return nil, fmt.Errorf("%w: sockstats from %q: %w", ErrFileRead, name, err)
|
||||
}
|
||||
|
||||
return stat, nil
|
||||
@@ -89,7 +89,7 @@ func parseSockstat(r io.Reader) (*NetSockstat, error) {
|
||||
// The remaining fields are key/value pairs.
|
||||
kvs, err := parseSockstatKVs(fields[1:])
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err)
|
||||
return nil, fmt.Errorf("%w: sockstat key/value pairs from %q: %w", ErrFileParse, s.Text(), err)
|
||||
}
|
||||
|
||||
// The first field is the protocol. We must trim its colon suffix.
|
||||
|
||||
2
vendor/github.com/prometheus/procfs/net_softnet.go
generated
vendored
2
vendor/github.com/prometheus/procfs/net_softnet.go
generated
vendored
@@ -64,7 +64,7 @@ func (fs FS) NetSoftnetStat() ([]SoftnetStat, error) {
|
||||
|
||||
entries, err := parseSoftnet(bytes.NewReader(b))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s: /proc/net/softnet_stat: %w", ErrFileParse, err)
|
||||
return nil, fmt.Errorf("%w: /proc/net/softnet_stat: %w", ErrFileParse, err)
|
||||
}
|
||||
|
||||
return entries, nil
|
||||
|
||||
119
vendor/github.com/prometheus/procfs/net_tls_stat.go
generated
vendored
Normal file
119
vendor/github.com/prometheus/procfs/net_tls_stat.go
generated
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
// Copyright 2023 Prometheus Team
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package procfs
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TLSStat struct represents data in /proc/net/tls_stat.
|
||||
// See https://docs.kernel.org/networking/tls.html#statistics
|
||||
type TLSStat struct {
|
||||
// number of TX sessions currently installed where host handles cryptography
|
||||
TLSCurrTxSw int
|
||||
// number of RX sessions currently installed where host handles cryptography
|
||||
TLSCurrRxSw int
|
||||
// number of TX sessions currently installed where NIC handles cryptography
|
||||
TLSCurrTxDevice int
|
||||
// number of RX sessions currently installed where NIC handles cryptography
|
||||
TLSCurrRxDevice int
|
||||
//number of TX sessions opened with host cryptography
|
||||
TLSTxSw int
|
||||
//number of RX sessions opened with host cryptography
|
||||
TLSRxSw int
|
||||
// number of TX sessions opened with NIC cryptography
|
||||
TLSTxDevice int
|
||||
// number of RX sessions opened with NIC cryptography
|
||||
TLSRxDevice int
|
||||
// record decryption failed (e.g. due to incorrect authentication tag)
|
||||
TLSDecryptError int
|
||||
// number of RX resyncs sent to NICs handling cryptography
|
||||
TLSRxDeviceResync int
|
||||
// number of RX records which had to be re-decrypted due to TLS_RX_EXPECT_NO_PAD mis-prediction. Note that this counter will also increment for non-data records.
|
||||
TLSDecryptRetry int
|
||||
// number of data RX records which had to be re-decrypted due to TLS_RX_EXPECT_NO_PAD mis-prediction.
|
||||
TLSRxNoPadViolation int
|
||||
}
|
||||
|
||||
// NewTLSStat reads the tls_stat statistics.
|
||||
func NewTLSStat() (TLSStat, error) {
|
||||
fs, err := NewFS(DefaultMountPoint)
|
||||
if err != nil {
|
||||
return TLSStat{}, err
|
||||
}
|
||||
|
||||
return fs.NewTLSStat()
|
||||
}
|
||||
|
||||
// NewTLSStat reads the tls_stat statistics.
|
||||
func (fs FS) NewTLSStat() (TLSStat, error) {
|
||||
file, err := os.Open(fs.proc.Path("net/tls_stat"))
|
||||
if err != nil {
|
||||
return TLSStat{}, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var (
|
||||
tlsstat = TLSStat{}
|
||||
s = bufio.NewScanner(file)
|
||||
)
|
||||
|
||||
for s.Scan() {
|
||||
fields := strings.Fields(s.Text())
|
||||
|
||||
if len(fields) != 2 {
|
||||
return TLSStat{}, fmt.Errorf("%w: %q line %q", ErrFileParse, file.Name(), s.Text())
|
||||
}
|
||||
|
||||
name := fields[0]
|
||||
value, err := strconv.Atoi(fields[1])
|
||||
if err != nil {
|
||||
return TLSStat{}, err
|
||||
}
|
||||
|
||||
switch name {
|
||||
case "TlsCurrTxSw":
|
||||
tlsstat.TLSCurrTxSw = value
|
||||
case "TlsCurrRxSw":
|
||||
tlsstat.TLSCurrRxSw = value
|
||||
case "TlsCurrTxDevice":
|
||||
tlsstat.TLSCurrTxDevice = value
|
||||
case "TlsCurrRxDevice":
|
||||
tlsstat.TLSCurrRxDevice = value
|
||||
case "TlsTxSw":
|
||||
tlsstat.TLSTxSw = value
|
||||
case "TlsRxSw":
|
||||
tlsstat.TLSRxSw = value
|
||||
case "TlsTxDevice":
|
||||
tlsstat.TLSTxDevice = value
|
||||
case "TlsRxDevice":
|
||||
tlsstat.TLSRxDevice = value
|
||||
case "TlsDecryptError":
|
||||
tlsstat.TLSDecryptError = value
|
||||
case "TlsRxDeviceResync":
|
||||
tlsstat.TLSRxDeviceResync = value
|
||||
case "TlsDecryptRetry":
|
||||
tlsstat.TLSDecryptRetry = value
|
||||
case "TlsRxNoPadViolation":
|
||||
tlsstat.TLSRxNoPadViolation = value
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return tlsstat, s.Err()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user