github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/connection/connections.go (about) 1 /* For license and copyright information please see LEGAL file in repository */ 2 3 package connection 4 5 import ( 6 "strconv" 7 "sync" 8 "time" 9 10 "../log" 11 "../protocol" 12 ) 13 14 // Connections store pools of connection to retrieve in many ways 15 type Connections struct { 16 mutex sync.Mutex 17 poolByPeerAddr map[[16]byte]protocol.Connection 18 poolByUserIDDelegateUserID map[[32]byte]protocol.Connection 19 poolByUserID map[[16]byte][]protocol.Connection 20 poolByDomain map[string]protocol.Connection 21 poolByBlackList map[[16]byte]protocol.Connection // key is PeerAddr 22 guestConnectionCount uint64 23 shutdownSignal chan struct{} 24 } 25 26 func (c *Connections) Init() { 27 c.poolByPeerAddr = make(map[[16]byte]protocol.Connection, 16384) 28 c.poolByUserIDDelegateUserID = make(map[[32]byte]protocol.Connection, 16384) 29 c.poolByUserID = make(map[[16]byte][]protocol.Connection, 16384) 30 c.poolByDomain = make(map[string]protocol.Connection, 16384) 31 c.poolByBlackList = make(map[[16]byte]protocol.Connection, 256) 32 c.shutdownSignal = make(chan struct{}) 33 34 go c.connectionIdleTimeoutSaveAndFree() 35 } 36 37 // GetConnectionByPeerAddr get a connection by peer GP from connections pool. 38 func (c *Connections) GetConnectionByPeerAddr(addr [16]byte) (conn protocol.Connection, err protocol.Error) { 39 conn = c.poolByPeerAddr[addr] 40 if conn == nil { 41 err = ErrNoConnection 42 } 43 return 44 } 45 46 // GetConnectionByUserIDDelegateUserID return the connection from pool or app storage. 47 // A connection can use just by single app node, so user can't use same connection to connect other node before close connection on usage node. 48 func (c *Connections) GetConnectionByUserIDDelegateUserID(userID, delegateUserID [16]byte) (conn protocol.Connection, err protocol.Error) { 49 conn = c.poolByUserIDDelegateUserID[c.userIDDelegateUserID(userID, delegateUserID)] 50 if conn == nil { 51 err = ErrNoConnection 52 } 53 return 54 } 55 56 // GetConnectionsByUserID get the connections by peer userID||domainID from connections pool. 57 func (c *Connections) GetConnectionsByUserID(userID [16]byte) (conn []protocol.Connection, err protocol.Error) { 58 conn = c.poolByUserID[userID] 59 if conn == nil { 60 err = ErrNoConnection 61 } 62 return 63 } 64 65 // GetConnectionByDomain return the connection from pool or app storage if any exist. 66 func (c *Connections) GetConnectionByDomain(domain string) (conn protocol.Connection, err protocol.Error) { 67 conn = c.poolByDomain[domain] 68 if conn == nil { 69 err = ErrNoConnection 70 } 71 return 72 } 73 74 // RegisterConnection register new connection in server connection pool 75 func (c *Connections) RegisterConnection(conn protocol.Connection) (err protocol.Error) { 76 c.mutex.Lock() 77 defer c.mutex.Unlock() 78 79 var userID = conn.UserID().UUID() 80 c.poolByUserIDDelegateUserID[c.userIDDelegateUserID(userID, conn.DelegateUserID().UUID())] = conn 81 if conn.Addr() != [16]byte{} { 82 c.poolByPeerAddr[conn.Addr()] = conn 83 } 84 85 var connDomain = conn.DomainName() 86 if connDomain != "" { 87 c.poolByDomain[connDomain] = conn 88 } 89 90 if userID != [16]byte{} { 91 c.poolByUserID[userID] = append(c.poolByUserID[userID], conn) 92 } 93 94 if conn.UserID().Type() == protocol.UserType_Unset { 95 c.guestConnectionCount++ 96 } 97 return 98 } 99 100 // DeregisterConnection delete the given connection in connections pool 101 func (c *Connections) DeregisterConnection(conn protocol.Connection) (err protocol.Error) { 102 c.mutex.Lock() 103 defer c.mutex.Unlock() 104 err = c.deregisterConnection(conn) 105 return 106 } 107 108 func (c *Connections) deregisterConnection(conn protocol.Connection) (err protocol.Error) { 109 if conn.UserID().Type() == protocol.UserType_Unset { 110 c.guestConnectionCount-- 111 } 112 113 var userID = conn.UserID().UUID() 114 delete(c.poolByUserIDDelegateUserID, c.userIDDelegateUserID(userID, conn.DelegateUserID().UUID())) 115 delete(c.poolByPeerAddr, conn.Addr()) 116 delete(c.poolByDomain, conn.DomainName()) 117 118 var userConnections = c.poolByUserID[userID] 119 var userConnectionsLen =len(userConnections) 120 for i := 0; i < userConnectionsLen; i++ { 121 if userConnections[i].UserID().UUID() == userID { 122 var newUserConnectionsLen = userConnectionsLen - 1 123 // copy(userConnections[i:], userConnections[i+1:]) 124 // userConnections = userConnections[:newUserConnectionsLen] 125 userConnections[i] = userConnections[newUserConnectionsLen] 126 userConnections = userConnections[:newUserConnectionsLen] 127 break 128 } 129 } 130 c.poolByUserID[userID] = userConnections 131 return 132 } 133 134 func (c *Connections) Shutdown() { 135 c.shutdownSignal <- struct{}{} 136 137 protocol.App.Log(log.InfoEvent(domainEnglish, "ShutDown - Saving proccess begin ...\n"+ 138 "Number of active connections:"+c.activeConnectionsNumber())) 139 for _, conn := range c.poolByUserIDDelegateUserID { 140 go conn.Close() 141 } 142 protocol.App.Log(log.InfoEvent(domainEnglish, "ShutDown - Saving proccess end now")) 143 } 144 145 func (c *Connections) userIDDelegateUserID(userID, delegateUserID [16]byte) (userIDDelegateUserID [32]byte) { 146 copy(userIDDelegateUserID[:], userID[:]) 147 copy(userIDDelegateUserID[16:], delegateUserID[:]) 148 return 149 } 150 151 func (c *Connections) connectionIdleTimeoutSaveAndFree() { 152 var timer = time.NewTimer(ConnectionIdleTimeout) 153 var timerTime time.Time 154 for { 155 select { 156 case timerTime = <-timer.C: 157 protocol.App.Log(log.InfoEvent(domainEnglish, "Cron - Idle connections timeout save and free proccess begin ...\n"+ 158 "Number of active connections: "+c.activeConnectionsNumber())) 159 160 var timeNowMilli = timerTime.UnixMilli() 161 162 c.mutex.Lock() 163 defer c.mutex.Unlock() 164 for _, conn := range c.poolByUserIDDelegateUserID { 165 var lastUsage = int64(conn.LastUsage()) 166 if lastUsage+ConnectionIdleTimeout < timeNowMilli { 167 continue 168 } 169 170 c.deregisterConnection(conn) 171 go conn.Close() 172 } 173 174 timer.Reset(ConnectionIdleTimeout) 175 protocol.App.Log(log.InfoEvent(domainEnglish, "Cron - Number of active connections after:"+c.activeConnectionsNumber()+ 176 "\nIdle connections timeout save and free proccess end now")) 177 case <-c.shutdownSignal: 178 return 179 } 180 } 181 } 182 183 func (c *Connections) activeConnectionsNumber() string { 184 return strconv.FormatInt(int64(len(c.poolByUserIDDelegateUserID)), 10) 185 }