Documentation ¶
Overview ¶
Package storage contains common structures for iterating over peer storage.
Index ¶
- Constants
- Variables
- func ForEach(ctx context.Context, iterator PeerIterator, cb func(Peer) error) error
- func UpdateHook(next telegram.UpdateHandler, storage PeerStorage) telegram.UpdateHandler
- type Peer
- func (p Peer) AsInputChannel() (*tg.InputChannel, bool)
- func (p Peer) AsInputPeer() tg.InputPeerClass
- func (p Peer) AsInputUser() (*tg.InputUser, bool)
- func (p *Peer) FromChat(chat tg.ChatClass) bool
- func (p *Peer) FromInputPeer(input tg.InputPeerClass) error
- func (p *Peer) FromUser(user tg.UserClass) bool
- func (p *Peer) Keys() []string
- func (p Peer) Marshal(e *jx.Encoder) error
- func (p Peer) MarshalJSON() ([]byte, error)
- func (p Peer) String() string
- func (p *Peer) Unmarshal(d *jx.Decoder) error
- func (p *Peer) UnmarshalJSON(data []byte) error
- type PeerCollector
- type PeerIterator
- type PeerKey
- type PeerStorage
- type ResolverCache
Examples ¶
Constants ¶
const LatestVersion = 2
LatestVersion is a latest supported version of data.
Variables ¶
var ErrPeerNotFound = errors.New("peer not found")
ErrPeerNotFound is a special error to return when peer not found.
var ErrPeerUnmarshalMustInvalidate = errors.New("outdated data for Peer (cache miss, must invalidate)")
ErrPeerUnmarshalMustInvalidate means that persisted Peer is outdated and must be invalidated.
var PeerKeyPrefix = []byte("peer") // nolint:gochecknoglobals
PeerKeyPrefix is a key prefix of peer key.
Functions ¶
func UpdateHook ¶
func UpdateHook(next telegram.UpdateHandler, storage PeerStorage) telegram.UpdateHandler
UpdateHook creates update hook, to collect peer data from updates.
Example ¶
package main import ( "context" "fmt" "os" "os/signal" pebbledb "github.com/cockroachdb/pebble" "github.com/go-faster/errors" "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/message" "github.com/gotd/td/tg" "github.com/t2bot/gotd-contrib/pebble" "github.com/t2bot/gotd-contrib/storage" ) func updatesHook(ctx context.Context) error { db, err := pebbledb.Open("pebble.db", &pebbledb.Options{}) if err != nil { return errors.Errorf("create pebble storage: %w", err) } s := pebble.NewPeerStorage(db) dispatcher := tg.NewUpdateDispatcher() handler := storage.UpdateHook(dispatcher, s) client, err := telegram.ClientFromEnvironment(telegram.Options{ UpdateHandler: handler, }) if err != nil { return errors.Errorf("create client: %w", err) } raw := tg.NewClient(client) sender := message.NewSender(raw) dispatcher.OnNewMessage(func(ctx context.Context, e tg.Entities, update *tg.UpdateNewMessage) error { msg, ok := update.Message.(*tg.Message) if !ok { return nil } // Use PeerID to find peer because *Short updates does not contain any entities, so it necessary to // store some entities. // Storage can be filled using PeerCollector. p, err := storage.FindPeer(ctx, s, msg.GetPeerID()) if err != nil { return err } _, err = sender.To(p.AsInputPeer()).Text(ctx, msg.GetMessage()) return err }) return client.Run(ctx, func(ctx context.Context) error { return telegram.RunUntilCanceled(ctx, client) }) } func main() { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() if err := updatesHook(ctx); err != nil { _, _ = fmt.Fprintf(os.Stderr, "%+v\n", err) os.Exit(1) } }
Output:
Types ¶
type Peer ¶
type Peer struct { Version int Key dialogs.DialogKey CreatedAt time.Time User *tg.User Chat *tg.Chat Channel *tg.Channel Metadata map[string]any }
Peer is abstraction for persisted peer object.
Note: unmarshal error ErrPeerUnmarshalMustInvalidate MUST be considered as cache miss and cache entry MUST be invalidated.
The only valid way to marshal and unmarshal Peer is to use UnmarshalJSON, MarshalJSON.
func (Peer) AsInputChannel ¶
func (p Peer) AsInputChannel() (*tg.InputChannel, bool)
AsInputChannel tries to convert peer to *tg.InputChannel.
func (Peer) AsInputPeer ¶
func (p Peer) AsInputPeer() tg.InputPeerClass
AsInputPeer tries to convert peer to tg.InputPeerClass.
func (Peer) AsInputUser ¶
AsInputUser tries to convert peer to *tg.InputUser.
func (*Peer) FromInputPeer ¶
func (p *Peer) FromInputPeer(input tg.InputPeerClass) error
FromInputPeer fills Peer object using given tg.InputPeerClass.
func (*Peer) Keys ¶
Keys returns list of all associated keys (phones, usernames, etc.) stored in the peer.
func (Peer) MarshalJSON ¶
func (*Peer) UnmarshalJSON ¶
type PeerCollector ¶
type PeerCollector struct {
// contains filtered or unexported fields
}
PeerCollector is a simple helper to collect peers from different sources.
func CollectPeers ¶
func CollectPeers(storage PeerStorage) PeerCollector
CollectPeers creates new PeerCollector.
Example ¶
package main import ( "context" "fmt" "os" "os/signal" pebbledb "github.com/cockroachdb/pebble" "github.com/go-faster/errors" "github.com/gotd/td/telegram" "github.com/gotd/td/telegram/query" "github.com/gotd/td/tg" "github.com/t2bot/gotd-contrib/pebble" "github.com/t2bot/gotd-contrib/storage" ) func peerCollector(ctx context.Context) error { db, err := pebbledb.Open("pebble.db", &pebbledb.Options{}) if err != nil { return errors.Errorf("create pebble storage: %w", err) } s := pebble.NewPeerStorage(db) collector := storage.CollectPeers(s) client, err := telegram.ClientFromEnvironment(telegram.Options{}) if err != nil { return errors.Errorf("create client: %w", err) } raw := tg.NewClient(client) return client.Run(ctx, func(ctx context.Context) error { // Fills storage with user dialogs peers metadata. return collector.Dialogs(ctx, query.GetDialogs(raw).Iter()) }) } func main() { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() if err := peerCollector(ctx); err != nil { _, _ = fmt.Fprintf(os.Stderr, "%+v\n", err) os.Exit(1) } }
Output:
func (PeerCollector) Contacts ¶
func (c PeerCollector) Contacts(ctx context.Context, contacts *tg.ContactsContacts) error
Contacts collects peers from contacts iterator.
func (PeerCollector) Participants ¶
func (c PeerCollector) Participants(ctx context.Context, iter *participants.Iterator) error
Participants collects peers from participants iterator.
type PeerIterator ¶
PeerIterator is a peer iterator.
type PeerKey ¶
PeerKey is unique key of peer object.
type PeerStorage ¶
type PeerStorage interface { // Add adds given peer to the storage. Add(ctx context.Context, value Peer) error // Find finds peer using given key. // If peer not found, it returns ErrPeerNotFound error. Find(ctx context.Context, key PeerKey) (Peer, error) // Assign adds given peer to the storage and associates it to the given key. Assign(ctx context.Context, key string, value Peer) error // Resolve finds peer using associated key. // If peer not found, it returns ErrPeerNotFound error. Resolve(ctx context.Context, key string) (Peer, error) // Iterate creates and returns new PeerIterator. Iterate(ctx context.Context) (PeerIterator, error) }
PeerStorage is abstraction for peer storage.
type ResolverCache ¶
type ResolverCache struct {
// contains filtered or unexported fields
}
ResolverCache is a peer.Resolver cache implemented using peer storage.
Example ¶
package main import ( "context" "fmt" "os" "os/signal" pebbledb "github.com/cockroachdb/pebble" "github.com/go-faster/errors" "github.com/gotd/td/telegram/message" "github.com/gotd/td/telegram/message/peer" "github.com/gotd/td/tg" "github.com/gotd/td/telegram" "github.com/t2bot/gotd-contrib/pebble" "github.com/t2bot/gotd-contrib/storage" ) func resolverCache(ctx context.Context) error { db, err := pebbledb.Open("pebble.db", &pebbledb.Options{}) if err != nil { return errors.Errorf("create pebble storage: %w", err) } client, err := telegram.ClientFromEnvironment(telegram.Options{}) if err != nil { return errors.Errorf("create client: %w", err) } return client.Run(ctx, func(ctx context.Context) error { raw := tg.NewClient(client) resolver := storage.NewResolverCache(peer.Plain(raw), pebble.NewPeerStorage(db)) s := message.NewSender(raw).WithResolver(resolver) _, err := s.Resolve("durov").Text(ctx, "Hi!") return err }) } func main() { ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) defer cancel() if err := resolverCache(ctx); err != nil { _, _ = fmt.Fprintf(os.Stderr, "%+v\n", err) os.Exit(1) } }
Output:
func NewResolverCache ¶
func NewResolverCache(next peer.Resolver, storage PeerStorage) ResolverCache
NewResolverCache creates new ResolverCache.
func (ResolverCache) ResolveDomain ¶
func (r ResolverCache) ResolveDomain(ctx context.Context, domain string) (tg.InputPeerClass, error)
ResolveDomain implements peer.Resolver
func (ResolverCache) ResolvePhone ¶
func (r ResolverCache) ResolvePhone(ctx context.Context, phone string) (tg.InputPeerClass, error)
ResolvePhone implements peer.Resolver