package notify import ( "context" "net" ) type clientConnSessionRuntime struct { transport *transportBinding transportAttached bool transportGeneration uint64 tuConn net.Conn stopCtx context.Context stopFn context.CancelFunc transportStopCtx context.Context transportStopFn context.CancelFunc transportDone chan struct{} } func (c *ClientConn) setClientConnSessionRuntime(rt *clientConnSessionRuntime) { if c == nil || rt == nil { return } logical := c.LogicalConn() if logical == nil { if rt.transport == nil && rt.tuConn != nil { rt.transport = newTransportBinding(rt.tuConn, nil) } normalizeClientConnSessionRuntimeTransportState(rt) ensureClientConnSessionRuntimeTransportLifecycle(rt) ensureClientConnSessionRuntimeTransportDone(rt) c.sessionRuntime.Store(rt) return } logical.setSessionRuntime(rt) } func (c *ClientConn) clientConnSessionRuntimeSnapshot() *clientConnSessionRuntime { if c == nil { return nil } state := c.ensureLogicalConnRuntimeState() if state == nil { return c.sessionRuntime.Load() } rt := state.sessionRuntimeSnapshot() if rt != c.sessionRuntime.Load() { c.sessionRuntime.Store(rt) } return rt } func (c *ClientConn) clearClientConnSessionRuntimeTransport() { if c == nil { return } logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return } if rt.transportStopFn != nil { rt.transportStopFn() } next := *rt next.transport = nil next.transportAttached = false next.transportGeneration = 0 next.tuConn = nil next.transportStopCtx = nil next.transportStopFn = nil next.transportDone = nil c.setClientConnSessionRuntime(&next) return } logical.clearSessionRuntimeTransport() } func (c *ClientConn) clientConnTransportSnapshot() net.Conn { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return nil } if rt.transport != nil { return rt.transport.connSnapshot() } return rt.tuConn } return logical.transportSnapshot() } func (c *ClientConn) clientConnStopContextSnapshot() context.Context { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return nil } return rt.stopCtx } return logical.stopContextSnapshot() } func (c *ClientConn) clientConnStopFuncSnapshot() context.CancelFunc { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return nil } return rt.stopFn } return logical.stopFuncSnapshot() } func (c *ClientConn) closeClientConnTransport() { logical := c.LogicalConn() if logical == nil { conn := c.clientConnTransportSnapshot() if conn == nil { return } _ = conn.Close() return } logical.closeTransport() } func (c *ClientConn) clientConnTransportBindingSnapshot() *transportBinding { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return nil } if rt.transport != nil { return rt.transport } if rt.tuConn == nil { return nil } return newTransportBinding(rt.tuConn, nil) } return logical.transportBindingSnapshot() } func normalizeClientConnSessionRuntimeTransportState(rt *clientConnSessionRuntime) { if rt == nil { return } if rt.transport != nil { rt.transportAttached = rt.transport.connSnapshot() != nil return } rt.transportAttached = rt.tuConn != nil } func ensureClientConnSessionRuntimeTransportLifecycle(rt *clientConnSessionRuntime) { if rt == nil { return } if rt.tuConn == nil { rt.transportStopCtx = nil rt.transportStopFn = nil rt.transportDone = nil return } if rt.transportStopCtx != nil && rt.transportStopFn != nil { return } parent := rt.stopCtx if parent == nil { parent = context.Background() } rt.transportStopCtx, rt.transportStopFn = context.WithCancel(parent) } func ensureClientConnSessionRuntimeTransportDone(rt *clientConnSessionRuntime) { if rt == nil { return } if rt.tuConn == nil { rt.transportDone = nil return } if rt.transportDone != nil { return } rt.transportDone = make(chan struct{}) } func closeClientConnSessionRuntimeTransportDone(rt *clientConnSessionRuntime) { if rt == nil || rt.transportDone == nil { return } select { case <-rt.transportDone: return default: close(rt.transportDone) } } func (c *ClientConn) clientConnTransportStopContextSnapshot() context.Context { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return nil } if rt.transportStopCtx != nil { return rt.transportStopCtx } return rt.stopCtx } return logical.transportStopContextSnapshot() } func (c *ClientConn) clientConnTransportAttachedSnapshot() bool { logical := c.LogicalConn() if logical == nil { rt := c.clientConnSessionRuntimeSnapshot() if rt == nil { return false } return rt.transportAttached } return logical.transportAttachedSnapshot() }