findFiles method

Future<List<Map<String, dynamic>>> findFiles(
  1. String startPath,
  2. String pattern, {
  3. int maxDepth = -1,
})

Implementation

Future<List<Map<String, dynamic>>> findFiles(String startPath, String pattern,
    {int maxDepth = -1}) async {
  final rootInfo = await resolvePath(startPath);
  if (rootInfo['type'] != 'folder') return [];

  final treeData = await getFlatFolderTree(rootInfo['uuid']);
  final rawFolders = treeData['folders'] as List? ?? [];
  final rawFiles =
      (treeData['files'] as List?) ?? (treeData['uploads'] as List?) ?? [];

  final folderMap = <String, Map<String, dynamic>>{};

  for (var f in rawFolders) {
    try {
      String uuid, encName, parent;
      if (f is List) {
        if (f.length < 3) continue;
        uuid = f[0];
        encName = f[1];
        parent = f[2];
      } else {
        if (f['deleted'] == true || f['trash'] == true) continue;
        uuid = f['uuid'];
        encName = f['name'];
        parent = f['parent'];
      }
      var decName = await crypto.tryDecrypt(encName, masterKeys);
      if (decName.startsWith('{')) {
        decName = json.decode(decName)['name'];
      }
      folderMap[uuid] = {'name': decName, 'parent': parent};
    } catch (_) {}
  }

  final results = <Map<String, dynamic>>[];

  String? getFullPath(String? parentUuid) {
    var parts = <String>[];
    var curr = parentUuid;
    var seen = <String>{};
    while (curr != null && curr != rootInfo['uuid']) {
      if (seen.contains(curr)) return null;
      seen.add(curr);
      if (!folderMap.containsKey(curr)) return null;
      final f = folderMap[curr]!;
      parts.add(f['name']);
      curr = f['parent'];
    }
    if (curr == null && rootInfo['uuid'] != 'root') return null;
    return p.join(startPath, parts.reversed.join('/'));
  }

  // Glob matching: translate `*`/`?` and escape every other character so
  // regex metacharacters in the pattern are matched literally.
  final globBuf = StringBuffer('^');
  for (final ch in pattern.split('')) {
    if (ch == '*') {
      globBuf.write('.*');
    } else if (ch == '?') {
      globBuf.write('.');
    } else {
      globBuf.write(RegExp.escape(ch));
    }
  }
  globBuf.write(r'$');
  final globRegex = RegExp(globBuf.toString(), caseSensitive: false);

  for (var f in rawFiles) {
    try {
      String uuid, encMeta, parent;
      if (f is List) {
        if (f.length < 6) continue;
        uuid = f[0];
        parent = f[4];
        encMeta = f[5];
      } else {
        if (f['deleted'] == true || f['trash'] == true) continue;
        uuid = f['uuid'];
        parent = f['parent'];
        encMeta = f['metadata'];
      }

      final meta = json.decode(await crypto.tryDecrypt(encMeta, masterKeys));
      final name = meta['name'];

      if (!globRegex.hasMatch(name)) continue;

      var dirPath = getFullPath(parent);
      if (parent == rootInfo['uuid'])
        dirPath = startPath;
      else if (dirPath == null) continue;

      if (maxDepth != -1) {
        final relDepth =
            dirPath.split('/').length - startPath.split('/').length;
        if (relDepth >= maxDepth) continue;
      }

      results.add({
        'uuid': uuid,
        'name': name,
        'fullPath': p.join(dirPath, name).replaceAll('\\', '/'),
        'size': meta['size'] ?? 0,
        'lastModified': meta['lastModified'] ?? 0
      });
    } catch (_) {}
  }

  return results;
}