private void visitEntry(final Entry entry, DropboxEntryVisitor visitor) { if (null != entry.contents) { logger.debug(entry.path + "contents size: " + entry.contents.size()); for (Entry child : entry.contents) { if (!child.isDeleted) { if (!child.isDir) { visitor.visitFile(child); } else { try { visitor.preVisitDirectory(child); } catch (IOException e) { logger.error(e.getMessage()); } try { Entry childWithContents = api.metadata( child.path, 0, MetaHandler.getHash(child.path), true, MetaHandler.getRev(child.path)); visitEntry(childWithContents, visitor); } catch (DropboxException e) { logger.error(e.getMessage()); } visitor.postVisitDirectory(child); } } } } }
private void loadMetadata(DropboxFile file) { Log.d(TAG, "Loading metadata for " + file.getRemoteFile()); DropboxAPI.Entry metadata = null; try { metadata = dropboxApi.metadata(file.getRemoteFile(), 0, null, false, null); } catch (DropboxServerException se) { if (se.error == DropboxServerException._404_NOT_FOUND) { Log.d(TAG, "metadata NOT found! Returning NOT_FOUND status."); file.setStatus(DropboxFileStatus.NOT_FOUND); return; } throw new RemoteException("Server Exception: " + se.error + " " + se.reason, se); } catch (DropboxException e) { throw new RemoteException("Dropbox Exception: " + e.getMessage(), e); } Log.d(TAG, "Metadata retrieved. rev on Dropbox = " + metadata.rev); Log.d(TAG, "local rev = " + file.getOriginalRev()); file.setLoadedMetadata(metadata); if (metadata.rev.equals(file.getOriginalRev())) { // don't bother downloading if the rev is the same Log.d(TAG, "revs match. returning NOT_CHANGED status."); file.setStatus(DropboxFileStatus.NOT_CHANGED); } else if (metadata.isDeleted) { Log.d(TAG, "File marked as deleted on Dropbox! Returning NOT_FOUND status."); file.setStatus(DropboxFileStatus.NOT_FOUND); } else { Log.d(TAG, "revs don't match. returning FOUND status."); file.setStatus(DropboxFileStatus.FOUND); } }
private void syncStorage() { try { logger.debug("Synching storage."); final String rootDir = "/"; Entry folderEntry = api.metadata(rootDir, 0, MetaHandler.getHash(rootDir), true, MetaHandler.getRev(rootDir)); // TODO handle removed entries visitEntry( folderEntry, new DropboxEntryVisitor() { @Override public void preVisitDirectory(Entry entry) throws IOException { if (!MetaHandler.isStored(entry.path)) { logger.debug("Creating local dir: " + entry.path); Path filePath = FileSystems.getDefault().getPath(startDir.toString(), entry.path.substring(1)); WatchKey key = filePath .getParent() .register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.remove(key); key.cancel(); filePath.toFile().mkdir(); key = filePath .getParent() .register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.put(key, filePath.getParent()); MetaHandler.setFile(entry.path, filePath.toFile(), entry.rev); } } @Override public void visitFile(Entry entry) { if (!MetaHandler.isStored(entry.path)) downloadFile(entry.path); else if (!MetaHandler.isCurrent(entry.path, entry.rev)) { Path fullPath = FileSystems.getDefault().getPath(startDir.toString(), entry.path.substring(1)); try { logger.debug("Uploading file " + entry.path); uploadFile(entry.path, fullPath); } catch (Exception e) { logger.error("Error uploading file: " + e.getMessage()); } } } }); } catch (DropboxException ex) { logger.error("Error syching root dir: " + ex.getMessage()); } }
public void downloadFile(String relPath) { VOSync.debug("Downloading file from storage: " + relPath); Path filePath = FileSystems.getDefault().getPath(startDir.toString(), relPath.substring(1)); try { WatchKey key = filePath.getParent().register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.remove(key); key.cancel(); FileOutputStream outp = new FileOutputStream(filePath.toFile()); DropboxFileInfo info = api.getFile(relPath, null, outp, null); outp.close(); key = filePath.getParent().register(watcher, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); keys.put(key, filePath.getParent()); MetaHandler.setFile(relPath, filePath.toFile(), info.getMetadata().rev); } catch (IOException ex) { logger.error("Error downloading file " + relPath + ": " + ex.getMessage()); } catch (DropboxException ex) { ex.printStackTrace(); logger.error("Error downloading file " + relPath + ": " + ex.getMessage()); } }
@Override public void run() { logger.debug("Register root " + startDir.toString()); try { registerAll(startDir); } catch (IOException ex) { logger.error(ex.getMessage()); return; } if (isInterrupted()) return; VOSync.debug("Sync local db with drive"); DbPool.goSql( "Synching the local db with drive", "select NAME from FILES", new SqlWorker<Boolean>() { @Override public Boolean go(Connection conn, PreparedStatement stmt) throws SQLException { ResultSet resSet = stmt.executeQuery(); while (resSet.next()) { try { String fileName = resSet.getString(1); Path filePath = FileSystems.getDefault().getPath(startDir.toString(), fileName.substring(1)); if (!filePath.toFile().exists()) { logger.debug( "Deleting file " + fileName + " existing in DB and not present on disk"); api.delete(fileName); MetaHandler.delete(fileName); } } catch (DropboxException ex) { } } resSet.close(); return true; } }); if (isInterrupted()) return; VOSync.debug("Sync storage"); syncStorage(); logger.debug("Start watching"); while (!isInterrupted()) { WatchKey key; try { key = watcher.take(); } catch (InterruptedException x) { return; } Path dir = keys.get(key); if (dir == null) { System.err.println("WatchKey " + key.toString() + " not recognized!"); continue; } for (WatchEvent<?> event : key.pollEvents()) { Kind<?> kind = event.kind(); // TBD - provide example of how OVERFLOW event is handled if (kind == OVERFLOW) { continue; } // Context for directory entry event is the file name of entry WatchEvent<Path> ev = cast(event); Path name = ev.context(); Path child = dir.resolve(name); Path relativeDir = startDir.relativize(child); String fileRelPath = "/" + fixPath(relativeDir.toString()); // print out event logger.debug(event.kind().name() + ":" + child + " " + name + " " + key); try { if (Files.exists(child, new LinkOption[] {}) && Files.isHidden(child)) { logger.error( "Skipping hidden file " + child.getFileName()); // skip OS generated catalog files } else { if (event.kind() == ENTRY_CREATE) { if (Files.isRegularFile(child, NOFOLLOW_LINKS)) { // file modified uploadFile(fileRelPath, child); } else if (Files.isDirectory(child, NOFOLLOW_LINKS)) { // directory contents changed registerAll(child); } } else if (event.kind() == ENTRY_DELETE) { logger.debug("Deleting " + fileRelPath); api.delete(fileRelPath); MetaHandler.delete(fileRelPath); logger.debug("Deleted!"); } else if (event.kind() == ENTRY_MODIFY) { if (Files.isRegularFile(child, NOFOLLOW_LINKS)) { // file modified uploadFile(fileRelPath, child); } else if (Files.isDirectory(child, NOFOLLOW_LINKS)) { // directory contents changed // logger.debug("Renewing dir: "+relativeDir.toString()); // TODO update folder date // MetaHandler.setFile(fileRelPath, child, rev); } } } } catch (IOException ex) { ex.printStackTrace(); logger.error(ex.getMessage()); } catch (DropboxException ex) { ex.printStackTrace(); logger.error(ex.getMessage()); } } boolean valid = key.reset(); if (!valid) keys.remove(key); } }