Concurrent folder sync

pull/50/head
M66B 6 years ago
parent e578051c2c
commit e60f8a6ffd

@ -431,184 +431,178 @@ public class ServiceSynchronize extends LifecycleService {
throw new IllegalStateException("synchronize folders", ex); throw new IllegalStateException("synchronize folders", ex);
} }
// Synchronize folders
for (EntityFolder folder : db.folder().getFolders(account.id)) for (EntityFolder folder : db.folder().getFolders(account.id))
db.folder().setFolderState(folder.id, null); db.folder().setFolderState(folder.id, null);
for (final EntityFolder folder : db.folder().getFolders(account.id, true))
try {
Log.i(Helper.TAG, account.name + " sync folder " + folder.name);
db.folder().setFolderState(folder.id, "connecting"); // Synchronize folders
for (final EntityFolder folder : db.folder().getFolders(account.id, true)) {
Log.i(Helper.TAG, account.name + " sync folder " + folder.name);
final IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name); db.folder().setFolderState(folder.id, "connecting");
ifolder.open(Folder.READ_WRITE);
folders.put(folder, ifolder);
db.folder().setFolderState(folder.id, "connected"); final IMAPFolder ifolder = (IMAPFolder) istore.getFolder(folder.name);
db.folder().setFolderError(folder.id, null); ifolder.open(Folder.READ_WRITE);
folders.put(folder, ifolder);
// Listen for new and deleted messages db.folder().setFolderState(folder.id, "connected");
ifolder.addMessageCountListener(new MessageCountAdapter() { db.folder().setFolderError(folder.id, null);
@Override
public void messagesAdded(MessageCountEvent e) {
synchronized (lock) {
try {
Log.i(Helper.TAG, folder.name + " messages added");
for (Message imessage : e.getMessages())
try {
synchronizeMessage(folder, ifolder, (IMAPMessage) imessage);
} catch (MessageRemovedException ex) {
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
// Keep folder connection alive
Thread noop = new Thread(new Runnable() {
@Override
public void run() {
try {
// Listen for new and deleted messages
ifolder.addMessageCountListener(new MessageCountAdapter() {
@Override
public void messagesAdded(MessageCountEvent e) {
synchronized (lock) {
try {
Log.i(Helper.TAG, folder.name + " messages added");
for (Message imessage : e.getMessages())
try {
synchronizeMessage(folder, ifolder, (IMAPMessage) imessage);
} catch (MessageRemovedException ex) {
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
}
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) {
state.notifyAll();
}
} }
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) {
state.notifyAll();
} }
} }
}
}
@Override @Override
public void messagesRemoved(MessageCountEvent e) { public void messagesRemoved(MessageCountEvent e) {
synchronized (lock) { synchronized (lock) {
try {
Log.i(Helper.TAG, folder.name + " messages removed");
for (Message imessage : e.getMessages())
try { try {
long uid = ifolder.getUID(imessage); Log.i(Helper.TAG, folder.name + " messages removed");
for (Message imessage : e.getMessages())
DB db = DB.getInstance(ServiceSynchronize.this); try {
int count = db.message().deleteMessage(folder.id, uid); long uid = ifolder.getUID(imessage);
Log.i(Helper.TAG, "Deleted uid=" + uid + " count=" + count); DB db = DB.getInstance(ServiceSynchronize.this);
} catch (MessageRemovedException ex) { int count = db.message().deleteMessage(folder.id, uid);
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
Log.i(Helper.TAG, "Deleted uid=" + uid + " count=" + count);
} catch (MessageRemovedException ex) {
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
}
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) {
state.notifyAll();
}
} }
} catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) {
state.notifyAll();
} }
} }
} });
}
});
// Fetch e-mail // Fetch e-mail
synchronizeMessages(account, folder, ifolder, state); synchronizeMessages(account, folder, ifolder, state);
// Flags (like "seen") at the remote could be changed while synchronizing // Flags (like "seen") at the remote could be changed while synchronizing
// Listen for changed messages // Listen for changed messages
ifolder.addMessageChangedListener(new MessageChangedListener() { ifolder.addMessageChangedListener(new MessageChangedListener() {
@Override @Override
public void messageChanged(MessageChangedEvent e) { public void messageChanged(MessageChangedEvent e) {
synchronized (lock) { synchronized (lock) {
try { try {
try { try {
Log.i(Helper.TAG, folder.name + " message changed"); Log.i(Helper.TAG, folder.name + " message changed");
synchronizeMessage(folder, ifolder, (IMAPMessage) e.getMessage()); synchronizeMessage(folder, ifolder, (IMAPMessage) e.getMessage());
} catch (MessageRemovedException ex) { } catch (MessageRemovedException ex) {
Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); Log.w(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
} }
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex); reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex)); db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) { synchronized (state) {
state.notifyAll(); state.notifyAll();
}
}
} }
} }
} });
}
}); Log.i(Helper.TAG, folder.name + " start noop");
while (state.running && ifolder.isOpen()) {
// Keep folder connection alive Log.i(Helper.TAG, folder.name + " request NOOP");
Thread noop = new Thread(new Runnable() { ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
@Override public Object doCommand(IMAPProtocol p) throws ProtocolException {
public void run() { Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
try { p.simpleCommand("NOOP", null);
Log.i(Helper.TAG, folder.name + " start noop"); Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
while (state.running && ifolder.isOpen()) { return null;
Log.i(Helper.TAG, folder.name + " request NOOP");
ifolder.doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
Log.i(Helper.TAG, ifolder.getName() + " start NOOP");
p.simpleCommand("NOOP", null);
Log.i(Helper.TAG, ifolder.getName() + " end NOOP");
return null;
}
});
try {
Thread.sleep(FOLDER_NOOP_INTERVAL);
} catch (InterruptedException ex) {
Log.w(Helper.TAG, folder.name + " noop " + ex.getMessage());
} }
});
try {
Thread.sleep(FOLDER_NOOP_INTERVAL);
} catch (InterruptedException ex) {
Log.w(Helper.TAG, folder.name + " noop " + ex.getMessage());
} }
} catch (Throwable ex) { }
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); } catch (Throwable ex) {
reportError(account.name, folder.name, ex); Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex)); db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) { synchronized (state) {
state.notifyAll(); state.notifyAll();
}
} finally {
Log.i(Helper.TAG, folder.name + " end noop");
} }
} finally {
Log.i(Helper.TAG, folder.name + " end noop");
} }
}, "sync.noop." + folder.id); }
noop.start(); }, "sync.noop." + folder.id);
noops.add(noop); noop.start();
noops.add(noop);
// Receive folder events // Receive folder events
Thread idle = new Thread(new Runnable() { Thread idle = new Thread(new Runnable() {
@Override @Override
public void run() { public void run() {
try { try {
Log.i(Helper.TAG, folder.name + " start idle"); Log.i(Helper.TAG, folder.name + " start idle");
while (state.running && ifolder.isOpen()) { while (state.running && ifolder.isOpen()) {
Log.i(Helper.TAG, folder.name + " do idle"); Log.i(Helper.TAG, folder.name + " do idle");
ifolder.idle(false); ifolder.idle(false);
Log.i(Helper.TAG, folder.name + " done idle"); Log.i(Helper.TAG, folder.name + " done idle");
} }
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, folder.name + " " + ex + "\n" + Log.getStackTraceString(ex));
reportError(account.name, folder.name, ex); reportError(account.name, folder.name, ex);
db.folder().setFolderError(folder.id, Helper.formatThrowable(ex)); db.folder().setFolderError(folder.id, Helper.formatThrowable(ex));
synchronized (state) { synchronized (state) {
state.notifyAll(); state.notifyAll();
}
} finally {
Log.i(Helper.TAG, folder.name + " end idle");
} }
} finally {
Log.i(Helper.TAG, folder.name + " end idle");
} }
}, "sync.idle." + folder.id); }
idle.start(); }, "sync.idle." + folder.id);
idlers.add(idle); idle.start();
} catch (MessagingException ex) { idlers.add(idle);
// Don't show to user }
throw new FolderClosedException(folders.get(folder), "start folder", ex);
} catch (IOException ex) {
// Don't show to user
throw new FolderClosedException(folders.get(folder), "start folder", ex);
}
BroadcastReceiver processReceiver = new BroadcastReceiver() { BroadcastReceiver processReceiver = new BroadcastReceiver() {
@Override @Override

Loading…
Cancel
Save