Repository: rclone/rclone
File: backend/box/box.go (Go)

Code before:
			return nextStreamPosition, nil
		}

		type pathToClear struct {
			path      string
			entryType fs.EntryType
		}
		var pathsToClear []pathToClear
		newEventIds := 0
		for _, entry := range result.Entries {
			if entry.EventId == "" || processedEventIds[entry.EventId] { // missing Event ID, or already saw this one
				continue
			}
			processedEventIds[entry.EventId] = true
			newEventIds++

			if entry.Source.ID == "" { // missing File or Folder ID
				continue
			}
			if entry.Source.Type != api.ItemTypeFile && entry.Source.Type != api.ItemTypeFolder { // event is not for a file or folder
				continue
			}

			// Only interested in event types that result in a file tree change
			isFileTreeChange := false
			for _, eventType := range api.FileTreeChangeEventTypes {
				if eventType == entry.EventType {
					isFileTreeChange = true
					break
				}
			}
			if !isFileTreeChange {
				continue
			}

			entryType := fs.EntryDirectory
			if entry.Source.Type == api.ItemTypeFile {
				entryType = fs.EntryObject
			}

			// The box event only includes the new path for the object (e.g.
			// the path after the object was moved). Use our caches to lookup
			// the old path based on its ID.
			if entry.Source.Type == api.ItemTypeFile {
				if path, ok := f.fileIdPaths.LoadAndDelete(entry.Source.ID); ok {
					pathsToClear = append(pathsToClear, pathToClear{path: path.(string), entryType: entryType})
				}
			} else {
				if path, ok := f.dirCache.GetInv(entry.Source.ID); ok {
					pathsToClear = append(pathsToClear, pathToClear{path: path, entryType: entryType})
				}

Review comment (suggestion):
`api.FileTreeChangeEventTypes` could be a map which would get rid of a few lines of code here (see above)

Code after:
}

func (f *Fs) changeNotifyRunner(ctx context.Context, notifyFunc func(string, fs.EntryType), streamPosition string) (nextStreamPosition string, err error) {
	nextStreamPosition = streamPosition

	// box can send duplicate Event IDs; filter any in a single notify run
	processedEventIDs := make(map[string]bool)

	for {
		limit := f.opt.ListChunk

		// box only allows a max of 500 events
		if limit > 500 {
			limit = 500
		}

		opts := rest.Opts{
			Method:     "GET",
			Path:       "/events",
			Parameters: fieldsValue(),
		}
		opts.Parameters.Set("stream_position", nextStreamPosition)
		opts.Parameters.Set("stream_type", "changes")
		opts.Parameters.Set("limit", strconv.Itoa(limit))

		var result api.Events
		var resp *http.Response
		fs.Debugf(f, "Checking for changes on remote (next_stream_position: %q)", nextStreamPosition)
		err = f.pacer.Call(func() (bool, error) {
			resp, err = f.srv.CallJSON(ctx, &opts, nil, &result)
			return shouldRetry(ctx, resp, err)
		})
		if err != nil {
			return "", err
		}

		if result.ChunkSize != int64(len(result.Entries)) {
			return "", fmt.Errorf("invalid response to event request, chunk_size (%v) not equal to number of entries (%v)", result.ChunkSize, len(result.Entries))
		}

		nextStreamPosition = strconv.FormatInt(result.NextStreamPosition, 10)
		if result.ChunkSize == 0 {
			return nextStreamPosition, nil
		}

		type pathToClear struct {
			path      string
			entryType fs.EntryType
		}
		var pathsToClear []pathToClear
		newEventIDs := 0