func (w *Monitor) start(lockWatch types.Watcher) {
	lockWatchDoneC := lockWatch.Done()
	defer func() {
		if err := lockWatch.Close(); err != nil {
			w.Entry.WithError(err).Warn("Failed to close lock watcher subscription.")
		}
	}()

	var certTime <-chan time.Time
	if !w.DisconnectExpiredCert.IsZero() {
		discTime := w.DisconnectExpiredCert.Sub(w.Clock.Now().UTC())
		if discTime <= 0 {
			// Client cert is already expired.
			// Disconnect the client immediately.
			w.disconnectClientOnExpiredCert()
			return
		}
		t := w.Clock.NewTicker(discTime)
		defer t.Stop()
		certTime = t.Chan()
	}

	var idleTime <-chan time.Time
	if w.ClientIdleTimeout != 0 {
		idleTime = w.Clock.After(w.ClientIdleTimeout)
	}

	for {
		select {
		// Expired certificate.
		case <-certTime:
			w.disconnectClientOnExpiredCert()
			return

		// Idle timeout.
		case <-idleTime:
			now := w.Clock.Now().UTC()
			clientLastActive := w.Tracker.GetClientLastActive()
			if now.Sub(clientLastActive) >= w.ClientIdleTimeout {
				reason := "client reported no activity"
				if !clientLastActive.IsZero() {
					reason = fmt.Sprintf("client is idle for %v, exceeded idle timeout of %v",
						now.Sub(clientLastActive), w.ClientIdleTimeout)
				}
				if err := w.emitDisconnectEvent(reason); err != nil {
					w.Entry.WithError(err).Warn("Failed to emit audit event.")
				}
				if w.MessageWriter != nil && w.IdleTimeoutMessage != "" {
					if _, err := w.MessageWriter.WriteString(w.IdleTimeoutMessage); err != nil {
						w.Entry.WithError(err).Warn("Failed to send idle timeout message.")
					}
				}
				w.Entry.Debugf("Disconnecting client: %v", reason)
				if err := w.Conn.Close(); err != nil {
					w.Entry.WithError(err).Error("Failed to close connection.")
				}
				return
			}
			w.Entry.Debugf("Next check in %v", w.ClientIdleTimeout-now.Sub(clientLastActive))
			idleTime = w.Clock.After(w.ClientIdleTimeout - now.Sub(clientLastActive))

		// Lock in force.
		case lockEvent := <-lockWatch.Events():
			var lockErr error
			switch lockEvent.Type {
			case types.OpPut:
				lock, ok := lockEvent.Resource.(types.Lock)
				if !ok {
					w.Entry.Warnf("Skipping unexpected lock event resource type %T.", lockEvent.Resource)
				}
				lockErr = services.LockInForceAccessDenied(lock)
			case types.OpDelete:
				// Lock deletion can be ignored.
			case types.OpUnreliable:
				if w.LockingMode == constants.LockingModeStrict {
					lockErr = services.StrictLockingModeAccessDenied
				}
			default:
				w.Entry.Warnf("Skipping unexpected lock event type %q.", lockEvent.Type)
			}
			if lockErr != nil {
				w.handleLockInForce(lockErr)
				return
			}

		case <-lockWatchDoneC:
			w.Entry.WithError(lockWatch.Error()).Warn("Lock watcher subscription was closed.")
			if w.DisconnectExpiredCert.IsZero() && w.ClientIdleTimeout == 0 {
				return
			}
			// Prevent spinning on the zero value received from closed lockWatchDoneC.
			lockWatchDoneC = nil

		case <-w.Context.Done():
			w.Entry.Debugf("Releasing associated resources - context has been closed.")
			return
		}
	}
}
// start starts monitoring connection.
start starts monitoring connection.
// start starts monitoring connection .
func (w *Monitor) start(lockWatch types.Watcher) {
	lockWatchDoneC := lockWatch.Done()
	defer func() {
		if err := lockWatch.Close(); err != nil {
			w.Entry.WithError(err).Warn("Failed to close lock watcher subscription.")
		}
	}()
	var certTime <-chan time.Time
	if !w.DisconnectExpiredCert.IsZero() {
		discTime := w.DisconnectExpiredCert.Sub(w.Clock.Now().UTC())
		if discTime <= 0 {
			w.disconnectClientOnExpiredCert()
			return
		}
		t := w.Clock.NewTicker(discTime)
		defer t.Stop()
		certTime = t.Chan()
	}
	var idleTime <-chan time.Time
	if w.ClientIdleTimeout != 0 {
		idleTime = w.Clock.After(w.ClientIdleTimeout)
	}
	for {
		select {
		case <-certTime:
			w.disconnectClientOnExpiredCert()
			return
		case <-idleTime:
			now := w.Clock.Now().UTC()
			clientLastActive := w.Tracker.GetClientLastActive()
			if now.Sub(clientLastActive) >= w.ClientIdleTimeout {
				reason := "client reported no activity"
				if !clientLastActive.IsZero() {
					reason = fmt.Sprintf("client is idle for %v, exceeded idle timeout of %v",
						now.Sub(clientLastActive), w.ClientIdleTimeout)
				}
				if err := w.emitDisconnectEvent(reason); err != nil {
					w.Entry.WithError(err).Warn("Failed to emit audit event.")
				}
				if w.MessageWriter != nil && w.IdleTimeoutMessage != "" {
					if _, err := w.MessageWriter.WriteString(w.IdleTimeoutMessage); err != nil {
						w.Entry.WithError(err).Warn("Failed to send idle timeout message.")
					}
				}
				w.Entry.Debugf("Disconnecting client: %v", reason)
				if err := w.Conn.Close(); err != nil {
					w.Entry.WithError(err).Error("Failed to close connection.")
				}
				return
			}
			w.Entry.Debugf("Next check in %v", w.ClientIdleTimeout-now.Sub(clientLastActive))
			idleTime = w.Clock.After(w.ClientIdleTimeout - now.Sub(clientLastActive))
		case lockEvent := <-lockWatch.Events():
			var lockErr error
			switch lockEvent.Type {
			case types.OpPut:
				lock, ok := lockEvent.Resource.(types.Lock)
				if !ok {
					w.Entry.Warnf("Skipping unexpected lock event resource type %T.", lockEvent.Resource)
				}
				lockErr = services.LockInForceAccessDenied(lock)
			case types.OpDelete:
			case types.OpUnreliable:
				if w.LockingMode == constants.LockingModeStrict {
					lockErr = services.StrictLockingModeAccessDenied
				}
			default:
				w.Entry.Warnf("Skipping unexpected lock event type %q.", lockEvent.Type)
			}
			if lockErr != nil {
				w.handleLockInForce(lockErr)
				return
			}
		case <-lockWatchDoneC:
			w.Entry.WithError(lockWatch.Error()).Warn("Lock watcher subscription was closed.")
			if w.DisconnectExpiredCert.IsZero() && w.ClientIdleTimeout == 0 {
				return
			}
			lockWatchDoneC = nil
		case <-w.Context.Done():
			w.Entry.Debugf("Releasing associated resources - context has been closed.")
			return
		}
	}
}
func ( w * Monitor ) start ( lockWatch types . Watcher ) { lockWatchDoneC := lockWatch . Done ( ) defer func ( ) { if err := lockWatch . Close ( ) ; err != nil { w . Entry . WithError ( err ) . Warn ( " " ) } } ( ) var certTime <- chan time . Time if ! w . DisconnectExpiredCert . IsZero ( ) { discTime := w . DisconnectExpiredCert . Sub ( w . Clock . Now ( ) . UTC ( ) ) if discTime <= 0 { w . disconnectClientOnExpiredCert ( ) return } t := w . Clock . NewTicker ( discTime ) defer t . Stop ( ) certTime = t . Chan ( ) } var idleTime <- chan time . Time if w . ClientIdleTimeout != 0 { idleTime = w . Clock . After ( w . ClientIdleTimeout ) } for { select { case <- certTime : w . disconnectClientOnExpiredCert ( ) return case <- idleTime : now := w . Clock . Now ( ) . UTC ( ) clientLastActive := w . Tracker . GetClientLastActive ( ) if now . Sub ( clientLastActive ) >= w . ClientIdleTimeout { reason := " " if ! clientLastActive . IsZero ( ) { reason = fmt . Sprintf ( " " , now . Sub ( clientLastActive ) , w . ClientIdleTimeout ) } if err := w . emitDisconnectEvent ( reason ) ; err != nil { w . Entry . WithError ( err ) . Warn ( " " ) } if w . MessageWriter != nil && w . IdleTimeoutMessage != " " { if _ , err := w . MessageWriter . WriteString ( w . IdleTimeoutMessage ) ; err != nil { w . Entry . WithError ( err ) . Warn ( " " ) } } w . Entry . Debugf ( " " , reason ) if err := w . Conn . Close ( ) ; err != nil { w . Entry . WithError ( err ) . Error ( " " ) } return } w . Entry . Debugf ( " " , w . ClientIdleTimeout - now . Sub ( clientLastActive ) ) idleTime = w . Clock . After ( w . ClientIdleTimeout - now . Sub ( clientLastActive ) ) case lockEvent := <- lockWatch . Events ( ) : var lockErr error switch lockEvent . Type { case types . OpPut : lock , ok := lockEvent . Resource . ( types . Lock ) if ! ok { w . Entry . Warnf ( " " , lockEvent . Resource ) } lockErr = services . LockInForceAccessDenied ( lock ) case types . OpDelete : case types . OpUnreliable : if w . LockingMode == constants . LockingModeStrict { lockErr = services . StrictLockingModeAccessDenied } default : w . Entry . Warnf ( " " , lockEvent . Type ) } if lockErr != nil { w . handleLockInForce ( lockErr ) return } case <- lockWatchDoneC : w . Entry . WithError ( lockWatch . Error ( ) ) . Warn ( " " ) if w . DisconnectExpiredCert . IsZero ( ) && w . ClientIdleTimeout == 0 { return } lockWatchDoneC = nil case <- w . Context . Done ( ) : w . Entry . Debugf ( " " ) return } } }
start starts monitoring connection.
start starts monitoring connection .
// Client cert is already expired. // Disconnect the client immediately. // Expired certificate. // Idle timeout. // Lock in force. // Lock deletion can be ignored. // Prevent spinning on the zero value received from closed lockWatchDoneC.