X-Git-Url: http://git.sourceforge.jp/view?p=neighbornote%2FNeighborNote.git;a=blobdiff_plain;f=src%2Fcx%2Ffbn%2Fnevernote%2Fthreads%2FSyncRunner.java;h=1fcc42ae6bc9b63badc78d2e23d9dda745114b21;hp=bb90835fe1eeb2076b68ee20dde623b66d60e238;hb=ace5c30f5af3febc965296bff2ac83a4d5a0ad74;hpb=f4a3681a3af02dffbee9f351eb79dc67e2bd2e13 diff --git a/src/cx/fbn/nevernote/threads/SyncRunner.java b/src/cx/fbn/nevernote/threads/SyncRunner.java index bb90835..1fcc42a 100644 --- a/src/cx/fbn/nevernote/threads/SyncRunner.java +++ b/src/cx/fbn/nevernote/threads/SyncRunner.java @@ -18,15 +18,32 @@ */ package cx.fbn.nevernote.threads; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; import java.util.List; +import java.util.TreeSet; import java.util.Vector; import java.util.concurrent.LinkedBlockingQueue; +import org.apache.http.HttpEntity; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; +import org.apache.http.protocol.HTTP; import org.apache.thrift.TException; import org.apache.thrift.protocol.TBinaryProtocol; import org.apache.thrift.transport.THttpClient; @@ -39,14 +56,19 @@ import com.evernote.edam.notestore.NoteStore; import com.evernote.edam.notestore.SyncChunk; import com.evernote.edam.notestore.SyncState; import com.evernote.edam.type.Data; +import com.evernote.edam.type.LinkedNotebook; import com.evernote.edam.type.Note; import com.evernote.edam.type.Notebook; import com.evernote.edam.type.Resource; import com.evernote.edam.type.SavedSearch; +import com.evernote.edam.type.SharedNotebook; import com.evernote.edam.type.Tag; import com.evernote.edam.type.User; import com.evernote.edam.userstore.AuthenticationResult; import com.evernote.edam.userstore.UserStore; +import com.trolltech.qt.core.QByteArray; +import com.trolltech.qt.core.QFile; +import com.trolltech.qt.core.QIODevice.OpenModeFlag; import com.trolltech.qt.core.QObject; import com.trolltech.qt.gui.QMessageBox; @@ -99,6 +121,7 @@ public class SyncRunner extends QObject implements Runnable { private THttpClient userStoreTrans; private TBinaryProtocol userStoreProt; private AuthenticationResult authResult; + private AuthenticationResult linkedAuthResult; private User user; private long authTimeRemaining; public long authRefreshTime; @@ -110,12 +133,14 @@ public class SyncRunner extends QObject implements Runnable { public int updateSequenceNumber; private boolean refreshNeeded; private volatile LinkedBlockingQueue workQueue; -// private static int MAX_EMPTY_QUEUE_COUNT = 1; private static int MAX_QUEUED_WAITING = 1000; String dbuid; String dburl; String dbpswd; String dbcpswd; + private final TreeSet ignoreTags; + private final TreeSet ignoreNotebooks; + private final TreeSet ignoreLinkedNotebooks; @@ -146,6 +171,10 @@ public class SyncRunner extends QObject implements Runnable { userStore = null; authToken = null; disableUploads = false; + ignoreTags = new TreeSet(); + ignoreNotebooks = new TreeSet(); + ignoreLinkedNotebooks = new TreeSet(); + // setAutoDelete(false); workQueue=new LinkedBlockingQueue(MAX_QUEUED_WAITING); } @@ -161,7 +190,7 @@ public class SyncRunner extends QObject implements Runnable { return; idle=false; error=false; - if (authRefreshNeeded == true) { + if (authRefreshNeeded == true || !isConnected) { logger.log(logger.EXTREME, "Refreshing connection"); refreshConnection(); } @@ -182,6 +211,10 @@ public class SyncRunner extends QObject implements Runnable { idle=true; logger.log(logger.EXTREME, "Signaling refresh finished. refreshNeeded=" +refreshNeeded); syncSignal.finished.emit(refreshNeeded); + if (error) { + syncSignal.errorDisconnect.emit(); + status.message.emit(tr("Error synchronizing - see log for details.")); + } } } catch (InterruptedException e1) { @@ -230,7 +263,24 @@ public class SyncRunner extends QObject implements Runnable { @SuppressWarnings("unused") private void evernoteSync() throws java.net.UnknownHostException { logger.log(logger.HIGH, "Entering SyncRunner.evernoteSync"); + + // Rebuild list of tags & notebooks to ignore + ignoreNotebooks.clear(); + List ignore = conn.getSyncTable().getIgnoreRecords("NOTEBOOK"); + for (int i=0; i guids = conn.getNoteTable().noteResourceTable.findInkNotes(); + for (int i=0; i notes = conn.getNoteTable().expungeIgnoreSynchronizedNotes(conn.getSyncTable().getIgnoreRecords("NOTEBOOK"), + conn.getSyncTable().getIgnoreRecords("TAG"), conn.getSyncTable().getIgnoreRecords("LINKEDNOTEBOOK")); + if (notes.size() > 0) + syncSignal.refreshLists.emit(); + + //***************************************** + //* End of synchronization + //***************************************** if (refreshNeeded) syncSignal.refreshLists.emit(); + if (!error) { logger.log(logger.EXTREME, "Sync completed. Errors=" +error); if (!disableUploads) @@ -355,16 +448,18 @@ public class SyncRunner extends QObject implements Runnable { } logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync"); } + // Sync deleted items with Evernote private void syncExpunged() { logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged"); List expunged = conn.getDeletedTable().getAllDeleted(); boolean error = false; - for (int i=0; i notes = conn.getNoteTable().getDirty(); // Sync the local notebooks with Evernote's for (int i=0; i 0) { - enNote = getNoteContent(enNote); - logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); - enNote = noteStore.updateNote(authToken, enNote); - } else { - logger.log(logger.EXTREME, "Active dirty found - new note"); - logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); - String oldGuid = enNote.getGuid(); - enNote = getNoteContent(enNote); - enNote = noteStore.createNote(authToken, enNote); - noteSignal.guidChanged.emit(oldGuid, enNote.getGuid()); - conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid()); - } - updateSequenceNumber = enNote.getUpdateSequenceNum(); - logger.log(logger.EXTREME, "Saving note"); - conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); - List rl = enNote.getResources(); - logger.log(logger.EXTREME, "Getting note resources"); - for (int j=0; j 0) { + enNote = getNoteContent(enNote); + logger.log(logger.MEDIUM, "Updating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); + enNote = noteStore.updateNote(token, enNote); + } else { + logger.log(logger.EXTREME, "Active dirty found - new note"); + logger.log(logger.MEDIUM, "Creating note : "+ enNote.getGuid() +" " +enNote.getTitle()+""); + String oldGuid = enNote.getGuid(); + enNote = getNoteContent(enNote); + enNote = noteStore.createNote(token, enNote); + noteSignal.guidChanged.emit(oldGuid, enNote.getGuid()); + conn.getNoteTable().updateNoteGuid(oldGuid, enNote.getGuid()); + } + updateSequenceNumber = enNote.getUpdateSequenceNum(); + logger.log(logger.EXTREME, "Saving note"); + conn.getNoteTable().updateNoteSequence(enNote.getGuid(), enNote.getUpdateSequenceNum()); + List rl = enNote.getResources(); + logger.log(logger.EXTREME, "Getting note resources"); + for (int j=0; j 0) { @@ -730,7 +837,43 @@ public class SyncRunner extends QObject implements Runnable { } logger.log(logger.HIGH, "Leaving SyncRunner.syncLocalTags"); } - // Sync Tags with Evernote + private void syncLocalLinkedNotebooks() { + logger.log(logger.HIGH, "Entering SyncRunner.syncLocalLinkedNotebooks"); + + List list = conn.getLinkedNotebookTable().getDirtyGuids(); + for (int i=0; i remoteList = new ArrayList(); @@ -763,7 +906,8 @@ public class SyncRunner extends QObject implements Runnable { for (int i=0; i guid = chunk.getExpungedNotes(); - if (guid != null) { - for (int i=0; i guid = chunk.getExpungedNotes(); + if (guid != null) { + for (int i=0; i tags) { logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); @@ -951,7 +1107,7 @@ public class SyncRunner extends QObject implements Runnable { } logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags"); } - // Sync remote tags + // Sync remote saved searches private void syncRemoteSavedSearches(List searches) { logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches"); if (searches != null) { @@ -965,6 +1121,16 @@ public class SyncRunner extends QObject implements Runnable { } logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches"); } + // Sync remote linked notebooks + private void syncRemoteLinkedNotebooks(List books) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncLinkedNotebooks"); + if (books != null) { + for (int i=0; i notebooks) { logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); @@ -975,99 +1141,132 @@ public class SyncRunner extends QObject implements Runnable { if (oldGuid != null && !conn.getNotebookTable().isNotebookLocal(oldGuid) && !notebooks.get(i).getGuid().equalsIgnoreCase(oldGuid)) conn.getNotebookTable().updateNotebookGuid(oldGuid, notebooks.get(i).getGuid()); conn.getNotebookTable().syncNotebook(notebooks.get(i), false); + + // Synchronize shared notebook information +// if (notebooks.get(i).getSharedNotebookIdsSize() > 0) { +// conn.getSharedNotebookTable().expungeNotebookByGuid(notebooks.get(i).getGuid(), false); +// for (int j=0; j books = noteStore.getSharedNotebookByAuth(authToken); +// } // Sync remote Resources private void syncRemoteResources(List resource) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteResources"); + if (resource != null) { + for (int i=0; i note, boolean fullSync) { + // Sync remote notes + private void syncRemoteNotes(List note, boolean fullSync, String token) { logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes"); if (note != null) { for (int i=0; i=5) { logger.log(logger.EXTREME, "Refresh attempts have failed. Disconnecting."); isConnected = false; - return; + status.message.emit(tr("Unable to synchronize - Authentication failed")); + return false; } // If this is the first time through, then we need to set this @@ -1368,31 +1567,33 @@ public class SyncRunner extends QObject implements Runnable { if (userStore != null && authToken != null) newAuth = userStore.refreshAuthentication(authToken); else - return; + return false; logger.log(logger.EXTREME, "UserStore.refreshAuthentication has succeeded."); } catch (EDAMUserException e) { e.printStackTrace(); syncSignal.authRefreshComplete.emit(false); failedRefreshes++; - return; + return false; } catch (EDAMSystemException e) { e.printStackTrace(); syncSignal.authRefreshComplete.emit(false); failedRefreshes++; - return; + return false; } catch (TException e) { e.printStackTrace(); syncSignal.authRefreshComplete.emit(false); failedRefreshes++; - return; + return false; } // If we didn't get a good auth, then we've failed if (newAuth == null) { failedRefreshes++; + status.message.emit(tr("Unable to synchronize - Authentication failed")); logger.log(logger.EXTREME, "Authentication failure #" +failedRefreshes); + status.message.emit(tr("Unable to synchronize - Authentication failed")); syncSignal.authRefreshComplete.emit(false); - return; + return false; } // We got a good token. Now we need to setup the time to renew it. @@ -1410,6 +1611,8 @@ public class SyncRunner extends QObject implements Runnable { // failedRefreshes++; // syncSignal.authRefreshComplete.emit(false); // } + + return true; } public synchronized boolean addWork(String request) { @@ -1422,4 +1625,337 @@ public class SyncRunner extends QObject implements Runnable { n.setContent(conn.getNoteTable().getNoteContentBinary(n.getGuid())); return n; } + + + + //********************************************************* + //* Special download instructions. Used for DB upgrades + //********************************************************* + private void downloadAllSharedNotebooks() { + try { + List books = noteStore.listSharedNotebooks(authToken); + logger.log(logger.LOW, "Shared notebooks found = " +books.size()); + for (int i=0; i books = noteStore.listNotebooks(authToken); + logger.log(logger.LOW, "Shared notebooks found = " +books.size()); + for (int i=0; i books = noteStore.listLinkedNotebooks(authToken); + logger.log(logger.LOW, "Linked notebooks found = " +books.size()); + for (int i=0; i nvps = new ArrayList (); + nvps.add(new BasicNameValuePair("auth", authToken)); + + try { + post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8)); + } catch (UnsupportedEncodingException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + try { + HttpResponse response = http.execute(post); + HttpEntity resEntity = response.getEntity(); + InputStream is = resEntity.getContent(); + QByteArray data = writeToFile(is); + conn.getInkImagesTable().saveImage(guid, slice, data); + } catch (ClientProtocolException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + slice++; + } + http.getConnectionManager().shutdown(); + noteSignal.noteChanged.emit(r.getNoteGuid(), null); // Signal to ivalidate note cache + } + + + public QByteArray writeToFile(InputStream iStream) throws IOException { + + File temp = File.createTempFile("nn-inknote-temp", ".png"); + + // Save InputStream to the file. + BufferedOutputStream fOut = null; + try { + fOut = new BufferedOutputStream(new FileOutputStream(temp)); + byte[] buffer = new byte[32 * 1024]; + int bytesRead = 0; + while ((bytesRead = iStream.read(buffer)) != -1) { + fOut.write(buffer, 0, bytesRead); + } + } + finally { + iStream.close(); + fOut.close(); + } + QFile tempFile = new QFile(temp.getAbsoluteFile().toString()); + tempFile.open(OpenModeFlag.ReadOnly); + QByteArray data = tempFile.readAll(); + tempFile.close(); + tempFile.remove(); + return data; + } + + + //****************************************** + //* Begin syncing shared notebooks + //****************************************** + private void syncLinkedNotebooks() { + logger.log(logger.MEDIUM, "Authenticating Shared Notebooks"); + status.message.emit(tr("Synchronizing shared notebooks.")); + List books = conn.getLinkedNotebookTable().getAll(); + for (int i=0; i lastSequenceNumber) { + if (lastSyncDate < linkedSyncState.getFullSyncBefore()) { + lastSequenceNumber = 0; + } + syncLinkedNotebook(books.get(i), lastSequenceNumber, linkedSyncState.getUpdateCount()); + } + + // Synchronize local changes + syncLocalLinkedNoteChanges(books.get(i)); + + } catch (EDAMUserException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (EDAMNotFoundException e) { + status.message.emit(tr("Error synchronizing \" " + + books.get(i).getShareName()+"\". Please verify you still have access to that shared notebook.")); + error = true; + e.printStackTrace(); + } catch (EDAMSystemException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (TException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + // Cleanup tags + conn.getTagTable().removeUnusedLinkedTags(); + conn.getTagTable().cleanupTags(); + tagSignal.listChanged.emit(); + } + + + //************************************************************** + //* Linked notebook contents (from someone else's account) + //************************************************************* + private void syncLinkedNotebook(LinkedNotebook book, int usn, int highSequence) { + boolean fullSync = false; + if (usn == 0) + fullSync = true; + while (usn < highSequence) { + try { + SyncChunk chunk = + noteStore.getLinkedNotebookSyncChunk(authToken, book, usn, 10, fullSync); + + if (!ignoreLinkedNotebooks.contains(book.getGuid())) + syncRemoteNotes(chunk.getNotes(), fullSync, linkedAuthResult.getAuthenticationToken()); + findNewLinkedTags(chunk.getNotes(), linkedAuthResult.getAuthenticationToken()); + for (int i=0; i tags, String notebookGuid) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteTags"); + if (tags != null) { + for (int i=0; i notebooks, boolean readOnly, LinkedNotebook linked) { + logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks"); + if (notebooks != null) { + for (int i=0; i newNotes, String token) { + if (newNotes == null) + return; + for (int i=0; i notes = conn.getNoteTable().getDirtyLinked(notebookGuid); + for (int i=0; i