github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/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  }