package mtproto

import (
	

	
	
	

	
)

// connect establishes connection using configured transport, creating
// new auth key if needed.
func ( *Conn) ( context.Context) ( error) {
	,  := context.WithTimeout(, .dialTimeout)
	defer ()

	,  := .dialer()
	if  != nil {
		return errors.Wrap(, "dial failed")
	}
	.conn = 
	defer func() {
		if  != nil {
			multierr.AppendInto(&, .Close())
		}
	}()

	 := .session()
	if .Key.Zero() {
		.log.Info("Generating new auth key")
		 := .clock.Now()
		if  := .createAuthKey();  != nil {
			return errors.Wrap(, "create auth key")
		}

		.log.Info("Auth key generated",
			zap.Duration("duration", .clock.Now().Sub()),
		)
		return nil
	}

	.log.Info("Key already exists")
	if .ID == 0 {
		// NB: Telegram can return 404 error if session id is zero.
		//
		// See https://github.com/gotd/td/issues/107.
		.log.Debug("Generating new session id")
		if  := .newSessionID();  != nil {
			return 
		}
	}

	return nil
}

// createAuthKey generates new authorization key.
func ( *Conn) ( context.Context) error {
	// Grab exclusive lock for writing.
	// It prevents message sending during key regeneration if server forgot current auth key.
	.exchangeLock.Lock()
	defer .exchangeLock.Unlock()

	if  := .log.Check(zap.DebugLevel, "Initializing new key exchange");  != nil {
		// Useful for debugging i/o timeout errors on tcp reads or writes.
		 := []zap.Field{
			zap.Duration("timeout", .exchangeTimeout),
		}
		if ,  := .Deadline();  {
			 = append(, zap.Time("context_deadline", ))
		}
		.Write(...)
	}

	,  := exchange.NewExchanger(.conn, .dcID).
		WithClock(.clock).
		WithLogger(.log.Named("exchange")).
		WithTimeout(.exchangeTimeout).
		WithRand(.rand).
		Client(.rsaPublicKeys).Run()
	if  != nil {
		return 
	}

	.sessionMux.Lock()
	.authKey = .AuthKey
	.sessionID = .SessionID
	.salt = .ServerSalt
	.sessionMux.Unlock()

	return nil
}