OSDN Git Service

Cleanup of initial sync with ink notes and added the ability to highlight words in...
[neighbornote/NeighborNote.git] / src / cx / fbn / nevernote / threads / SyncRunner.java
index 525545e..912e63a 100644 (file)
 */\r
 package cx.fbn.nevernote.threads;\r
 \r
+import java.io.BufferedOutputStream;\r
+import java.io.File;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.UnsupportedEncodingException;\r
 import java.net.UnknownHostException;\r
 import java.util.ArrayList;\r
 import java.util.Calendar;\r
@@ -27,6 +33,16 @@ import java.util.List;
 import java.util.Vector;\r
 import java.util.concurrent.LinkedBlockingQueue;\r
 \r
+import org.apache.http.HttpEntity;\r
+import org.apache.http.HttpResponse;\r
+import org.apache.http.NameValuePair;\r
+import org.apache.http.client.ClientProtocolException;\r
+import org.apache.http.client.HttpClient;\r
+import org.apache.http.client.entity.UrlEncodedFormEntity;\r
+import org.apache.http.client.methods.HttpPost;\r
+import org.apache.http.impl.client.DefaultHttpClient;\r
+import org.apache.http.message.BasicNameValuePair;\r
+import org.apache.http.protocol.HTTP;\r
 import org.apache.thrift.TException;\r
 import org.apache.thrift.protocol.TBinaryProtocol;\r
 import org.apache.thrift.transport.THttpClient;\r
@@ -39,14 +55,19 @@ import com.evernote.edam.notestore.NoteStore;
 import com.evernote.edam.notestore.SyncChunk;\r
 import com.evernote.edam.notestore.SyncState;\r
 import com.evernote.edam.type.Data;\r
+import com.evernote.edam.type.LinkedNotebook;\r
 import com.evernote.edam.type.Note;\r
 import com.evernote.edam.type.Notebook;\r
 import com.evernote.edam.type.Resource;\r
 import com.evernote.edam.type.SavedSearch;\r
+import com.evernote.edam.type.SharedNotebook;\r
 import com.evernote.edam.type.Tag;\r
 import com.evernote.edam.type.User;\r
 import com.evernote.edam.userstore.AuthenticationResult;\r
 import com.evernote.edam.userstore.UserStore;\r
+import com.trolltech.qt.core.QByteArray;\r
+import com.trolltech.qt.core.QFile;\r
+import com.trolltech.qt.core.QIODevice.OpenModeFlag;\r
 import com.trolltech.qt.core.QObject;\r
 import com.trolltech.qt.gui.QMessageBox;\r
 \r
@@ -307,7 +328,29 @@ public class SyncRunner extends QObject implements Runnable {
                                updateSequenceNumber = 0;\r
                                conn.getSyncTable().setUpdateSequenceNumber(0);\r
                        }\r
-\r
+                       // Check for "special" sync instructions\r
+                       String syncLinked = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
+                       String syncShared = conn.getSyncTable().getRecord("FullLinkedNotebookSync");\r
+                       String syncNotebooks = conn.getSyncTable().getRecord("FullNotebookSync");\r
+                       String syncInkNoteImages = conn.getSyncTable().getRecord("FullInkNoteImageSync");\r
+                       if (syncLinked != null) {\r
+                               downloadAllLinkedNotebooks();\r
+                       }\r
+                       if (syncShared != null) {\r
+                               downloadAllSharedNotebooks();\r
+                       }\r
+                       if (syncNotebooks != null) {\r
+                               downloadAllNotebooks();\r
+                       }\r
+                       \r
+                       if (syncInkNoteImages != null) {\r
+                               List<String> guids = conn.getNoteTable().noteResourceTable.findInkNotes();\r
+                               for (int i=0; i<guids.size(); i++) {\r
+                                       downloadInkNoteImage(guids.get(i));\r
+                               }\r
+                               conn.getSyncTable().deleteRecord("FullInkNoteImageSync");\r
+                       }\r
+                       \r
                        // If there are remote changes\r
                        logger.log(logger.LOW, "Update Count: " +syncState.getUpdateCount());\r
                        logger.log(logger.LOW, "Last Update Count: " +updateSequenceNumber);\r
@@ -337,6 +380,7 @@ public class SyncRunner extends QObject implements Runnable {
                        }\r
                        if (refreshNeeded)\r
                                syncSignal.refreshLists.emit();\r
+                       \r
                        if (!error) {\r
                                logger.log(logger.EXTREME, "Sync completed.  Errors=" +error);\r
                                if (!disableUploads) \r
@@ -355,13 +399,14 @@ public class SyncRunner extends QObject implements Runnable {
                }\r
                logger.log(logger.HIGH, "Leaving SyncRunner.evernoteSync");\r
        }\r
+       \r
        // Sync deleted items with Evernote\r
        private void syncExpunged() {\r
                logger.log(logger.HIGH, "Entering SyncRunner.syncExpunged");\r
                \r
                List<DeletedItemRecord> expunged = conn.getDeletedTable().getAllDeleted();\r
                boolean error = false;\r
-               for (int i=0; i<expunged.size(); i++) {\r
+               for (int i=0; i<expunged.size() && keepRunning; i++) {\r
                        \r
                        if (authRefreshNeeded)\r
                                refreshConnection();\r
@@ -872,15 +917,25 @@ public class SyncRunner extends QObject implements Runnable {
                        syncRemoteNotebooks(chunk.getNotebooks());\r
                        syncRemoteNotes(chunk.getNotes(), fullSync);\r
                        syncRemoteResources(chunk.getResources());\r
+                       syncRemoteLinkedNotebooks(chunk.getLinkedNotebooks());\r
                        \r
                        // Do the local deletes\r
                        logger.log(logger.EXTREME, "Doing local deletes");\r
                        List<String> guid = chunk.getExpungedNotes();\r
-                       if (guid != null) \r
+                       if (guid != null) {\r
                                for (int i=0; i<guid.size() && keepRunning; i++) {\r
-                                       logger.log(logger.EXTREME, "Expunging local note from database");\r
-                                       conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
+                                       String notebookGuid = "";\r
+                                       Note localNote = conn.getNoteTable().getNote(guid.get(i), false, false, false, false, false);\r
+                                       if (localNote != null) {\r
+                                               conn.getNoteTable().updateNoteSequence(guid.get(i), 0);\r
+                                               notebookGuid = localNote.getNotebookGuid();\r
+                                       }\r
+                                       if (!conn.getNotebookTable().isNotebookLocal(notebookGuid)) {\r
+                                               logger.log(logger.EXTREME, "Expunging local note from database");\r
+                                               conn.getNoteTable().expungeNote(guid.get(i), true, false);\r
+                                       }\r
                                }\r
+                       }\r
                        guid = chunk.getExpungedNotebooks();\r
                        if (guid != null)\r
                                for (int i=0; i<guid.size() && keepRunning; i++) {\r
@@ -899,6 +954,12 @@ public class SyncRunner extends QObject implements Runnable {
                                        logger.log(logger.EXTREME, "Expunging saved search from local database");\r
                                        conn.getSavedSearchTable().expungeSavedSearch(guid.get(i), false);\r
                                }\r
+                       guid = chunk.getExpungedLinkedNotebooks();\r
+                       if (guid != null) \r
+                               for (int i=0; i<guid.size() && keepRunning; i++) {\r
+                                       logger.log(logger.EXTREME, "Expunging linked notebook from local database");\r
+                                       conn.getLinkedNotebookTable().expungeNotebook(guid.get(i), false);\r
+                               }\r
 \r
                        \r
                        // Check for more notes\r
@@ -942,7 +1003,7 @@ public class SyncRunner extends QObject implements Runnable {
                }\r
                logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteTags");\r
        }\r
-       // Sync remote tags\r
+       // Sync remote saved searches\r
        private void syncRemoteSavedSearches(List<SavedSearch> searches) {\r
                logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
                if (searches != null) {\r
@@ -956,6 +1017,16 @@ public class SyncRunner extends QObject implements Runnable {
                }\r
                logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
        }\r
+       // Sync remote linked notebooks\r
+       private void syncRemoteLinkedNotebooks(List<LinkedNotebook> books) {\r
+               logger.log(logger.EXTREME, "Entering SyncRunner.syncSavedSearches");\r
+               if (books != null) {\r
+                       for (int i=0; i<books.size() && keepRunning; i++) {\r
+                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false); \r
+                       }\r
+               }\r
+               logger.log(logger.EXTREME, "Leaving SyncRunner.syncSavedSearches");\r
+       }\r
        // Sync remote Notebooks 2\r
        private void syncRemoteNotebooks(List<Notebook> notebooks) {\r
                logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotebooks");\r
@@ -1005,12 +1076,14 @@ public class SyncRunner extends QObject implements Runnable {
                                \r
                                if (saveNeeded) \r
                                        conn.getNoteTable().noteResourceTable.updateNoteResource(r, false);\r
+                               if (r.getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
+                                       downloadInkNoteImage(r.getGuid());\r
 \r
                        }\r
                }\r
                logger.log(logger.EXTREME, "Leaving SyncRunner.syncRemoteResources");\r
        }\r
-       // Sync remote notebooks\r
+       // Sync remote notes\r
        private void syncRemoteNotes(List<Note> note, boolean fullSync) {\r
                logger.log(logger.EXTREME, "Entering SyncRunner.syncRemoteNotes");\r
                if (note != null) {\r
@@ -1046,6 +1119,8 @@ public class SyncRunner extends QObject implements Runnable {
                                                        for (int q=0; q<n.getResources().size() && keepRunning; q++) {\r
                                                                logger.log(logger.EXTREME, "Getting note resources.");\r
                                                                conn.getNoteTable().noteResourceTable.updateNoteResource(n.getResources().get(q), false);\r
+                                                               if (n.getResources().get(q).getMime().equalsIgnoreCase("application/vnd.evernote.ink"))\r
+                                                                       downloadInkNoteImage(n.getResources().get(q).getGuid());\r
                                                        }\r
                                                }\r
                                        }\r
@@ -1413,4 +1488,161 @@ public class SyncRunner extends QObject implements Runnable {
        n.setContent(conn.getNoteTable().getNoteContentBinary(n.getGuid()));\r
        return n;\r
     }\r
+\r
+\r
+\r
+    //*********************************************************\r
+    //* Special download instructions.  Used for DB upgrades\r
+    //*********************************************************\r
+    private void downloadAllSharedNotebooks() {\r
+       try {\r
+                       List<SharedNotebook> books = noteStore.listSharedNotebooks(authToken);\r
+                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
+                       for (int i=0; i<books.size(); i++) {\r
+                               conn.getSharedNotebookTable().updateNotebook(books.get(i), false);\r
+                       }\r
+                       conn.getSyncTable().deleteRecord("FullSharedNotebookSync");\r
+               } catch (EDAMUserException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("User exception Listing shared notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (EDAMSystemException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("System exception Listing shared notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (TException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("Transaction exception Listing shared notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (EDAMNotFoundException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("EDAM Not Found exception Listing shared notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+               }\r
+    }\r
+    private void downloadAllNotebooks() {\r
+       try {\r
+                       List<Notebook> books = noteStore.listNotebooks(authToken);\r
+                       logger.log(logger.LOW, "Shared notebooks found = " +books.size());\r
+                       for (int i=0; i<books.size(); i++) {\r
+                               conn.getNotebookTable().updateNotebook(books.get(i), false);\r
+                       }\r
+                       conn.getSyncTable().deleteRecord("FullNotebookSync");\r
+               } catch (EDAMUserException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("User exception Listing notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (EDAMSystemException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("System exception Listing notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (TException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("Transaction exception Listing notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               }\r
+    }\r
+    private void downloadAllLinkedNotebooks() {\r
+       try {\r
+                       List<LinkedNotebook> books = noteStore.listLinkedNotebooks(authToken);\r
+                       logger.log(logger.LOW, "Linked notebooks found = " +books.size());\r
+                       for (int i=0; i<books.size(); i++) {\r
+                               conn.getLinkedNotebookTable().updateNotebook(books.get(i), false);\r
+                       }\r
+                       conn.getSyncTable().deleteRecord("FullLinkedNotebookSync");\r
+               } catch (EDAMUserException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("User exception Listing linked notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (EDAMSystemException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("System exception Listing linked notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (TException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("Transaction exception Listing lineked notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+                       return;\r
+               } catch (EDAMNotFoundException e1) {\r
+                       e1.printStackTrace();\r
+                       status.message.emit(tr("EDAM Not Found exception Listing linked notebooks."));\r
+                       logger.log(logger.LOW, e1.getMessage());\r
+               }\r
+    }\r
+\r
+    \r
+    private void downloadInkNoteImage(String guid) {\r
+               String urlBase = noteStoreUrl.replace("/edam/note/", "/shard/") + "/res/"+guid+".ink?slice=";\r
+//             urlBase = "https://www.evernote.com/shard/s1/res/52b567a9-54ae-4a08-afc5-d5bae275b2a8.ink?slice=";\r
+               Integer slice = 1;\r
+               Resource r = conn.getNoteTable().noteResourceTable.getNoteResource(guid, false);\r
+               conn.getInkImagesTable().expungeImage(r.getGuid());\r
+               int sliceCount = 1+((r.getHeight()-1)/480);\r
+               HttpClient http = new DefaultHttpClient();\r
+       for (int i=0; i<sliceCount; i++) {\r
+               String url = urlBase + slice.toString();\r
+               HttpPost post = new HttpPost(url);\r
+               post.getParams().setParameter("auth", authToken);\r
+               List <NameValuePair> nvps = new ArrayList <NameValuePair>();\r
+            nvps.add(new BasicNameValuePair("auth", authToken));\r
+\r
+            try {\r
+                               post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));\r
+                       } catch (UnsupportedEncodingException e1) {\r
+                               // TODO Auto-generated catch block\r
+                               e1.printStackTrace();\r
+                       }\r
+               try {\r
+                       HttpResponse response = http.execute(post);\r
+                       HttpEntity resEntity = response.getEntity();\r
+                       InputStream is = resEntity.getContent();\r
+                       QByteArray data = writeToFile(is);\r
+                       conn.getInkImagesTable().saveImage(guid, slice, data);\r
+                       } catch (ClientProtocolException e) {\r
+                               e.printStackTrace();\r
+                       } catch (IOException e) {\r
+                               e.printStackTrace();\r
+                       }\r
+\r
+                       slice++;\r
+       }\r
+       http.getConnectionManager().shutdown(); \r
+               noteSignal.noteChanged.emit(r.getNoteGuid(), null);   // Signal to ivalidate note cache\r
+    }\r
+    \r
+    \r
+    public QByteArray writeToFile(InputStream iStream) throws IOException {\r
+\r
+           File temp = File.createTempFile("nn-inknote-temp", ".png");\r
+\r
+           // Save InputStream to the file.\r
+           BufferedOutputStream fOut = null;\r
+           try {\r
+             fOut = new BufferedOutputStream(new FileOutputStream(temp));\r
+             byte[] buffer = new byte[32 * 1024];\r
+             int bytesRead = 0;\r
+             while ((bytesRead = iStream.read(buffer)) != -1) {\r
+               fOut.write(buffer, 0, bytesRead);\r
+             }\r
+           }\r
+           finally {\r
+               iStream.close();\r
+               fOut.close();\r
+           }\r
+           QFile tempFile = new QFile(temp.getAbsoluteFile().toString());\r
+           tempFile.open(OpenModeFlag.ReadOnly);\r
+           QByteArray data = tempFile.readAll();\r
+           tempFile.close();\r
+           tempFile.remove();\r
+           return data;\r
+    }\r
+    \r
 }\r