listDirectory static method

Future<List<PodFileItem>> listDirectory(
  1. String relativePath, {
  2. bool forceRefresh = false,
})

List contents of a directory in the POD.

relativePath - Path relative to the app directory (e.g., 'data/places'). Empty string means app root directory (geopod/). forceRefresh - If true, bypass cache and fetch fresh data. Returns a list of PodFileItem representing files and directories.

Implementation

static Future<List<PodFileItem>> listDirectory(
  String relativePath, {
  bool forceRefresh = false,
}) async {
  // Check cache first (unless forcing refresh)
  if (!forceRefresh) {
    final cached = _cache[relativePath];
    if (cached != null) {
      final (items, timestamp) = cached;
      if (DateTime.now().difference(timestamp) < _cacheExpiry) {
        debugPrint(
          'PodDirectoryService: Using cached data for: $relativePath',
        );
        return List.from(items); // Return a copy
      }
    }
  }

  try {
    // Build the directory URL.
    String dirUrl = await PodPath.getDirUrl(relativePath);

    // Ensure URL ends with /

    if (!dirUrl.endsWith('/')) {
      dirUrl = '$dirUrl/';
    }

    debugPrint('PodDirectoryService: Listing directory: $dirUrl');

    // Get authentication tokens.
    final tokens = await PodAuth.getTokens(dirUrl, 'GET');

    // Make the request with proper headers (matching solidpod's implementation)
    final response = await http.get(
      Uri.parse(dirUrl),
      headers: <String, String>{
        'Accept': '*/*',
        'Authorization': 'DPoP ${tokens.accessToken}',
        'Connection': 'keep-alive',
        'DPoP': tokens.dPopToken,
      },
    );

    debugPrint(
      'PodDirectoryService: Response status: ${response.statusCode}',
    );

    if (response.statusCode == 404) {
      // Directory doesn't exist.
      debugPrint('PodDirectoryService: Directory not found');
      return [];
    }

    if (response.statusCode == 403) {
      debugPrint('PodDirectoryService: Access forbidden');
      throw Exception('Access denied to this directory');
    }

    if (response.statusCode != 200) {
      debugPrint(
        'PodDirectoryService: Failed with status ${response.statusCode}',
      );
      throw Exception('Failed to list directory: ${response.statusCode}');
    }

    // Parse the Turtle/RDF response to extract file list.
    final items = _parseTurtleResponse(response.body, relativePath);

    // Update cache.

    _cache[relativePath] = (List.from(items), DateTime.now());
    debugPrint(
      'PodDirectoryService: Cached ${items.length} items for: $relativePath',
    );

    return items;
  } catch (e) {
    debugPrint('PodDirectoryService.listDirectory() error: $e');
    rethrow;
  }
}