Files
indra/pkg/relay/sessionmanager.go
херетик 919d4187e6 refactoring some ugly long parameters
would like to redo a lotta this stuff but another time
2023-03-01 06:54:21 +00:00

249 lines
6.1 KiB
Go

package relay
import (
"sync"
"git-indra.lan/indra-labs/lnd/lnd/lnwire"
"git-indra.lan/indra-labs/indra/pkg/crypto/key/prv"
"git-indra.lan/indra-labs/indra/pkg/crypto/key/pub"
"git-indra.lan/indra-labs/indra/pkg/crypto/nonce"
"git-indra.lan/indra-labs/indra/pkg/crypto/sha256"
)
// Session management functions
//
// In order to enable scaling client processing the session data will be
// accessed by multiple goroutines, and thus we use the node's mutex to prevent
// race conditions on this data. This is the only mutable data. A relay's
// identity is its keys so a different key is a different relay, even if it is
// on the same IP address. Because we use netip.AddrPort as network addresses
// there can be more than one relay at an IP address, though hop selection will
// consider the IP address as the unique identifier and not select more than one
// relay on the same IP address. (todo:)
type SessionManager struct {
nodes []*Node
PendingPayments PendingPayments
Sessions
SessionCache
sync.Mutex
}
func NewSessionManager() *SessionManager {
return &SessionManager{
SessionCache: make(SessionCache),
}
}
// ClearPendingPayments is used only for debugging, removing all pending
// payments, making the engine forget about payments it received.
func (sm *SessionManager) ClearPendingPayments() {
log.D.Ln("clearing pending payments")
sm.PendingPayments = sm.PendingPayments[:0]
}
// ClearSessions is used only for debugging, removing all but the first session,
// which is the engine's initial return session.
func (sm *SessionManager) ClearSessions() {
log.D.Ln("clearing sessions")
sm.Sessions = sm.Sessions[:1]
}
func (sm *SessionManager) IncSession(id nonce.ID, sats lnwire.MilliSatoshi,
sender bool, typ string) {
sess := sm.FindSession(id)
if sess != nil {
sm.Lock()
defer sm.Unlock()
sess.IncSats(sats, sender, typ)
}
}
func (sm *SessionManager) DecSession(id nonce.ID, sats int,
sender bool, typ string) bool {
sess := sm.FindSession(id)
if sess != nil {
sm.Lock()
defer sm.Unlock()
return sess.DecSats(lnwire.MilliSatoshi(sats/1024/1024),
sender, typ)
}
return false
}
func (sm *SessionManager) GetNodeCircuit(id nonce.ID) (sce *Circuit,
exists bool) {
sm.Lock()
defer sm.Unlock()
sce, exists = sm.SessionCache[id]
return
}
func (sm *SessionManager) AddSession(s *Session) {
sm.Lock()
defer sm.Unlock()
// check for dupes
for i := range sm.Sessions {
if sm.Sessions[i].ID == s.ID {
log.D.F("refusing to add duplicate session ID %x", s.ID)
return
}
}
sm.Sessions = append(sm.Sessions, s)
// log.D.S(s.ID, sm.Sessions)
// Hop 5, the return session( s) are not added to the SessionCache as they
// are not Billable and are only related to the node of the Engine.
if s.Hop < 5 {
log.D.Ln("storing session", s)
sm.SessionCache = sm.SessionCache.Add(s)
}
}
func (sm *SessionManager) FindSession(id nonce.ID) *Session {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].ID == id {
return sm.Sessions[i]
}
}
return nil
}
func (sm *SessionManager) FindSessionByHeader(prvKey *prv.Key) *Session {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].HeaderPrv.Key.Equals(&prvKey.Key) {
return sm.Sessions[i]
}
}
return nil
}
func (sm *SessionManager) FindSessionByHeaderPub(pubKey *pub.Key) *Session {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].HeaderPub.Equals(pubKey) {
return sm.Sessions[i]
}
}
return nil
}
func (sm *SessionManager) FindSessionPreimage(pr sha256.Hash) *Session {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].Preimage == pr {
return sm.Sessions[i]
}
}
return nil
}
func (sm *SessionManager) GetSessionsAtHop(hop byte) (s Sessions) {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].Hop == hop {
s = append(s, sm.Sessions[i])
}
}
return
}
func (sm *SessionManager) DeleteSession(id nonce.ID) {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if sm.Sessions[i].ID == id {
// ProcessAndDelete from Session cache.
sm.SessionCache[sm.Sessions[i].Node.ID][sm.Sessions[i].Hop] = nil
// ProcessAndDelete from Sessions.
sm.Sessions = append(sm.Sessions[:i], sm.Sessions[i+1:]...)
}
}
}
// IterateSessions calls a function for each entry in the Sessions slice.
//
// Do not call SessionManager methods within this function.
func (sm *SessionManager) IterateSessions(fn func(s *Session) bool) {
sm.Lock()
defer sm.Unlock()
for i := range sm.Sessions {
if fn(sm.Sessions[i]) {
break
}
}
}
// IterateSessionCache calls a function for each entry in the SessionCache
// that provides also access to the related node.
//
// Do not call SessionManager methods within this function.
func (sm *SessionManager) IterateSessionCache(fn func(n *Node,
c *Circuit) bool) {
sm.Lock()
defer sm.Unlock()
out:
for i := range sm.SessionCache {
for j := range sm.nodes {
if sm.nodes[j].ID == i {
if fn(sm.nodes[j], sm.SessionCache[i]) {
break out
}
break
}
}
}
}
func (sm *SessionManager) GetSessionByIndex(i int) (s *Session) {
sm.Lock()
defer sm.Unlock()
if len(sm.Sessions) > i {
s = sm.Sessions[i]
}
return
}
func (sm *SessionManager) DeleteNodeAndSessions(id nonce.ID) {
sm.Lock()
defer sm.Unlock()
var exists bool
// If the node exists its ID is in the SessionCache.
if _, exists = sm.SessionCache[id]; !exists {
return
}
delete(sm.SessionCache, id)
// ProcessAndDelete from the nodes list.
for i := range sm.nodes {
if sm.nodes[i].ID == id {
sm.nodes = append(sm.nodes[:i], sm.nodes[i+1:]...)
break
}
}
var found []int
// Locate all the sessions with the node in them.
for i := range sm.Sessions {
if sm.Sessions[i].Node.ID == id {
found = append(found, i)
}
}
// Create a new Sessions slice and add the ones not in the found list.
temp := make(Sessions, 0, len(sm.Sessions)-len(found))
for i := range sm.Sessions {
for j := range found {
if i != found[j] {
temp = append(temp, sm.Sessions[i])
break
}
}
}
// Place the new Sessions slice in place of the old.
sm.Sessions = temp
}