You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
62 lines
1.8 KiB
62 lines
1.8 KiB
package telegram |
|
|
|
import ( |
|
"context" |
|
"strings" |
|
|
|
"go.uber.org/zap" |
|
|
|
"github.com/gotd/td/bin" |
|
"github.com/gotd/td/tg" |
|
"github.com/gotd/td/tgerr" |
|
) |
|
|
|
// API returns *tg.Client for calling raw MTProto methods. |
|
func (c *Client) API() *tg.Client { |
|
return c.tg |
|
} |
|
|
|
// Invoke invokes raw MTProto RPC method. It sends input and decodes result |
|
// into output. |
|
func (c *Client) Invoke(ctx context.Context, input bin.Encoder, output bin.Decoder) error { |
|
return c.invoker.Invoke(ctx, input, output) |
|
} |
|
|
|
// invokeDirect directly invokes RPC method, automatically handling datacenter redirects. |
|
func (c *Client) invokeDirect(ctx context.Context, input bin.Encoder, output bin.Decoder) error { |
|
if err := c.invokeConn(ctx, input, output); err != nil { |
|
// Handling datacenter migration request. |
|
if rpcErr, ok := tgerr.As(err); ok && strings.HasSuffix(rpcErr.Type, "_MIGRATE") { |
|
targetDC := rpcErr.Argument |
|
log := c.log.With( |
|
zap.String("error_type", rpcErr.Type), |
|
zap.Int("target_dc", targetDC), |
|
) |
|
// If migration error is FILE_MIGRATE or STATS_MIGRATE, then the method |
|
// called by authorized client, so we should try to transfer auth to new DC |
|
// and create new connection. |
|
if rpcErr.IsOneOf("FILE_MIGRATE", "STATS_MIGRATE") { |
|
log.Debug("Invoking on target DC") |
|
return c.invokeSub(ctx, targetDC, input, output) |
|
} |
|
|
|
// Otherwise we should change primary DC. |
|
log.Info("Migrating to target DC") |
|
return c.invokeMigrate(ctx, targetDC, input, output) |
|
} |
|
|
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// invokeConn directly invokes RPC call on primary connection without any |
|
// additional handling. |
|
func (c *Client) invokeConn(ctx context.Context, input bin.Encoder, output bin.Decoder) error { |
|
c.connMux.Lock() |
|
conn := c.conn |
|
c.connMux.Unlock() |
|
|
|
return conn.Invoke(ctx, input, output) |
|
}
|
|
|