loadMissingRelayListsFromNip65OrNip02 method

Future<void> loadMissingRelayListsFromNip65OrNip02(
  1. List<String> pubKeys, {
  2. dynamic onProgress(
    1. String stepName,
    2. int count,
    3. int total
    )?,
  3. bool forceRefresh = false,
})

Implementation

Future<void> loadMissingRelayListsFromNip65OrNip02(List<String> pubKeys,
    {Function(String stepName, int count, int total)? onProgress, bool forceRefresh = false}) async {
  List<String> missingPubKeys = [];
  for (var pubKey in pubKeys) {
    UserRelayList? userRelayList = cacheManager.loadUserRelayList(pubKey);
    if (userRelayList == null || forceRefresh) {
      // TODO check if not too old (time passed since last refreshed timestamp)
      missingPubKeys.add(pubKey);
    }
  }
  Map<String, UserRelayList> fromNip65s = {};
  Map<String, UserRelayList> fromNip02Contacts = {};
  Set<ContactList> contactLists = {};
  Set<String> found = {};

  if (missingPubKeys.isNotEmpty) {
    print("loading missing relay lists ${missingPubKeys.length}");
    if (onProgress != null) {
      onProgress.call(
          "loading missing relay lists", 0, missingPubKeys.length);
    }
    try {
      await for (final event in (await requestRelays(
          timeout: missingPubKeys.length > 1 ? 10 : 3,
          bootstrapRelays,
          Filter(
              authors: missingPubKeys,
              kinds: [Nip65.KIND, ContactList.KIND]))).stream) {
        switch (event.kind) {
          case Nip65.KIND:
            Nip65 nip65 = Nip65.fromEvent(event);
            if (nip65.relays.isNotEmpty) {
              UserRelayList fromNip65 = UserRelayList.fromNip65(nip65);
              if (fromNip65s[event.pubKey] == null ||
                  fromNip65s[event.pubKey]!.createdAt < event.createdAt) {
                fromNip65s[event.pubKey] = fromNip65;
              }
              if (onProgress != null) {
                found.add(event.pubKey);
                onProgress.call("loading missing relay lists", found.length,
                    missingPubKeys.length);
              }
            }
          case ContactList.KIND:
            ContactList contactList = ContactList.fromEvent(event);
            contactLists.add(contactList);
            if (event.content.isNotEmpty) {
              if (fromNip02Contacts[event.pubKey] == null ||
                  fromNip02Contacts[event.pubKey]!.createdAt <
                      event.createdAt) {
                fromNip02Contacts[event.pubKey] =
                    UserRelayList.fromNip02EventContent(event);
              }
              if (onProgress != null) {
                found.add(event.pubKey);
                onProgress.call("loading missing relay lists", found.length,
                    missingPubKeys.length);
              }
            }
        }
      }
    } catch (e) {
      print(e);
    }
    Set<UserRelayList> relayLists = Set.of(fromNip65s.values);
    // Only add kind3 contents relays if there is no Nip65 for given pubKey.
    // This is because kind3 contents relay should be deprecated, and if we have a nip65 list should be considered more up-to-date.
    for (MapEntry<String, UserRelayList> entry in fromNip02Contacts.entries) {
      if (!fromNip65s.containsKey(entry.key)) {
        relayLists.add(entry.value);
      }
    }
    await cacheManager.saveUserRelayLists(relayLists.toList());

    // also save to cache any fresher contact list
    List<ContactList> contactListsSave = [];
    for (ContactList contactList in contactLists) {
      ContactList? existing =
      cacheManager.loadContactList(contactList.pubKey);
      if (existing == null || existing.createdAt < contactList.createdAt) {
        contactListsSave.add(contactList);
      }
    }
    await cacheManager.saveContactLists(contactListsSave);

    if (onProgress != null) {
      onProgress.call(
          "loading missing relay lists", found.length, missingPubKeys.length);
    }
  }
  print("Loaded ${found.length} relay lists ");
}