2023-08-23 15:30:52 +09:00

64 lines
1.6 KiB
Go

package addressmanager
import (
"math"
"math/rand"
"time"
"github.com/c4ei/yunseokyeol/app/appmessage"
)
// AddressRandomize implement addressRandomizer interface
type AddressRandomize struct {
random *rand.Rand
maxFailedCount uint64
}
// NewAddressRandomize returns a new RandomizeAddress.
func NewAddressRandomize(maxFailedCount uint64) *AddressRandomize {
return &AddressRandomize{
random: rand.New(rand.NewSource(time.Now().UnixNano())),
maxFailedCount: maxFailedCount,
}
}
// weightedRand is a help function which returns a random index in the
// range [0, len(weights)-1] with probability weighted by `weights`
func weightedRand(weights []float32) int {
sum := float32(0)
for _, weight := range weights {
sum += weight
}
randPoint := rand.Float32()
scanPoint := float32(0)
for i, weight := range weights {
normalizedWeight := weight / sum
scanPoint += normalizedWeight
if randPoint <= scanPoint {
return i
}
}
return len(weights) - 1
}
// RandomAddresses returns count addresses at random from input list
func (amc *AddressRandomize) RandomAddresses(addresses []*address, count int) []*appmessage.NetAddress {
if len(addresses) < count {
count = len(addresses)
}
weights := make([]float32, 0, len(addresses))
for _, addr := range addresses {
weights = append(weights, float32(math.Pow(64, float64(amc.maxFailedCount-addr.connectionFailedCount))))
}
result := make([]*appmessage.NetAddress, 0, count)
for count > 0 {
i := weightedRand(weights)
result = append(result, addresses[i].netAddress)
// Zero entry i to avoid re-selection
weights[i] = 0
// Update count
count--
}
return result
}