Skip to main content

Overview

Telegram uses unique AccessHash values to identify users and channels. Without these hashes, you cannot interact with them (send messages, join, etc.). Gogram automatically caches these InputPeer objects whenever it encounters them in updates or API responses. The cache stores:
  • Users: ID mapped to Access Hash.
  • Channels: ID mapped to Access Hash.
  • Usernames: Username mapped to ID (for quick lookup).

Persistence

By default, Gogram persists the cache to a file named cache<session_name>.db in the working directory. This ensures that even after a restart, your bot remembers users and channels it has interacted with.

File Storage (Default)

// Default behavior: persists to ./cache_my_session.db
client, _ := telegram.NewClient(telegram.ClientConfig{
    SessionName: "my_session",
})

In-Memory Only

If you don’t want to persist the cache to disk (e.g., for short-lived sessions), use MemorySession or configure the cache explicitly.
client, _ := telegram.NewClient(telegram.ClientConfig{
    DisableCache: false, // Ensure cache is enabled
    Cache: telegram.NewCache("", &telegram.CacheConfig{
        Memory: true, // Do not write to disk
    }),
})

Custom Storage

The CacheStorage interface allows you to define how peer data (users, channels, access hashes) is persisted. By default, Gogram uses a local file (cache.db), but you can implement this interface to use any backend.

The Interface

Your custom storage must implement the telegram.CacheStorage interface:
type CacheStorage interface {
    // Read should retrieve the cache from your storage and return it.
    // If no cache exists, return an empty initialized InputPeerCache or error.
    Read() (*telegram.InputPeerCache, error)

    // Write is called periodically to save the current cache state.
    Write(data *telegram.InputPeerCache) error

    // Close is called when the client shuts down.
    Close() error
}

The Data Structure

The methods interact with the InputPeerCache struct, which holds the mapping of IDs to Access Hashes.
type InputPeerCache struct {
    // Map of Channel ID -> Access Hash
    InputChannels map[int64]int64  `json:"channels,omitempty"`
    
    // Map of User ID -> Access Hash
    InputUsers    map[int64]int64  `json:"users,omitempty"`
    
    // Map of Username -> Peer ID (User or Channel)
    UsernameMap   map[string]int64 `json:"username_map,omitempty"`
    
    // The ID of the user/bot this cache belongs to
    OwnerID       int64            `json:"owner_id,omitempty"`
}

Example: Redis Implementation

Here is a conceptual example of how you might implement a Redis-based cache storage.
import (
    "context"
    "encoding/json"
    "github.com/redis/go-redis/v9"
    "github.com/amarnathcjd/gogram/telegram"
)

type RedisCache struct {
    client *redis.Client
    key    string
}

func NewRedisCache(addr, password, key string) *RedisCache {
    rdb := redis.NewClient(&redis.Options{
        Addr:     addr,
        Password: password,
    })
    return &RedisCache{client: rdb, key: key}
}

// Read retrieves the JSON blob from Redis and unmarshals it
func (r *RedisCache) Read() (*telegram.InputPeerCache, error) {
    val, err := r.client.Get(context.Background(), r.key).Result()
    if err == redis.Nil {
        // Cache misses are fine, return empty structure
        return &telegram.InputPeerCache{
            InputChannels: make(map[int64]int64),
            InputUsers:    make(map[int64]int64),
            UsernameMap:   make(map[string]int64),
        }, nil
    }
    if err != nil {
        return nil, err
    }

    var data telegram.InputPeerCache
    if err := json.Unmarshal([]byte(val), &data); err != nil {
        return nil, err
    }
    return &data, nil
}

// Write serializes the cache and saves it to Redis
func (r *RedisCache) Write(data *telegram.InputPeerCache) error {
    bytes, err := json.Marshal(data)
    if err != nil {
        return err
    }
    return r.client.Set(context.Background(), r.key, bytes, 0).Err()
}

func (r *RedisCache) Close() error {
    return r.client.Close()
}

Usage

To use your custom storage, pass it to the NewClient configuration:
redisCache := NewRedisCache("localhost:6379", "", "my_bot_cache")

client, err := telegram.NewClient(telegram.ClientConfig{
    AppID:   12345,
    AppHash: "abcdef",
    // Configure the cache with your storage
    Cache: telegram.NewCache("cache_name", &telegram.CacheConfig{
        Storage: redisCache,
    }),
})

Managing Cache

Binding to User

The cache is bound to the current authorized user (bot or user). If you switch sessions or authorize a different user, Gogram handles rebinding automatically.

Cache Size Limit

To prevent the cache from growing indefinitely, you can set a maximum size. When the limit is reached, older entries are evicted.
client.Cache = telegram.NewCache("cache.db", &telegram.CacheConfig{
    MaxSize: 10000, // Max 10,000 users/channels
})

Clearing Cache

client.Cache.Clear() // Removes all entries from memory (and disk on next write)

APIs

Lookup by Username

If you need to find a peer by username without making an API call (if it’s already cached):
peerID, accessHash, isChannel, found := client.Cache.LookupUsername("username")
if found {
    // specific logic
}

Getting InputPeer

The client.GetInputPeer(id) method uses the cache to resolve IDs to InputPeer objects.
peer, err := client.GetInputPeer(123456789)

Export/Import

You can manually export and import the cache as JSON.
data, err := client.Cache.ExportJSON()
// ... save data ...
err = client.Cache.ImportJSON(data)