github.com/mysteriumnetwork/node@v0.0.0-20240516044423-365054f76801/core/connection/multi.go (about) 1 /* 2 * Copyright (C) 2022 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 connection 19 20 import ( 21 "context" 22 "sync" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/rs/zerolog/log" 26 27 "github.com/mysteriumnetwork/node/core/connection/connectionstate" 28 "github.com/mysteriumnetwork/node/identity" 29 ) 30 31 type multiConnectionManager struct { 32 mu sync.RWMutex 33 cms map[int]Manager 34 35 newConnectionManager func() Manager 36 } 37 38 // NewMultiConnectionManager create a wrapper around connection manager to support multiple connections. 39 func NewMultiConnectionManager(newConnectionManager func() Manager) *multiConnectionManager { 40 return &multiConnectionManager{ 41 cms: make(map[int]Manager), 42 43 newConnectionManager: newConnectionManager, 44 } 45 } 46 47 // Connect creates new connection from given consumer to provider, reports error if connection already exists. 48 func (mcm *multiConnectionManager) Connect(consumerID identity.Identity, hermesID common.Address, proposalLookup ProposalLookup, params ConnectParams) error { 49 mcm.mu.Lock() 50 51 m, ok := mcm.cms[params.ProxyPort] 52 if !ok { 53 m = mcm.newConnectionManager() 54 mcm.cms[params.ProxyPort] = m 55 } 56 mcm.mu.Unlock() 57 58 return m.Connect(consumerID, hermesID, proposalLookup, params) 59 } 60 61 // Status queries current status of connection. 62 func (mcm *multiConnectionManager) Status(id int) connectionstate.Status { 63 mcm.mu.RLock() 64 defer mcm.mu.RUnlock() 65 66 if m, ok := mcm.cms[id]; ok { 67 return m.Status() 68 } 69 70 return connectionstate.Status{ 71 State: connectionstate.NotConnected, 72 } 73 } 74 75 // Stats provides connection statistics information. 76 func (mcm *multiConnectionManager) Stats(id int) connectionstate.Statistics { 77 mcm.mu.RLock() 78 defer mcm.mu.RUnlock() 79 80 if m, ok := mcm.cms[id]; ok { 81 return m.Stats() 82 } 83 84 return connectionstate.Statistics{} 85 } 86 87 // Disconnect closes established connection, reports error if no connection. 88 func (mcm *multiConnectionManager) Disconnect(id int) error { 89 mcm.mu.RLock() 90 m, ok := mcm.cms[id] 91 mcm.mu.RUnlock() 92 93 if ok { 94 err := m.Disconnect() 95 return err 96 } 97 98 if id < 0 { 99 mcm.mu.RLock() 100 defer mcm.mu.RUnlock() 101 102 for _, m := range mcm.cms { 103 if err := m.Disconnect(); err != nil { 104 log.Error().Err(err).Msg("Failed to disconnect active connection") 105 } 106 } 107 } 108 109 return nil 110 } 111 112 // CheckChannel checks if current session channel is alive, returns error on failed keep-alive ping. 113 func (mcm *multiConnectionManager) CheckChannel(context.Context) error { return nil } 114 115 // Reconnect reconnects current session. 116 func (mcm *multiConnectionManager) Reconnect(id int) { 117 mcm.mu.RLock() 118 defer mcm.mu.RUnlock() 119 120 if m, ok := mcm.cms[id]; ok { 121 m.Reconnect() 122 } 123 }