export async function createSortedParticipantArray()

in src/sorted_participant_array.js [16:143]


export async function createSortedParticipantArray() {

  if (currentSortedParticipantArray_ != null) {
    return currentSortedParticipantArray_;
  }

  const globalParticipantsArray =
    await GlobalAppendOnlyArray.createGlobalAppendOnlyArray([], SPARK_SORTED_PARTICIPANTS);

  const sortedParticipantsWrapper = {}

  const isSynced = Reactive.boolSignalSource(SPARK_SORTED_PARTICIPANTS_COMPLETE);
  isSynced.set(false);
  sortedParticipantsWrapper.isSyncedSignal = isSynced.signal;

  // Add local or send to changes queue
  const localParticipant = await Participants.self;
  globalParticipantsArray.push(localParticipant.id);

  // Wait for all current participants to be added
  const initialSyncInterval = Time.setInterval(async () => {
    const complete = isSortedParticipantArrayComplete();
    if (complete) {
      Diagnostics.log("Complete from peers!")
      isSynced.set(true);
      Time.clearInterval(initialSyncInterval);
    }
  }, 1000);

  sortedParticipantsWrapper.getSortedActiveParticipants = async () => {
    const activeParticipantsMap = await getActiveParticipantsMap();
    const sortedActiveParticipants = [];
    const globalParticipantsSnapshot = globalParticipantsArray.getSnapshot();
    for (let participantId of globalParticipantsSnapshot) {
      if (activeParticipantsMap.has(participantId)) {
        sortedActiveParticipants.push(activeParticipantsMap.get(participantId));
        activeParticipantsMap.delete(participantId);
      }
    }
    return sortedActiveParticipants;
  }

  sortedParticipantsWrapper.getSortedAllTimeParticipants = async () => {
    const allParticipantsMap = new Map();
    (await Participants.getAllOtherParticipants()).forEach(p => allParticipantsMap.set(p.id, p));
    allParticipantsMap.set(localParticipant.id, localParticipant);

    const sortedAllTimeParticipants = [];
    const globalParticipantsSnapshot = globalParticipantsArray.getSnapshot();
    for (let participantId of globalParticipantsSnapshot) {
      if (allParticipantsMap.has(participantId)) {
        sortedAllTimeParticipants.push(allParticipantsMap.get(participantId));
        allParticipantsMap.delete(participantId);
      }
    }
    return sortedAllTimeParticipants;
  }

  // Monitor changes
  Participants.onOtherParticipantAdded().subscribe(async (participant) => {
    // When a new participant is added to the call, the array is not synced
    // until this participant is added to the global array
    isSynced.set(false);
    let intervalRuns = 0;
    const addParticipantInterval = Time.setInterval(async () => {
      intervalRuns++;
      let complete = await isSortedParticipantArrayComplete();
      if (complete) {
        Time.clearInterval(addParticipantInterval);
        updateIsSyncedAfterIntervals(intervalRuns);
      }
    }, 1000);

    // Monitor the new participant for status changes to emit
    // an isSynced signal
    participant.isActiveInCall.monitor().subscribe((event) => {
      isSynced.set(false);
      Time.setTimeout(() => {
        isSynced.set(true);
      }, 50);
    })
  })

  const currentParticipants = await Participants.getAllOtherParticipants();
  currentParticipants.forEach(participant => {
    // Monitor all current participants for status changes to emit
    // an isSynced signal
    participant.isActiveInCall.monitor().subscribe((event) => {
      isSynced.set(false);
      Time.setTimeout(() => {
        isSynced.set(true);
      }, 50);
    })
  })

  // Helper functions
  async function getActiveParticipantsMap() {
    const peers = await Participants.getAllOtherParticipants();
    const activeParticipantsMap = new Map();
    peers.forEach(p => {
      if (p.isActiveInCall.pinLastValue()) {
        activeParticipantsMap.set(p.id, p);
      }
    });
    activeParticipantsMap.set(localParticipant.id, localParticipant);
    return activeParticipantsMap;
  }

  async function isSortedParticipantArrayComplete() {
    const participantsFromAPI = await Participants.getAllOtherParticipants();
    participantsFromAPI.push(localParticipant);
    const participantsFromArray = new Set(globalParticipantsArray.getSnapshot());
    return participantsFromAPI.every(p => participantsFromArray.has(p.id));
  }

  function updateIsSyncedAfterIntervals(intervalRuns) {
    if (intervalRuns > 1) {
      isSynced.set(true);
    } else {
      Time.setTimeout(() => {
        isSynced.set(true);
      }, 50);
    }
  }

  currentSortedParticipantArray_ = sortedParticipantsWrapper;
  return sortedParticipantsWrapper;
}