From 7dfa85267718e858d389989df3e3c85094ed04ea Mon Sep 17 00:00:00 2001 From: v2ray Date: Sun, 24 Jul 2016 23:22:46 +0200 Subject: [PATCH] server spec --- common/protocol/account.go | 10 ++++ common/protocol/server_picker.go | 90 ++++++++++++++++++++++++++++++++ common/protocol/server_spec.go | 81 ++++++++++++++++++++++++++++ 3 files changed, 181 insertions(+) create mode 100644 common/protocol/server_picker.go create mode 100644 common/protocol/server_spec.go diff --git a/common/protocol/account.go b/common/protocol/account.go index 86c7f2235..e70ff4f71 100644 --- a/common/protocol/account.go +++ b/common/protocol/account.go @@ -5,6 +5,7 @@ import ( ) type Account interface { + Equals(Account) bool } type VMessAccount struct { @@ -18,3 +19,12 @@ func (this *VMessAccount) AnyValidID() *ID { } return this.AlterIDs[dice.Roll(len(this.AlterIDs))] } + +func (this *VMessAccount) Equals(account Account) bool { + vmessAccount, ok := account.(*VMessAccount) + if !ok { + return false + } + // TODO: handle AlterIds difference + return this.ID.Equals(vmessAccount.ID) +} diff --git a/common/protocol/server_picker.go b/common/protocol/server_picker.go new file mode 100644 index 000000000..c6b8dd4cf --- /dev/null +++ b/common/protocol/server_picker.go @@ -0,0 +1,90 @@ +package protocol + +import ( + "sync" +) + +type ServerList struct { + sync.RWMutex + servers []*ServerSpec +} + +func NewServerList() *ServerList { + return &ServerList{} +} + +func (this *ServerList) AddServer(server *ServerSpec) { + this.Lock() + defer this.Unlock() + + this.servers = append(this.servers, server) +} + +func (this *ServerList) Size() uint32 { + this.RLock() + defer this.RUnlock() + + return uint32(len(this.servers)) +} + +func (this *ServerList) GetServer(idx uint32) *ServerSpec { + this.RLock() + defer this.RUnlock() + + for { + if idx >= uint32(len(this.servers)) { + return nil + } + + server := this.servers[idx] + if !server.IsValid() { + this.RemoveServer(idx) + continue + } + + return server + } +} + +// @Private +func (this *ServerList) RemoveServer(idx uint32) { + n := len(this.servers) + this.servers[idx] = this.servers[n-1] + this.servers = this.servers[:n-1] +} + +type ServerPicker interface { + PickServer() *ServerSpec +} + +type RoundRobinServerPicker struct { + sync.Mutex + serverlist *ServerList + nextIndex uint32 +} + +func NewRoundRobinServerPicker(serverlist *ServerList) *RoundRobinServerPicker { + return &RoundRobinServerPicker{ + serverlist: serverlist, + nextIndex: 0, + } +} + +func (this *RoundRobinServerPicker) PickServer() *ServerSpec { + this.Lock() + defer this.Unlock() + + next := this.nextIndex + server := this.serverlist.GetServer(next) + if server == nil { + next = 0 + server = this.serverlist.GetServer(0) + } + next++ + if next >= this.serverlist.Size() { + next = 0 + } + this.nextIndex = next + + return server +} diff --git a/common/protocol/server_spec.go b/common/protocol/server_spec.go new file mode 100644 index 000000000..3289307ea --- /dev/null +++ b/common/protocol/server_spec.go @@ -0,0 +1,81 @@ +package protocol + +import ( + "sync" + "time" + + "github.com/v2ray/v2ray-core/common/dice" + v2net "github.com/v2ray/v2ray-core/common/net" +) + +type ServerSpec struct { + sync.RWMutex + Destination v2net.Destination + + users []*User +} + +func NewServerSpec(dest v2net.Destination, users ...*User) *ServerSpec { + return &ServerSpec{ + Destination: dest, + users: users, + } +} + +func (this *ServerSpec) HasUser(user *User) bool { + this.RLock() + defer this.RUnlock() + + account := user.Account + for _, u := range this.users { + if u.Account.Equals(account) { + return true + } + } + return false +} + +func (this *ServerSpec) AddUser(user *User) { + if this.HasUser(user) { + return + } + + this.Lock() + defer this.Unlock() + + this.users = append(this.users, user) +} + +func (this *ServerSpec) PickUser() *User { + userCount := len(this.users) + return this.users[dice.Roll(userCount)] +} + +func (this *ServerSpec) IsValid() bool { + return true +} + +func (this *ServerSpec) SetValid(b bool) { +} + +type TimeoutServerSpec struct { + *ServerSpec + until time.Time +} + +func NewTimeoutServerSpec(spec *ServerSpec, until time.Time) *TimeoutServerSpec { + return &TimeoutServerSpec{ + ServerSpec: spec, + until: until, + } +} + +func (this *TimeoutServerSpec) IsValid() bool { + return this.until.Before(time.Now()) +} + +func (this *TimeoutServerSpec) SetValid(b bool) { + if !b { + this.until = time.Time{} + } +}