package rcmgr import ( "bytes" "sort" "strings" "github.com/libp2p/go-libp2p/core/network" "github.com/libp2p/go-libp2p/core/peer" "github.com/libp2p/go-libp2p/core/protocol" ) // ResourceScopeLimiter is a trait interface that allows you to access scope limits. type ResourceScopeLimiter interface { Limit() Limit SetLimit(Limit) } var _ ResourceScopeLimiter = (*resourceScope)(nil) // ResourceManagerStat is a trait that allows you to access resource manager state. type ResourceManagerState interface { ListServices() []string ListProtocols() []protocol.ID ListPeers() []peer.ID Stat() ResourceManagerStat } type ResourceManagerStat struct { System network.ScopeStat Transient network.ScopeStat Services map[string]network.ScopeStat Protocols map[protocol.ID]network.ScopeStat Peers map[peer.ID]network.ScopeStat } var _ ResourceManagerState = (*resourceManager)(nil) func (s *resourceScope) Limit() Limit { s.Lock() defer s.Unlock() return s.rc.limit } func (s *resourceScope) SetLimit(limit Limit) { s.Lock() defer s.Unlock() s.rc.limit = limit } func (s *protocolScope) SetLimit(limit Limit) { s.rcmgr.setStickyProtocol(s.proto) s.resourceScope.SetLimit(limit) } func (s *peerScope) SetLimit(limit Limit) { s.rcmgr.setStickyPeer(s.peer) s.resourceScope.SetLimit(limit) } func (r *resourceManager) ListServices() []string { r.mx.Lock() defer r.mx.Unlock() result := make([]string, 0, len(r.svc)) for svc := range r.svc { result = append(result, svc) } sort.Slice(result, func(i, j int) bool { return strings.Compare(result[i], result[j]) < 0 }) return result } func (r *resourceManager) ListProtocols() []protocol.ID { r.mx.Lock() defer r.mx.Unlock() result := make([]protocol.ID, 0, len(r.proto)) for p := range r.proto { result = append(result, p) } sort.Slice(result, func(i, j int) bool { return result[i] < result[j] }) return result } func (r *resourceManager) ListPeers() []peer.ID { r.mx.Lock() defer r.mx.Unlock() result := make([]peer.ID, 0, len(r.peer)) for p := range r.peer { result = append(result, p) } sort.Slice(result, func(i, j int) bool { return bytes.Compare([]byte(result[i]), []byte(result[j])) < 0 }) return result } func (r *resourceManager) Stat() (result ResourceManagerStat) { r.mx.Lock() svcs := make([]*serviceScope, 0, len(r.svc)) for _, svc := range r.svc { svcs = append(svcs, svc) } protos := make([]*protocolScope, 0, len(r.proto)) for _, proto := range r.proto { protos = append(protos, proto) } peers := make([]*peerScope, 0, len(r.peer)) for _, peer := range r.peer { peers = append(peers, peer) } r.mx.Unlock() // Note: there is no global lock, so the system is updating while we are dumping its state... // as such stats might not exactly add up to the system level; we take the system stat // last nonetheless so that this is the most up-to-date snapshot result.Peers = make(map[peer.ID]network.ScopeStat, len(peers)) for _, peer := range peers { result.Peers[peer.peer] = peer.Stat() } result.Protocols = make(map[protocol.ID]network.ScopeStat, len(protos)) for _, proto := range protos { result.Protocols[proto.proto] = proto.Stat() } result.Services = make(map[string]network.ScopeStat, len(svcs)) for _, svc := range svcs { result.Services[svc.service] = svc.Stat() } result.Transient = r.transient.Stat() result.System = r.system.Stat() return result } func (r *resourceManager) GetConnLimit() int { return r.limits.GetSystemLimits().GetConnTotalLimit() }