package peer import ( "context" "strings" "github.com/go-faster/errors" "github.com/gotd/td/internal/ascii" "github.com/gotd/td/telegram/internal/deeplink" "github.com/gotd/td/tg" ) // Promise is a peer promise. type Promise func(ctx context.Context) (tg.InputPeerClass, error) // Resolve uses given string to create new peer promise. // It resolves peer of message using given Resolver. // Input examples: // // @telegram // telegram // t.me/telegram // https://t.me/telegram // tg:resolve?domain=telegram // tg://resolve?domain=telegram // +13115552368 // +1 (311) 555-0123 // +1 311 555-6162 // 13115556162 // func Resolve(r Resolver, from string) Promise { from = strings.TrimSpace(from) if deeplink.IsDeeplinkLike(from) { return ResolveDeeplink(r, from) } if isPhoneNumber(from) { return ResolvePhone(r, from) } return ResolveDomain(r, from) } func isPhoneNumber(s string) bool { if s == "" { return false } r := rune(s[0]) return r == '+' || ascii.IsDigit(r) } func cleanupPhone(phone string) string { clean := strings.Builder{} clean.Grow(len(phone) + 1) for _, ch := range phone { if ascii.IsDigit(ch) { clean.WriteRune(ch) } } return clean.String() } // ResolvePhone uses given phone to create new peer promise. // It resolves peer of message using given Resolver. // Input example: // // +13115552368 // +1 (311) 555-0123 // +1 311 555-6162 // 13115556162 // // Note that Telegram represents phone numbers according to the E.164 standard // without the plus sign (”+”) prefix. The resolver therefore takes an easy // route and just deletes any non-digit symbols from phone number string. func ResolvePhone(r Resolver, phone string) Promise { return func(ctx context.Context) (tg.InputPeerClass, error) { return r.ResolvePhone(ctx, cleanupPhone(phone)) } } // ResolveDomain uses given domain to create new peer promise. // It resolves peer of message using given Resolver. // Can has prefix with @ or not. // Input examples: // // @telegram // telegram // func ResolveDomain(r Resolver, domain string) Promise { return func(ctx context.Context) (tg.InputPeerClass, error) { domain = strings.TrimPrefix(domain, "@") if err := validateDomain(domain); err != nil { return nil, errors.Wrap(err, "validate domain") } return r.ResolveDomain(ctx, domain) } } func validateDomain(domain string) error { return deeplink.ValidateDomain(domain) } // ResolveDeeplink uses given deeplink to create new peer promise. // Deeplink is a URL like https://t.me/telegram. // It resolves peer of message using given Resolver. // Input examples: // // t.me/telegram // https://t.me/telegram // tg:resolve?domain=telegram // tg://resolve?domain=telegram // func ResolveDeeplink(r Resolver, u string) Promise { return func(ctx context.Context) (tg.InputPeerClass, error) { link, err := deeplink.Expect(u, deeplink.Resolve) if err != nil { return nil, err } domain := link.Args.Get("domain") if err := validateDomain(domain); err != nil { return nil, errors.Wrap(err, "validate domain") } return r.ResolveDomain(ctx, domain) } }