mirror of
https://github.com/lukaszraczylo/go-telegram.git
synced 2026-06-05 22:43:59 +00:00
Initial release of go-telegram
A fully-generated, strongly-typed Go client for the Telegram Bot API. * 176 methods + 301 types generated from Bot API v10.0 * 1408 auto-generated tests (8 scenarios per method) * Typed unions throughout — no 'any' in the public surface * Pluggable HTTP transport and JSON codec (default goccy/go-json) * Built-in retry middleware honouring Telegram's retry_after * Generic dispatcher with filters and conversation handlers * Self-verifying codegen pipeline (regen → audit → emit → run tests) * 14 example bots covering common patterns
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
// Package api contains the Telegram Bot API types and method wrappers.
|
||||
// Most of the package is generated by cmd/genapi from internal/spec/api.json;
|
||||
// this file holds the runtime types that are intentionally hand-coded.
|
||||
//
|
||||
// InputFile carries either a local upload (Reader+Filename) or a reference
|
||||
// to a previously-uploaded file (file_id) / URL Telegram can fetch. It is
|
||||
// not a pure JSON type, so the codegen skips it (see runtimeTypes in
|
||||
// cmd/genapi/emitter.go).
|
||||
//
|
||||
// ResponseParameters mirrors client.ResponseParameters so callers importing
|
||||
// only `api` can access retry_after and migrate_to_chat_id without pulling
|
||||
// in the client package.
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/goccy/go-json"
|
||||
"io"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// InputFile carries either a file path (for upload) or a Telegram file_id
|
||||
// / URL string (for reuse). When PathOrID names a local file, the request
|
||||
// is sent as multipart/form-data; otherwise the value is sent inline.
|
||||
type InputFile struct {
|
||||
// PathOrID is one of: an absolute or relative filesystem path, a
|
||||
// previously-uploaded Telegram file_id, or an HTTPS URL Telegram
|
||||
// can fetch.
|
||||
PathOrID string
|
||||
// Reader, when non-nil, is used as the file content (Filename names it).
|
||||
Reader io.Reader
|
||||
// Filename is the upload filename used when Reader is set.
|
||||
Filename string
|
||||
}
|
||||
|
||||
// IsLocalUpload reports whether this InputFile triggers a multipart upload.
|
||||
func (f *InputFile) IsLocalUpload() bool {
|
||||
if f == nil {
|
||||
return false
|
||||
}
|
||||
return f.Reader != nil
|
||||
}
|
||||
|
||||
// ResponseParameters is the optional metadata Telegram includes on certain
|
||||
// failures. The most common is RetryAfter (seconds) on 429 responses.
|
||||
//
|
||||
// https://core.telegram.org/bots/api#responseparameters
|
||||
type ResponseParameters struct {
|
||||
MigrateToChatID int64 `json:"migrate_to_chat_id,omitempty"`
|
||||
RetryAfter int `json:"retry_after,omitempty"`
|
||||
}
|
||||
|
||||
// ChatID identifies a chat by either numeric id or "@username". The Telegram
|
||||
// Bot API spells the same field as either an integer or a string; ChatID
|
||||
// preserves both forms with explicit constructors and a custom MarshalJSON
|
||||
// so callers never see `any` at the source level.
|
||||
type ChatID struct {
|
||||
int64Set bool
|
||||
intID int64
|
||||
username string
|
||||
}
|
||||
|
||||
// ChatIDFromInt builds a ChatID for a numeric chat identifier (e.g. -1001234567890).
|
||||
func ChatIDFromInt(id int64) ChatID { return ChatID{int64Set: true, intID: id} }
|
||||
|
||||
// ChatIDFromUsername builds a ChatID for a public chat (e.g. "@channel").
|
||||
// The leading "@" is required by Telegram for usernames.
|
||||
func ChatIDFromUsername(name string) ChatID { return ChatID{username: name} }
|
||||
|
||||
// IsZero reports whether c carries no value.
|
||||
func (c ChatID) IsZero() bool { return !c.int64Set && c.username == "" }
|
||||
|
||||
// String returns the wire form (decimal integer or "@name") for use in
|
||||
// multipart bodies.
|
||||
func (c ChatID) String() string {
|
||||
if c.int64Set {
|
||||
return strconv.FormatInt(c.intID, 10)
|
||||
}
|
||||
return c.username
|
||||
}
|
||||
|
||||
// MarshalJSON emits either a JSON number (integer form) or a JSON string
|
||||
// (@username form). Empty values marshal as "null".
|
||||
func (c ChatID) MarshalJSON() ([]byte, error) {
|
||||
if c.int64Set {
|
||||
return []byte(strconv.FormatInt(c.intID, 10)), nil
|
||||
}
|
||||
if c.username != "" {
|
||||
return json.Marshal(c.username)
|
||||
}
|
||||
return []byte("null"), nil
|
||||
}
|
||||
|
||||
// UnmarshalJSON accepts either a JSON number or a JSON string.
|
||||
func (c *ChatID) UnmarshalJSON(data []byte) error {
|
||||
data = bytes.TrimSpace(data)
|
||||
if len(data) == 0 || bytes.Equal(data, []byte("null")) {
|
||||
*c = ChatID{}
|
||||
return nil
|
||||
}
|
||||
if data[0] == '"' {
|
||||
var s string
|
||||
if err := json.Unmarshal(data, &s); err != nil {
|
||||
return err
|
||||
}
|
||||
*c = ChatIDFromUsername(s)
|
||||
return nil
|
||||
}
|
||||
var n int64
|
||||
if err := json.Unmarshal(data, &n); err != nil {
|
||||
return fmt.Errorf("ChatID: %w", err)
|
||||
}
|
||||
*c = ChatIDFromInt(n)
|
||||
return nil
|
||||
}
|
||||
|
||||
// MessageOrBool wraps the "Message or True" return shape Telegram uses on
|
||||
// edit methods (editMessageText, editMessageCaption, etc.). When the bot
|
||||
// edits a regular chat message, Message is non-nil; when it edits an
|
||||
// inline message, OK is true.
|
||||
type MessageOrBool struct {
|
||||
Message *Message
|
||||
OK bool
|
||||
}
|
||||
|
||||
// UnmarshalJSON decodes either {...} into Message or `true`/`false` into OK.
|
||||
func (m *MessageOrBool) UnmarshalJSON(data []byte) error {
|
||||
data = bytes.TrimSpace(data)
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
}
|
||||
if data[0] == '{' {
|
||||
m.Message = new(Message)
|
||||
return json.Unmarshal(data, m.Message)
|
||||
}
|
||||
var b bool
|
||||
if err := json.Unmarshal(data, &b); err != nil {
|
||||
return fmt.Errorf("MessageOrBool: %w", err)
|
||||
}
|
||||
m.OK = b
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user