github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/service/session_pool.go (about)

     1  /*
     2   * Copyright (C) 2018 The "MysteriumNetwork/node" Authors.
     3   *
     4   * This program is free software: you can redistribute it and/or modify
     5   * it under the terms of the GNU General Public License as published by
     6   * the Free Software Foundation, either version 3 of the License, or
     7   * (at your option) any later version.
     8   *
     9   * This program is distributed in the hope that it will be useful,
    10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    12   * GNU General Public License for more details.
    13   *
    14   * You should have received a copy of the GNU General Public License
    15   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16   */
    17  
    18  package service
    19  
    20  import (
    21  	"sync"
    22  
    23  	"github.com/mysteriumnetwork/node/identity"
    24  	"github.com/mysteriumnetwork/node/session"
    25  	"github.com/mysteriumnetwork/node/session/event"
    26  )
    27  
    28  // NewSessionPool initiates new session storage
    29  func NewSessionPool(publisher publisher) *SessionPool {
    30  	sm := &SessionPool{
    31  		sessions:  make(map[session.ID]*Session),
    32  		lock:      sync.Mutex{},
    33  		publisher: publisher,
    34  	}
    35  	return sm
    36  }
    37  
    38  // SessionPool maintains all current sessions in memory
    39  type SessionPool struct {
    40  	sessions  map[session.ID]*Session
    41  	lock      sync.Mutex
    42  	publisher publisher
    43  }
    44  
    45  // Add puts given session to storage and publishes a creation event.
    46  // Multiple sessions per peerID is possible in case different services are used
    47  func (sp *SessionPool) Add(instance *Session) {
    48  	sp.lock.Lock()
    49  	defer sp.lock.Unlock()
    50  
    51  	sp.sessions[instance.ID] = instance
    52  	sp.publisher.Publish(event.AppTopicSession, instance.toEvent(event.CreatedStatus))
    53  }
    54  
    55  // GetAll returns all sessions in storage
    56  func (sp *SessionPool) GetAll() []*Session {
    57  	sp.lock.Lock()
    58  	defer sp.lock.Unlock()
    59  
    60  	// we're never gonna have more than 100000 sessions ongoing on a single node - performance here should not be an issue.
    61  	// see Benchmark_Storage_GetAll
    62  	sessions := make([]*Session, len(sp.sessions))
    63  
    64  	i := 0
    65  	for _, value := range sp.sessions {
    66  		sessions[i] = value
    67  		i++
    68  	}
    69  	return sessions
    70  }
    71  
    72  // Find returns underlying session instance
    73  func (sp *SessionPool) Find(id session.ID) (*Session, bool) {
    74  	sp.lock.Lock()
    75  	defer sp.lock.Unlock()
    76  
    77  	instance, found := sp.sessions[id]
    78  	return instance, found
    79  }
    80  
    81  // FindOpts provides fields to search sessions.
    82  type FindOpts struct {
    83  	Peer        *identity.Identity
    84  	ServiceType string
    85  }
    86  
    87  // FindBy returns a session by find options.
    88  func (sp *SessionPool) FindBy(opts FindOpts) (*Session, bool) {
    89  	sp.lock.Lock()
    90  	defer sp.lock.Unlock()
    91  
    92  	for _, session := range sp.sessions {
    93  		if opts.Peer != nil && *opts.Peer != session.ConsumerID {
    94  			continue
    95  		}
    96  		if opts.ServiceType != "" && opts.ServiceType != session.Proposal.ServiceType {
    97  			continue
    98  		}
    99  		return session, true
   100  	}
   101  	return nil, false
   102  }
   103  
   104  // Remove removes given session from underlying storage
   105  func (sp *SessionPool) Remove(id session.ID) {
   106  	sp.lock.Lock()
   107  	defer sp.lock.Unlock()
   108  
   109  	if instance, found := sp.sessions[id]; found {
   110  		delete(sp.sessions, id)
   111  		go sp.publisher.Publish(event.AppTopicSession, instance.toEvent(event.RemovedStatus))
   112  	}
   113  }
   114  
   115  // RemoveForService removes all sessions which belong to given service
   116  func (sp *SessionPool) RemoveForService(serviceID string) {
   117  	sessions := sp.GetAll()
   118  	for _, session := range sessions {
   119  		if session.ServiceID == serviceID {
   120  			sp.Remove(session.ID)
   121  		}
   122  	}
   123  }