Repository: syncthing/syncthing
File: lib/model/model.go (Go)

Code before:
				return
			case <-evChan:
			case <-ticker.C:
			}

			continue
		}

		err = s.sendIndexTo()

		// Wait a short amount of time before entering the next loop. If there
		// are continuous changes happening to the local index, this gives us
		// time to batch them up a little.
		time.Sleep(250 * time.Millisecond)
	}
}

func (s *indexSender) Stop() {
	close(s.stop)
	<-s.stopped
}

// Complete returning true means that the suture supervisor will not restart
// this service if it wasn't stopped. Here it always returns true, as indexSender
// only terminates when a connection is closed/has failed, in which case
// retrying doesn't help.
func (s *indexSender) Complete() bool { return true }

// sendIndexTo sends file infos with a sequence number higher than prevSequence and
// returns the highest sent sequence number.
func (s *indexSender) sendIndexTo() error {
	initial := s.prevSequence == 0
	batch := newFileInfoBatch(nil)
	batch.flushFn = func(fs []protocol.FileInfo) error {
		l.Debugf("Sending indexes for %s to %s at %s: %d files (<%d bytes)", s.folder, s.dev, s.conn, len(batch.infos), batch.size)
		if initial {
			initial = false
			return s.conn.Index(s.folder, fs)
		}
		return s.conn.IndexUpdate(s.folder, fs)
	}

	var err error
	var f protocol.FileInfo
	s.fset.WithHaveSequence(s.prevSequence+1, func(fi db.FileIntf) bool {
		if err = batch.flushIfFull(); err != nil {
			return false
		}

		if shouldDebug() {
			if fi.SequenceNo() < s.prevSequence+1 {

Review comment (refactor):
We should explain that there is a hidden interface satisfaction check in suture for this.

The other option would be for the folder to be supervisor where all of its cruft gets run (versiomer, index senders et al), so we tear down the whole supervisor.

Also, it's a great opportunity to move this thing into a separate file.

Code after:
			case <-s.stop:
				return
			case <-s.connClosed:
				return
			case <-evChan:
			case <-ticker.C:
			}

			continue
		}

		err = s.sendIndexTo()

		// Wait a short amount of time before entering the next loop. If there
		// are continuous changes happening to the local index, this gives us
		// time to batch them up a little.
		time.Sleep(250 * time.Millisecond)
	}
}

func (s *indexSender) Stop() {
	close(s.stop)
	<-s.stopped
}

// Complete implements the suture.IsCompletable interface. When Serve terminates
// before Stop is called, the supervisor will check for this method and if it
// returns true removes the service instead of restarting it. Here it always
// returns true, as indexSender only terminates when a connection is
// closed/has failed, in which case retrying doesn't help.
func (s *indexSender) Complete() bool { return true }

// sendIndexTo sends file infos with a sequence number higher than prevSequence and
// returns the highest sent sequence number.
func (s *indexSender) sendIndexTo() error {
	initial := s.prevSequence == 0
	batch := newFileInfoBatch(nil)
	batch.flushFn = func(fs []protocol.FileInfo) error {
		l.Debugf("Sending indexes for %s to %s at %s: %d files (<%d bytes)", s.folder, s.dev, s.conn, len(batch.infos), batch.size)
		if initial {
			initial = false
			return s.conn.Index(s.folder, fs)
		}
		return s.conn.IndexUpdate(s.folder, fs)
	}

	var err error
	var f protocol.FileInfo
	s.fset.WithHaveSequence(s.prevSequence+1, func(fi db.FileIntf) bool {
		if err = batch.flushIfFull(); err != nil {
			return false