package mtproto

import (
	
	

	

	
)

func ( *Conn) ( context.Context,  int64,  int32,  bin.Encoder) error {
	return .write(, , , )
}

func ( *Conn) ( context.Context,  bin.Encoder) error {
	,  := .nextMsgSeq(false)
	return .write(, , , )
}

var bufPool = bin.NewPool(0)

// slowWriteThreshold is the duration after which a single write (lock
// acquisition + encrypt + transport send) is considered suspiciously slow and
// logged at warning level. A blocked or slow write is the primary signature of
// a half-open connection where updates are still received but requests can no
// longer be issued.
const slowWriteThreshold = 3 * time.Second

func ( *Conn) ( context.Context,  int64,  int32,  bin.Encoder) error {
	 := .clock.Now()

	// Grab shared lock for writing.
	// It prevents message sending during key regeneration if server forgot current auth key.
	//
	// Note: if key exchange holds the write lock (see createAuthKey), every
	// send — including pings, acks and content requests — blocks here. Tracing
	// the lock acquisition separately lets us distinguish "stuck on exchange
	// lock" from "stuck on transport send".
	.exchangeLock.RLock()
	defer .exchangeLock.RUnlock()

	 := .clock.Now()
	if  := .Sub();  > slowWriteThreshold {
		.logWithTypeID(peekID()).Warn(, "Slow write: waited for exchange lock",
			log.Int64("msg_id", ),
			log.Int32("seq_no", ),
			log.Duration("waited", ),
		)
	}

	 := bufPool.Get()
	defer bufPool.Put()

	if  := .newEncryptedMessage(, , , );  != nil {
		return 
	}

	 := .logWithTypeID(peekID()).With(
		log.Int64("msg_id", ),
		log.Int32("seq_no", ),
		log.Int("size_bytes", .Len()),
	)
	.Debug(, "Sending message")

	if  := .conn.Send(, );  != nil {
		.Debug(, "Send failed", log.Error(), log.Duration("elapsed", .clock.Now().Sub()))
		return 
	}

	if  := .clock.Now().Sub();  > slowWriteThreshold {
		.Warn(, "Slow write: transport send took too long", log.Duration("elapsed", ))
	}

	return nil
}

// peekID returns the type id of an encodable message for logging, or 0 if it
// cannot be determined without encoding.
func ( bin.Encoder) uint32 {
	if ,  := .(interface{ () uint32 });  {
		return .()
	}
	return 0
}

func ( *Conn) ( bool) ( int64,  int32) {
	.reqMux.Lock()
	defer .reqMux.Unlock()

	 = .newMessageID()

	// Computing current sequence number (seqno).
	// This should be serialized with new message id generation.
	//
	// See https://github.com/gotd/td/issues/245 for reference.
	 = .sentContentMessages * 2
	if  {
		++
		.sentContentMessages++
	}

	return
}