| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- package outbound
- import (
- "sync"
- "time"
- "github.com/v2ray/v2ray-core/common/dice"
- v2net "github.com/v2ray/v2ray-core/common/net"
- "github.com/v2ray/v2ray-core/common/protocol"
- )
- type Receiver struct {
- sync.RWMutex
- Destination v2net.Destination
- Accounts []*protocol.User
- }
- func NewReceiver(dest v2net.Destination, users ...*protocol.User) *Receiver {
- return &Receiver{
- Destination: dest,
- Accounts: users,
- }
- }
- func (this *Receiver) HasUser(user *protocol.User) bool {
- this.RLock()
- defer this.RUnlock()
- account := user.Account.(*protocol.VMessAccount)
- for _, u := range this.Accounts {
- // TODO: handle AlterIds difference.
- uAccount := u.Account.(*protocol.VMessAccount)
- if uAccount.ID.Equals(account.ID) {
- return true
- }
- }
- return false
- }
- func (this *Receiver) AddUser(user *protocol.User) {
- if this.HasUser(user) {
- return
- }
- this.Lock()
- this.Accounts = append(this.Accounts, user)
- this.Unlock()
- }
- func (this *Receiver) PickUser() *protocol.User {
- return this.Accounts[dice.Roll(len(this.Accounts))]
- }
- type ExpiringReceiver struct {
- *Receiver
- until time.Time
- }
- func (this *ExpiringReceiver) Expired() bool {
- return this.until.Before(time.Now())
- }
- type ReceiverManager struct {
- receivers []*Receiver
- detours []*ExpiringReceiver
- detourAccess sync.RWMutex
- }
- func NewReceiverManager(receivers []*Receiver) *ReceiverManager {
- return &ReceiverManager{
- receivers: receivers,
- detours: make([]*ExpiringReceiver, 0, 16),
- }
- }
- func (this *ReceiverManager) AddDetour(rec *Receiver, availableMin byte) {
- if availableMin < 2 {
- return
- }
- this.detourAccess.RLock()
- destExists := false
- for _, r := range this.detours {
- if r.Destination == rec.Destination {
- destExists = true
- // Destination exists, add new user if necessary
- for _, u := range rec.Accounts {
- r.AddUser(u)
- }
- break
- }
- }
- this.detourAccess.RUnlock()
- if !destExists {
- expRec := &ExpiringReceiver{
- Receiver: rec,
- until: time.Now().Add(time.Duration(availableMin-1) * time.Minute),
- }
- this.detourAccess.Lock()
- this.detours = append(this.detours, expRec)
- this.detourAccess.Unlock()
- }
- }
- func (this *ReceiverManager) pickDetour() *Receiver {
- if len(this.detours) == 0 {
- return nil
- }
- this.detourAccess.RLock()
- idx := dice.Roll(len(this.detours))
- rec := this.detours[idx]
- this.detourAccess.RUnlock()
- if rec.Expired() {
- this.detourAccess.Lock()
- detourLen := len(this.detours)
- if detourLen > idx && this.detours[idx].Expired() {
- this.detours[idx] = this.detours[detourLen-1]
- this.detours = this.detours[:detourLen-1]
- }
- this.detourAccess.Unlock()
- return nil
- }
- return rec.Receiver
- }
- func (this *ReceiverManager) pickStdReceiver() *Receiver {
- return this.receivers[dice.Roll(len(this.receivers))]
- }
- func (this *ReceiverManager) PickReceiver() (v2net.Destination, *protocol.User) {
- rec := this.pickDetour()
- if rec == nil {
- rec = this.pickStdReceiver()
- }
- user := rec.PickUser()
- return rec.Destination, user
- }
|