package client
import (
"net"
"sync"
"time"
"github.com/pion/stun/v3"
)
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
IgnoreResult bool
}
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 {
var resultCh chan TransactionResult
if !config .IgnoreResult {
resultCh = make (chan TransactionResult )
}
return &Transaction {
Key : config .Key ,
Raw : config .Raw ,
To : config .To ,
interval : config .Interval ,
resultCh : resultCh ,
}
}
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 .mutex .Lock ()
t .nRtx ++
nRtx := t .nRtx
t .interval *= 2
if t .interval > maxRtxInterval {
t .interval = maxRtxInterval
}
t .mutex .Unlock ()
onTimeout (t .Key , nRtx )
})
}
func (t *Transaction ) StopRtxTimer () {
t .mutex .Lock ()
defer t .mutex .Unlock ()
if t .timer != nil {
t .timer .Stop ()
}
}
func (t *Transaction ) WriteResult (res TransactionResult ) bool {
if t .resultCh == nil {
return false
}
t .resultCh <- res
return true
}
func (t *Transaction ) WaitForResult () TransactionResult {
if t .resultCh == nil {
return TransactionResult {
Err : errWaitForResultOnNonResultTransaction ,
}
}
result , ok := <-t .resultCh
if !ok {
result .Err = errTransactionClosed
}
return result
}
func (t *Transaction ) Close () {
if t .resultCh != nil {
close (t .resultCh )
}
}
func (t *Transaction ) Retries () int {
t .mutex .RLock ()
defer t .mutex .RUnlock ()
return t .nRtx
}
type TransactionMap struct {
trMap map [string ]*Transaction
mutex sync .RWMutex
}
func NewTransactionMap () *TransactionMap {
return &TransactionMap {
trMap : map [string ]*Transaction {},
}
}
func (m *TransactionMap ) Insert (key string , tr *Transaction ) bool {
m .mutex .Lock ()
defer m .mutex .Unlock ()
m .trMap [key ] = tr
return true
}
func (m *TransactionMap ) Find (key string ) (*Transaction , bool ) {
m .mutex .RLock ()
defer m .mutex .RUnlock ()
tr , ok := m .trMap [key ]
return tr , ok
}
func (m *TransactionMap ) Delete (key string ) {
m .mutex .Lock ()
defer m .mutex .Unlock ()
delete (m .trMap , key )
}
func (m *TransactionMap ) CloseAndDeleteAll () {
m .mutex .Lock ()
defer m .mutex .Unlock ()
for trKey , tr := range m .trMap {
tr .Close ()
delete (m .trMap , trKey )
}
}
func (m *TransactionMap ) Size () int {
m .mutex .RLock ()
defer m .mutex .RUnlock ()
return len (m .trMap )
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .