func (t *Transaction) WriteResult(res TransactionResult) bool {
	select {
	case t.resultCh <- res:
		return true
	default:
	}
	return false
}
WriteResult writes the result to the result channel
package client
import (
	"fmt"
	"net"
	"sync"
	"time"
	"github.com/pion/stun"
)
const (
	maxRtxInterval time.Duration = 1600 * time.Millisecond
)
type TransactionResult struct {
	Msg     *stun.Message
	From    net.Addr
	Retries int
	Err     error
}
type TransactionConfig struct {
	Key      string
	Raw      []byte
	To       net.Addr
	Interval time.Duration
}
type Transaction struct {
	Key      string                  
	Raw      []byte                  
	To       net.Addr                
	nRtx     int                     
	interval time.Duration           
	timer    *time.Timer             
	resultCh chan TransactionResult  
	mutex    sync.RWMutex
}
func NewTransaction(config *TransactionConfig) *Transaction {
	return &Transaction{
		Key:      config.Key,                    
		Raw:      config.Raw,                    
		To:       config.To,                     
		interval: config.Interval,               
		resultCh: make(chan TransactionResult),  
	}
}
func (t *Transaction) StartRtxTimer(onTimeout func(trKey string, nRtx int)) {
	t.mutex.Lock()
	defer t.mutex.Unlock()
	t.timer = time.AfterFunc(t.interval, func() {
		t.nRtx++
		t.interval *= 2
		if t.interval > maxRtxInterval {
			t.interval = maxRtxInterval
		}
		onTimeout(t.Key, t.nRtx)
	})
}
func (t *Transaction) StopRtxTimer() {
	t.mutex.Lock()
	defer t.mutex.Unlock()
	if t.timer != nil {
		t.timer.Stop()
	}
}