Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion example/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ dependency_overrides:
solidui:
git:
url: https://github.com/anusii/solidui.git
ref: tony/127_browserpod
ref: tony/204_pod_initialisation

dev_dependencies:
flutter_lints: ^6.0.0
Expand Down
5 changes: 4 additions & 1 deletion lib/solidpod.dart
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,13 @@ export 'src/solid/utils/get_url_helper.dart'

export 'src/solid/utils/init_helper.dart'
show
clearPodStructureInitialised,
generateDefaultFolders,
generateCustomFolders,
generateDefaultFiles,
initPod;
initPod,
isPodStructureInitialised,
markPodStructureInitialised;

/// Read encrypted/non-encrypted files stored in a POD

Expand Down
52 changes: 35 additions & 17 deletions lib/src/solid/api/rest_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,30 +142,48 @@ Future<List<dynamic>> initialStructureTest(
'fileNames': [],
};

for (final containerName in folders) {
// NB: the trailing separator in path is essential for this check
final resourceUrl = await getDirUrl(containerName);
if (await checkResourceStatus(resourceUrl, isFile: false) ==
ResourceStatus.notExist) {
allExists = false;
// Resolve URLs and check existence of all folders in parallel.

final folderResults = await Future.wait(
folders.map((containerName) async {
final resourceUrl = await getDirUrl(containerName);
final status = await checkResourceStatus(resourceUrl, isFile: false);
return (name: containerName, url: resourceUrl, status: status);
}),
);

resNotExist['folders'].add(resourceUrl);
resNotExist['folderNames'].add(containerName);
for (final result in folderResults) {
if (result.status == ResourceStatus.notExist) {
allExists = false;
resNotExist['folders'].add(result.url);
resNotExist['folderNames'].add(result.name);
}
}

// Resolve URLs and check existence of all files in parallel.

final fileFutures =
<Future<({String fileName, String url, ResourceStatus status})>>[];
for (final containerName in files.keys) {
final fileNameList = files[containerName] as List<String>;
for (final fileName in fileNameList) {
final resourceUrl = await getFileUrl(
[containerName as String, fileName].join('/'),
);
if (await checkResourceStatus(resourceUrl, isFile: true) ==
ResourceStatus.notExist) {
allExists = false;
resNotExist['files'].add(resourceUrl);
resNotExist['fileNames'].add(fileName);
}
fileFutures.add(() async {
final resourceUrl = await getFileUrl(
[containerName as String, fileName].join('/'),
);
final status = await checkResourceStatus(resourceUrl, isFile: true);
return (fileName: fileName, url: resourceUrl, status: status);
}());
}
}

final fileResults = await Future.wait(fileFutures);

for (final result in fileResults) {
if (result.status == ResourceStatus.notExist) {
allExists = false;
resNotExist['files'].add(result.url);
resNotExist['fileNames'].add(result.fileName);
}
}

Expand Down
72 changes: 67 additions & 5 deletions lib/src/solid/utils/init_helper.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,12 @@

library;

import 'package:flutter/foundation.dart' show debugPrint;

import 'package:solidpod/src/solid/api/rest_api.dart';
import 'package:solidpod/src/solid/constants/common.dart';
import 'package:solidpod/src/solid/constants/web_acl.dart';
import 'package:solidpod/src/solid/utils/authdata_manager.dart';
import 'package:solidpod/src/solid/utils/exceptions.dart';
import 'package:solidpod/src/solid/utils/get_url_helper.dart';
import 'package:solidpod/src/solid/utils/key_manager.dart';
Expand All @@ -41,14 +44,70 @@ import 'package:solidpod/src/solid/utils/misc.dart'
getEncKeyPath,
getIndKeyPath,
getPubKeyPath,
isUserLoggedIn;
isUserLoggedIn,
writeToSecureStorage;
import 'package:solidpod/src/solid/utils/permission.dart' show genAclTurtle;
import 'package:solidpod/src/solid/utils/rdf.dart' show genPermLogTTLStr;

/// Key prefix for the POD initialisation flag in secure storage.

const String _podInitFlagPrefix = '_pod_init_done_';

/// Builds a unique storage key for the current user and app.

Future<String> _getPodInitFlagKey() async {
final webId = await AuthDataManager.getWebId();
if (webId == null || webId.isEmpty) {
throw NotLoggedInException(
'Cannot check initialisation flag without logging in',
);
}
return '$_podInitFlagPrefix${appDirName}_$webId';
}

/// Returns `true` if the POD structure has already been initialised for the
/// current user and app, allowing subsequent logins to skip the full
/// folder/file existence check.

Future<bool> isPodStructureInitialised() async {
try {
final key = await _getPodInitFlagKey();
final value = await secureStorage.read(key: key);
return value == 'true';
} on Object catch (e) {
debugPrint('isPodStructureInitialised() check failed: $e');
return false;
}
}

/// Persists a flag indicating the POD structure has been successfully
/// initialised for the current user and app.

Future<void> markPodStructureInitialised() async {
final key = await _getPodInitFlagKey();
await writeToSecureStorage(key, 'true');
}

/// Clears the initialisation flag, forcing a full structure check on the
/// next login. Useful when the expected folder/file layout changes between
/// app versions.

Future<void> clearPodStructureInitialised() async {
try {
final key = await _getPodInitFlagKey();
if (await secureStorage.containsKey(key: key)) {
await secureStorage.delete(key: key);
}
} on Object catch (e) {
debugPrint('clearPodStructureInitialised() failed: $e');
}
}

/// Generates a list of default folder paths for a given application.
///
/// This function takes the name of an application as input and returns a list of strings.
/// Each string in the list represents a path to a default folder for the application.
/// This function takes the name of an application as input and returns a list
/// of strings. Each string in the list represents a path to a default folder
/// for the application.

Future<List<String>> generateDefaultFolders() async {
final dataDirLoc = [appDirName, dataDir].join('/');
Expand Down Expand Up @@ -91,8 +150,9 @@ List<String> generateCustomFolders(List customFolderPaths) {

/// Generates a list of default folder paths for a given application.
///
/// This function takes the name of an application as input and returns a list of strings.
/// Each string in the list represents a path to a default folder for the application.
/// This function takes the name of an application as input and returns a list
/// of strings. Each string in the list represents a path to a default folder
/// for the application.

Future<Map<dynamic, dynamic>> generateDefaultFiles() async {
final sharingDirLoc = [appDirName, sharingDir].join('/');
Expand Down Expand Up @@ -204,4 +264,6 @@ Future<void> initPod(

await createResource(f, content: fileContent, replaceIfExist: aclFlag);
}

await markPodStructureInitialised();
}
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependency_overrides:
solidui:
git:
url: https://github.com/anusii/solidui.git
ref: tony/127_browserpod
ref: tony/204_pod_initialisation

dev_dependencies:
build_runner: ^2.10.5
Expand Down