feat: remove idCache and switch to loading with paths
This commit is contained in:
parent
86a0b1e6d5
commit
9b93fb9623
@ -11,15 +11,13 @@ class PCloudFile implements CloudFile, PCloudNode {
|
||||
private final PCloudFolder parent;
|
||||
private final String name;
|
||||
private final String path;
|
||||
private final Long fileId;
|
||||
private final Optional<Long> size;
|
||||
private final Optional<Date> modified;
|
||||
|
||||
public PCloudFile(PCloudFolder parent, String name, String path, Long fileId, Optional<Long> size, Optional<Date> modified) {
|
||||
public PCloudFile(PCloudFolder parent, String name, String path, Optional<Long> size, Optional<Date> modified) {
|
||||
this.parent = parent;
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
this.fileId = fileId;
|
||||
this.size = size;
|
||||
this.modified = modified;
|
||||
}
|
||||
@ -39,11 +37,6 @@ class PCloudFile implements CloudFile, PCloudNode {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return fileId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PCloudFolder getParent() {
|
||||
return parent;
|
||||
|
@ -8,11 +8,9 @@ class PCloudFolder implements CloudFolder, PCloudNode {
|
||||
private final PCloudFolder parent;
|
||||
private final String name;
|
||||
private final String path;
|
||||
private final Long folderId;
|
||||
|
||||
public PCloudFolder(PCloudFolder parent, String name, String path, Long folderId) {
|
||||
public PCloudFolder(PCloudFolder parent, String name, String path) {
|
||||
this.parent = parent;
|
||||
this.folderId = folderId;
|
||||
this.name = name;
|
||||
this.path = path;
|
||||
}
|
||||
@ -32,11 +30,6 @@ class PCloudFolder implements CloudFolder, PCloudNode {
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getId() {
|
||||
return folderId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PCloudFolder getParent() {
|
||||
return parent;
|
||||
@ -44,6 +37,6 @@ class PCloudFolder implements CloudFolder, PCloudNode {
|
||||
|
||||
@Override
|
||||
public PCloudFolder withCloud(Cloud cloud) {
|
||||
return new PCloudFolder(parent.withCloud(cloud), name, path, folderId);
|
||||
return new PCloudFolder(parent.withCloud(cloud), name, path);
|
||||
}
|
||||
}
|
||||
|
@ -1,77 +0,0 @@
|
||||
package org.cryptomator.data.cloud.pcloud;
|
||||
|
||||
import android.util.LruCache;
|
||||
|
||||
import org.cryptomator.domain.CloudFolder;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
class PCloudIdCache {
|
||||
|
||||
private final LruCache<String, NodeInfo> cache;
|
||||
|
||||
@Inject
|
||||
PCloudIdCache() {
|
||||
cache = new LruCache<>(1000);
|
||||
}
|
||||
|
||||
public NodeInfo get(String path) {
|
||||
return cache.get(path);
|
||||
}
|
||||
|
||||
<T extends PCloudNode> T cache(T value) {
|
||||
add(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public void add(PCloudNode node) {
|
||||
add(node.getPath(), new NodeInfo(node));
|
||||
}
|
||||
|
||||
private void add(String path, NodeInfo info) {
|
||||
cache.put(path, info);
|
||||
}
|
||||
|
||||
public void remove(PCloudNode node) {
|
||||
remove(node.getPath());
|
||||
}
|
||||
|
||||
private void remove(String path) {
|
||||
removeChildren(path);
|
||||
cache.remove(path);
|
||||
}
|
||||
|
||||
private void removeChildren(String path) {
|
||||
String prefix = path + '/';
|
||||
for (String key : cache.snapshot().keySet()) {
|
||||
if (key.startsWith(prefix)) {
|
||||
cache.remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class NodeInfo {
|
||||
|
||||
private final Long id;
|
||||
private final boolean isFolder;
|
||||
|
||||
private NodeInfo(PCloudNode node) {
|
||||
this(node.getId(), node instanceof CloudFolder);
|
||||
}
|
||||
|
||||
NodeInfo(Long id, boolean isFolder) {
|
||||
this.id = id;
|
||||
this.isFolder = isFolder;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isFolder() {
|
||||
return isFolder;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -58,8 +58,6 @@ import static org.cryptomator.util.file.LruFileCacheUtil.storeToLruCache;
|
||||
|
||||
class PCloudImpl {
|
||||
|
||||
private final PCloudIdCache idCache;
|
||||
|
||||
private final PCloudClientFactory clientFactory = new PCloudClientFactory();
|
||||
private final PCloud cloud;
|
||||
private final RootPCloudFolder root;
|
||||
@ -77,7 +75,6 @@ class PCloudImpl {
|
||||
|
||||
this.context = context;
|
||||
this.cloud = cloud;
|
||||
this.idCache = new PCloudIdCache();
|
||||
this.root = new RootPCloudFolder(cloud);
|
||||
this.sharedPreferencesHandler = new SharedPreferencesHandler(context);
|
||||
}
|
||||
@ -102,83 +99,24 @@ class PCloudImpl {
|
||||
return folder;
|
||||
}
|
||||
|
||||
private Optional<RemoteEntry> findEntry(Long folderId, String name, boolean isFolder) throws IOException, BackendException {
|
||||
if (folderId == null) {
|
||||
throw new NoSuchCloudFileException();
|
||||
}
|
||||
try {
|
||||
RemoteFolder remoteFolder = client().listFolder(folderId).execute();
|
||||
for (RemoteEntry remoteEntry : remoteFolder.children()) {
|
||||
if (isFolder) {
|
||||
if (remoteEntry.isFolder() && remoteEntry.name().equals(name)) {
|
||||
return Optional.of(remoteEntry);
|
||||
}
|
||||
} else {
|
||||
if (remoteEntry.isFile() && remoteEntry.name().equals(name)) {
|
||||
return Optional.of(remoteEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
} catch(ApiError ex) {
|
||||
Set<Integer> ignoredErrorCodes = new HashSet<>();
|
||||
ignoredErrorCodes.add(PCloudApiError.PCloudApiErrorCodes.DIRECTORY_DOES_NOT_EXIST.getValue());
|
||||
ignoredErrorCodes.add(PCloudApiError.PCloudApiErrorCodes.FILE_OR_FOLDER_NOT_FOUND.getValue());
|
||||
ignoredErrorCodes.add(PCloudApiError.PCloudApiErrorCodes.FILE_NOT_FOUND.getValue());
|
||||
handleApiError(ex, ignoredErrorCodes);
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
public PCloudFile file(PCloudFolder parent, String name) throws BackendException, IOException {
|
||||
return file(parent, name, Optional.empty());
|
||||
}
|
||||
|
||||
public PCloudFile file(PCloudFolder parent, String name, Optional<Long> size) throws BackendException, IOException {
|
||||
if (parent.getId() == null) {
|
||||
return PCloudNodeFactory.file(parent, name, size);
|
||||
}
|
||||
|
||||
String path = PCloudNodeFactory.getNodePath(parent, name);
|
||||
PCloudIdCache.NodeInfo nodeInfo = idCache.get(path);
|
||||
if (nodeInfo != null && !nodeInfo.isFolder()) {
|
||||
return PCloudNodeFactory.file(parent, name, size, path, nodeInfo.getId());
|
||||
}
|
||||
|
||||
Optional<RemoteEntry> file = findEntry(parent.getId(), name, false);
|
||||
if (file.isPresent()) {
|
||||
return idCache.cache(PCloudNodeFactory.file(parent, file.get().asFile()));
|
||||
}
|
||||
|
||||
return PCloudNodeFactory.file(parent, name, size);
|
||||
return PCloudNodeFactory.file(parent, name, size, parent.getPath() + "/" + name);
|
||||
}
|
||||
|
||||
public PCloudFolder folder(PCloudFolder parent, String name) throws IOException, BackendException {
|
||||
if (parent.getId() == null) {
|
||||
return PCloudNodeFactory.folder(parent, name);
|
||||
}
|
||||
|
||||
String path = PCloudNodeFactory.getNodePath(parent, name);
|
||||
PCloudIdCache.NodeInfo nodeInfo = idCache.get(path);
|
||||
if (nodeInfo != null && nodeInfo.isFolder()) {
|
||||
return PCloudNodeFactory.folder(parent, name, path, nodeInfo.getId());
|
||||
}
|
||||
|
||||
Optional<RemoteEntry> folder = findEntry(parent.getId(), name, true);
|
||||
if (folder.isPresent()) {
|
||||
return idCache.cache(PCloudNodeFactory.folder(parent, folder.get().asFolder()));
|
||||
}
|
||||
return PCloudNodeFactory.folder(parent, name);
|
||||
return PCloudNodeFactory.folder(parent, name, parent.getPath() + "/" + name);
|
||||
}
|
||||
|
||||
public boolean exists(PCloudNode node) throws IOException, BackendException {
|
||||
try {
|
||||
if (node instanceof PCloudFolder) {
|
||||
RemoteFolder remoteFolder = client().listFolder(node.getPath()).execute();
|
||||
idCache.add(PCloudNodeFactory.folder(node.getParent(), remoteFolder));
|
||||
client().loadFolder(node.getPath()).execute();
|
||||
} else {
|
||||
RemoteFile remoteFile = client().loadFile(node.getPath()).execute();
|
||||
idCache.add(PCloudNodeFactory.file(node.getParent(), remoteFile));
|
||||
client().loadFile(node.getPath()).execute();
|
||||
}
|
||||
return true;
|
||||
} catch (ApiError ex) {
|
||||
@ -195,19 +133,11 @@ class PCloudImpl {
|
||||
public List<PCloudNode> list(PCloudFolder folder) throws IOException, BackendException {
|
||||
List<PCloudNode> result = new ArrayList<>();
|
||||
|
||||
Long folderId = folder.getId();
|
||||
RemoteFolder listFolderResult;
|
||||
try {
|
||||
if (folderId == null) {
|
||||
listFolderResult = client().listFolder(folder.getPath()).execute();
|
||||
} else {
|
||||
listFolderResult = client() //
|
||||
.listFolder(folder.getId()) //
|
||||
.execute();
|
||||
}
|
||||
RemoteFolder listFolderResult = client().listFolder(folder.getPath()).execute();
|
||||
List<RemoteEntry> entryMetadata = listFolderResult.children();
|
||||
for (RemoteEntry metadata : entryMetadata) {
|
||||
result.add(idCache.cache(PCloudNodeFactory.from(folder, metadata)));
|
||||
result.add(PCloudNodeFactory.from(folder, metadata));
|
||||
}
|
||||
return result;
|
||||
} catch(ApiError ex) {
|
||||
@ -217,20 +147,18 @@ class PCloudImpl {
|
||||
}
|
||||
|
||||
public PCloudFolder create(PCloudFolder folder) throws IOException, BackendException {
|
||||
if (folder.getParent().getId() == null) {
|
||||
if (!exists(folder.getParent())) {
|
||||
folder = new PCloudFolder( //
|
||||
create(folder.getParent()), //
|
||||
folder.getName(), folder.getPath(), folder.getId() //
|
||||
//
|
||||
folder.getName(), folder.getPath() //
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
RemoteFolder createdFolder = client() //
|
||||
.createFolder(folder.getParent().getId(), folder.getName()) //
|
||||
.createFolder(folder.getPath()) //
|
||||
.execute();
|
||||
return idCache.cache( //
|
||||
PCloudNodeFactory.folder(folder.getParent(), createdFolder));
|
||||
return PCloudNodeFactory.folder(folder.getParent(), createdFolder);
|
||||
} catch (ApiError ex) {
|
||||
handleApiError(ex);
|
||||
throw new FatalBackendException(ex);
|
||||
@ -242,23 +170,12 @@ class PCloudImpl {
|
||||
throw new CloudNodeAlreadyExistsException(target.getName());
|
||||
}
|
||||
|
||||
RemoteEntry relocationResult;
|
||||
|
||||
try {
|
||||
if (source instanceof PCloudFolder) {
|
||||
relocationResult = client().moveFolder(source.getId(), target.getParent().getId()).execute();
|
||||
if (!relocationResult.name().equals(target.getName())) {
|
||||
relocationResult = client().renameFolder(relocationResult.asFolder(), target.getName()).execute();
|
||||
}
|
||||
return PCloudNodeFactory.from(target.getParent(), client().moveFolder(source.getPath(), target.getPath()).execute());
|
||||
} else {
|
||||
relocationResult = client().moveFile(source.getId(), target.getParent().getId()).execute();
|
||||
if (!relocationResult.name().equals(target.getName())) {
|
||||
relocationResult = client().renameFile(relocationResult.asFile(), target.getName()).execute();
|
||||
}
|
||||
return PCloudNodeFactory.from(target.getParent(), client().moveFile(source.getPath(), target.getPath()).execute());
|
||||
}
|
||||
|
||||
idCache.remove(source);
|
||||
return idCache.cache(PCloudNodeFactory.from(target.getParent(), relocationResult));
|
||||
} catch(ApiError ex) {
|
||||
handleApiError(ex);
|
||||
throw new FatalBackendException(ex);
|
||||
@ -271,13 +188,9 @@ class PCloudImpl {
|
||||
throw new CloudNodeAlreadyExistsException("CloudNode already exists and replace is false");
|
||||
}
|
||||
|
||||
if (file.getParent().getId() == null) {
|
||||
throw new NoSuchCloudFileException(String.format("The parent folder of %s doesn't have a folderId. The file would remain in root folder", file.getPath()));
|
||||
}
|
||||
|
||||
progressAware.onProgress(Progress.started(UploadState.upload(file)));
|
||||
UploadOptions uploadOptions = UploadOptions.DEFAULT;
|
||||
if (file.getId() != null && replace) {
|
||||
if (replace) {
|
||||
uploadOptions = UploadOptions.OVERRIDE_FILE;
|
||||
}
|
||||
|
||||
@ -285,7 +198,8 @@ class PCloudImpl {
|
||||
|
||||
progressAware.onProgress(Progress.completed(UploadState.upload(file)));
|
||||
|
||||
return idCache.cache(PCloudNodeFactory.file(file.getParent(), uploadedFile));
|
||||
return PCloudNodeFactory.file(file.getParent(), uploadedFile);
|
||||
|
||||
}
|
||||
|
||||
private RemoteFile uploadFile(final PCloudFile file, DataSource data, final ProgressAware<UploadState> progressAware, UploadOptions uploadOptions, final long size) //
|
||||
@ -310,17 +224,12 @@ class PCloudImpl {
|
||||
}
|
||||
};
|
||||
|
||||
Long parentFolderId = file.getParent().getId();
|
||||
if (parentFolderId == null) {
|
||||
parentFolderId = idCache.get(file.getParent().getPath()).getId();
|
||||
}
|
||||
|
||||
String filename = file.getName();
|
||||
String encodedFilename = URLEncoder.encode(filename, UTF_8);
|
||||
|
||||
try {
|
||||
RemoteFile newFile = client() //
|
||||
.createFile(parentFolderId, encodedFilename, pCloudDataSource, new Date(), listener, uploadOptions) //
|
||||
.createFile(file.getParent().getPath(), encodedFilename, pCloudDataSource, new Date(), listener, uploadOptions) //
|
||||
.execute();
|
||||
if (!filename.equals(encodedFilename)) {
|
||||
return client().renameFile(newFile.fileId(), filename).execute();
|
||||
@ -335,36 +244,17 @@ class PCloudImpl {
|
||||
public void read(PCloudFile file, Optional<File> encryptedTmpFile, OutputStream data, final ProgressAware<DownloadState> progressAware) throws IOException, BackendException {
|
||||
progressAware.onProgress(Progress.started(DownloadState.download(file)));
|
||||
|
||||
Long fileId = file.getId();
|
||||
if (fileId == null) {
|
||||
PCloudIdCache.NodeInfo nodeInfo = idCache.get(file.getPath());
|
||||
if (nodeInfo != null) {
|
||||
fileId = nodeInfo.getId();
|
||||
}
|
||||
}
|
||||
|
||||
RemoteFile remoteFile = null;
|
||||
if (fileId == null) {
|
||||
Optional<RemoteEntry> remoteEntryOptional = findEntry(file.getParent().getId(), file.getName(), false);
|
||||
if (remoteEntryOptional.isPresent()) {
|
||||
remoteFile = remoteEntryOptional.get().asFile();
|
||||
fileId = remoteFile.fileId();
|
||||
} else {
|
||||
throw new NoSuchCloudFileException(file.getName());
|
||||
}
|
||||
}
|
||||
|
||||
Optional<String> cacheKey = Optional.empty();
|
||||
Optional<File> cacheFile = Optional.empty();
|
||||
|
||||
RemoteFile remoteFile;
|
||||
|
||||
if (sharedPreferencesHandler.useLruCache() && createLruCache(sharedPreferencesHandler.lruCacheSize())) {
|
||||
if (remoteFile == null) {
|
||||
try {
|
||||
remoteFile = client().loadFile(fileId).execute().asFile();
|
||||
cacheKey = Optional.of(remoteFile.fileId() + remoteFile.hash());
|
||||
} catch(ApiError ex) {
|
||||
handleApiError(ex);
|
||||
}
|
||||
try {
|
||||
remoteFile = client().loadFile(file.getPath()).execute().asFile();
|
||||
cacheKey = Optional.of(remoteFile.fileId() + remoteFile.hash());
|
||||
} catch(ApiError ex) {
|
||||
handleApiError(ex);
|
||||
}
|
||||
|
||||
File cachedFile = diskLruCache.get(cacheKey.get());
|
||||
@ -376,23 +266,22 @@ class PCloudImpl {
|
||||
retrieveFromLruCache(cacheFile.get(), data);
|
||||
} catch (IOException e) {
|
||||
Timber.tag("PCloudImpl").w(e, "Error while retrieving content from Cache, get from web request");
|
||||
writeToData(file, fileId, data, encryptedTmpFile, cacheKey, progressAware);
|
||||
writeToData(file, data, encryptedTmpFile, cacheKey, progressAware);
|
||||
}
|
||||
} else {
|
||||
writeToData(file, fileId, data, encryptedTmpFile, cacheKey, progressAware);
|
||||
writeToData(file, data, encryptedTmpFile, cacheKey, progressAware);
|
||||
}
|
||||
|
||||
progressAware.onProgress(Progress.completed(DownloadState.download(file)));
|
||||
}
|
||||
|
||||
private void writeToData(final PCloudFile file, //
|
||||
final long fileId, //
|
||||
final OutputStream data, //
|
||||
final Optional<File> encryptedTmpFile, //
|
||||
final Optional<String> cacheKey, //
|
||||
final ProgressAware<DownloadState> progressAware) throws IOException, BackendException {
|
||||
try {
|
||||
FileLink fileLink = client().createFileLink(fileId, DownloadOptions.DEFAULT).execute();
|
||||
FileLink fileLink = client().createFileLink(file.getPath(), DownloadOptions.DEFAULT).execute();
|
||||
|
||||
ProgressListener listener = (done, total) -> progressAware.onProgress( //
|
||||
progress(DownloadState.download(file)) //
|
||||
@ -426,12 +315,11 @@ class PCloudImpl {
|
||||
try {
|
||||
if (node instanceof PCloudFolder) {
|
||||
client() //
|
||||
.deleteFolder(node.getId(), true).execute();
|
||||
.deleteFolder(node.getPath(), true).execute();
|
||||
} else {
|
||||
client() //
|
||||
.deleteFile(node.getId()).execute();
|
||||
.deleteFile(node.getPath()).execute();
|
||||
}
|
||||
idCache.remove(node);
|
||||
} catch(ApiError ex) {
|
||||
handleApiError(ex);
|
||||
}
|
||||
|
@ -4,8 +4,6 @@ import org.cryptomator.domain.CloudNode;
|
||||
|
||||
interface PCloudNode extends CloudNode {
|
||||
|
||||
Long getId();
|
||||
|
||||
@Override
|
||||
PCloudFolder getParent();
|
||||
|
||||
|
@ -9,27 +9,27 @@ import org.cryptomator.util.Optional;
|
||||
class PCloudNodeFactory {
|
||||
|
||||
public static PCloudFile file(PCloudFolder parent, RemoteFile file) {
|
||||
return new PCloudFile(parent, file.name(), getNodePath(parent, file.name()), file.fileId(), Optional.ofNullable(file.size()), Optional.ofNullable(file.lastModified()));
|
||||
return new PCloudFile(parent, file.name(), getNodePath(parent, file.name()), Optional.ofNullable(file.size()), Optional.ofNullable(file.lastModified()));
|
||||
}
|
||||
|
||||
public static PCloudFile file(PCloudFolder parent, String name, Optional<Long> size) {
|
||||
return new PCloudFile(parent, name, getNodePath(parent, name), null, size, Optional.empty());
|
||||
return new PCloudFile(parent, name, getNodePath(parent, name), size, Optional.empty());
|
||||
}
|
||||
|
||||
public static PCloudFile file(PCloudFolder folder, String name, Optional<Long> size, String path, Long fileId) {
|
||||
return new PCloudFile(folder, name, path, fileId, size, Optional.empty());
|
||||
public static PCloudFile file(PCloudFolder folder, String name, Optional<Long> size, String path) {
|
||||
return new PCloudFile(folder, name, path, size, Optional.empty());
|
||||
}
|
||||
|
||||
public static PCloudFolder folder(PCloudFolder parent, RemoteFolder folder) {
|
||||
return new PCloudFolder(parent, folder.name(), getNodePath(parent, folder.name()), folder.folderId());
|
||||
return new PCloudFolder(parent, folder.name(), getNodePath(parent, folder.name()));
|
||||
}
|
||||
|
||||
public static PCloudFolder folder(PCloudFolder parent, String name) {
|
||||
return new PCloudFolder(parent, name, getNodePath(parent, name), null);
|
||||
return new PCloudFolder(parent, name, getNodePath(parent, name));
|
||||
}
|
||||
|
||||
public static PCloudFolder folder(PCloudFolder parent, String name, String path, Long folderId) {
|
||||
return new PCloudFolder(parent, name, path, folderId);
|
||||
public static PCloudFolder folder(PCloudFolder parent, String name, String path) {
|
||||
return new PCloudFolder(parent, name, path);
|
||||
}
|
||||
|
||||
public static String getNodePath(PCloudFolder parent, String name) {
|
||||
|
@ -1,7 +1,5 @@
|
||||
package org.cryptomator.data.cloud.pcloud;
|
||||
|
||||
import com.pcloud.sdk.RemoteFolder;
|
||||
|
||||
import org.cryptomator.domain.Cloud;
|
||||
import org.cryptomator.domain.PCloud;
|
||||
|
||||
@ -10,7 +8,7 @@ class RootPCloudFolder extends PCloudFolder {
|
||||
private final PCloud cloud;
|
||||
|
||||
public RootPCloudFolder(PCloud cloud) {
|
||||
super(null, "", "", (long) RemoteFolder.ROOT_FOLDER_ID);
|
||||
super(null, "", "");
|
||||
this.cloud = cloud;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user