Author: dbkr
Date: 2006-07-26 21:20:00 +0000 (Wed, 26 Jul 2006)
New Revision: 9786
Modified:
trunk/apps/Freemail/src/freemail/AckProcrastinator.java
trunk/apps/Freemail/src/freemail/MessageSender.java
trunk/apps/Freemail/src/freemail/OutboundContact.java
trunk/apps/Freemail/src/freemail/utils/PropsFile.java
Log:
Request and handle message acks and handle message retransmission
Modified: trunk/apps/Freemail/src/freemail/AckProcrastinator.java
===================================================================
--- trunk/apps/Freemail/src/freemail/AckProcrastinator.java 2006-07-26
21:12:13 UTC (rev 9785)
+++ trunk/apps/Freemail/src/freemail/AckProcrastinator.java 2006-07-26
21:20:00 UTC (rev 9786)
@@ -118,7 +118,7 @@
long insertTime = System.currentTimeMillis();
- insertTime += rnd.nextFloat() * by;
+ insertTime += rnd.nextFloat() * (by - insertTime);
ackfile.put("nominalInsertTime",
Long.toString(insertTime));
} catch (IOException ioe) {
Modified: trunk/apps/Freemail/src/freemail/MessageSender.java
===================================================================
--- trunk/apps/Freemail/src/freemail/MessageSender.java 2006-07-26 21:12:13 UTC
(rev 9785)
+++ trunk/apps/Freemail/src/freemail/MessageSender.java 2006-07-26 21:20:00 UTC
(rev 9786)
@@ -93,7 +93,7 @@
private void checkCTSs(File accdir) {
File contactsdir = new File(accdir,
SingleAccountWatcher.CONTACTS_DIR);
- File outbounddir = new File(contactsdir,
OutboundContact.OUTBOUND_DIR);
+ File outbounddir = new File(contactsdir,
SingleAccountWatcher.OUTBOUND_DIR);
if (!outbounddir.exists())
outbounddir.mkdir();
@@ -168,7 +168,6 @@
return true;
}
} else {
- System.out.println("ready");
ready = true;
}
Modified: trunk/apps/Freemail/src/freemail/OutboundContact.java
===================================================================
--- trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-07-26
21:12:13 UTC (rev 9785)
+++ trunk/apps/Freemail/src/freemail/OutboundContact.java 2006-07-26
21:20:00 UTC (rev 9786)
@@ -37,6 +37,10 @@
// up and roughly the same time every day
private static final long CTS_WAIT_TIME = 26 * 60 * 60 * 1000;
private static final String PROPSFILE_NAME = "props";
+ // how long do we wait before retransmitting the message? 26 hours
allows for people starting Freemail at roughly the same time every day
+ private static final long RETRANSMIT_DELAY = 26 * 60 * 60 * 1000;
+ // how long do we wait before we give up all hope and just bounce the
message back? 5 days is fairly standard, so we'll go with that for now, except
that means things bounce when the recipient goes to the Bahamas for a
fortnight. Could be longer if we have a GUI to see what messages are in what
delivery state.
+ private static final long FAIL_DELAY = 5 * 24 * 60 * 60 * 1000;
public OutboundContact(File accdir, EmailAddress a) throws
BadFreemailAddressException {
this.address = a;
@@ -385,12 +389,10 @@
// create a new file that contains the complete Freemail
// message, with Freemail headers
- File msg;
+ QueuedMessage qm = new QueuedMessage(uid);
FileOutputStream fos;
try {
- msg = File.createTempFile("ogm", "msg",
Freemail.getTempDir());
-
- fos = new FileOutputStream(msg);
+ fos = qm.getOutputStream();
} catch (IOException ioe) {
System.out.println("IO Error encountered whilst trying
to send message: "+ioe.getMessage()+" Will try again soon");
return false;
@@ -411,19 +413,18 @@
fos.close();
} catch (IOException ioe) {
System.out.println("IO Error encountered whilst trying
to send message: "+ioe.getMessage()+" Will try again soon");
- msg.delete();
+ qm.delete();
return false;
}
String slot = this.popNextSlot();
- File outbox_msg = new File(this.ctoutbox,
Integer.toString(uid)+","+slot+",notsent");
+ qm.slot = slot;
- System.out.println("renaming temp file to "+outbox_msg);
-
- if (msg.renameTo(outbox_msg))
+ if (qm.saveProps()) {
+ body.delete();
return true;
-
+ }
return false;
}
@@ -439,8 +440,8 @@
int i;
for (i = 0; i < msgs.length; i++) {
- if (msgs[i].uid == -1) continue;
- if (msgs[i].status != QueuedMessage.STATUS_NOTSENT)
continue;
+ if (msgs[i] == null) continue;
+ if (msgs[i].last_send_time > 0) continue;
if (fcpcli == null) fcpcli = new HighLevelFCPClient();
@@ -470,8 +471,9 @@
}
if (err == null) {
System.out.println("Successfully inserted
"+key);
- File newfile = new File(this.ctoutbox,
msgs[i].uid+","+msgs[i].slot+",awaitingack");
- msgs[i].file.renameTo(newfile);
+ msgs[i].first_send_time =
System.currentTimeMillis();
+ msgs[i].last_send_time =
System.currentTimeMillis();
+ msgs[i].saveProps();
} else {
System.out.println("Failed to insert "+key+"
will try again soon.");
}
@@ -479,53 +481,128 @@
}
private void pollAcks() {
+ HighLevelFCPClient fcpcli = null;
QueuedMessage[] msgs = this.getSendQueue();
int i;
for (i = 0; i < msgs.length; i++) {
- if (msgs[i].uid == -1) continue;
+ if (msgs[i] == null) continue;
+ if (msgs[i].first_send_time < 0) continue;
+ if (fcpcli == null) fcpcli = new HighLevelFCPClient();
+ String key = this.contactfile.get("ackssk.pubkey");
+ if (key == null) {
+ System.out.println("Contact file does not
contain public ack key! It appears that your Freemail directory is corrupt!");
+ continue;
+ }
+
+ key += msgs[i].uid;
+
+ File ack = fcpcli.fetch(key);
+ if (ack != null) {
+ System.out.println("Ack received for message
"+msgs[i].uid+" on contact "+this.address.domain+". Now that's a job well
done.");
+ ack.delete();
+ msgs[i].delete();
+ // treat the ACK as a CTS too
+ this.contactfile.put("status", "cts-received");
+ } else {
+ if (System.currentTimeMillis() >
msgs[i].first_send_time + FAIL_DELAY) {
+ // give up and bounce the message
+ // TODO: bounce message
+ System.out.println("Giving up on
message - been trying for too long.");
+ msgs[i].delete();
+ } else if (System.currentTimeMillis() >
msgs[i].last_send_time + RETRANSMIT_DELAY) {
+ // no ack yet - retransmit on another
slot
+ msgs[i].slot = this.popNextSlot();
+ // mark for re-insertion
+ msgs[i].last_send_time = -1;
+ msgs[i].saveProps();
+ }
+ }
}
}
private QueuedMessage[] getSendQueue() {
- File[] files = this.ctoutbox.listFiles();
+ File[] files = ctoutbox.listFiles();
QueuedMessage[] msgs = new QueuedMessage[files.length];
int i;
for (i = 0; i < files.length; i++) {
- String[] parts = files[i].getName().split(",", 3);
- msgs[i] = new QueuedMessage();
- if (parts.length < 2) {
+ if
(files[i].getName().equals(QueuedMessage.INDEX_FILE)) continue;
+
+ int uid;
+ try {
+ uid = Integer.parseInt(files[i].getName());
+ } catch (NumberFormatException nfe) {
// how did that get there? just delete it
System.out.println("Found spurious file in send
queue - deleting.");
files[i].delete();
- msgs[i].uid = -1;
+ msgs[i] = null;
continue;
}
- msgs[i].uid = Integer.parseInt(parts[0]);
- msgs[i].slot = parts[1];
- if (parts.length < 3) {
- msgs[i].status = QueuedMessage.STATUS_NOTSENT;
- } else if (parts[2].equals("awaitingack")) {
- msgs[i].status = QueuedMessage.STATUS_ACKWAIT;
- } else {
- msgs[i].status = QueuedMessage.STATUS_NOTSENT;
- }
- msgs[i].file = files[i];
+
+ msgs[i] = new QueuedMessage(uid);
}
return msgs;
}
private class QueuedMessage {
- int uid;
+ static final String INDEX_FILE = "_index";
+
+ PropsFile index;
+
+ final int uid;
String slot;
- int status;
- File file;
+ long first_send_time;
+ long last_send_time;
+ private final File file;
- static final int STATUS_NOTSENT = 0;
- static final int STATUS_ACKWAIT = 1;
+ public QueuedMessage(int uid) {
+ this.uid = uid;
+ this.file = new File(ctoutbox, Integer.toString(uid));
+
+ this.index = new PropsFile(new File(ctoutbox,
INDEX_FILE));
+
+ this.slot = this.index.get(uid+".slot");
+ String s_first = this.index.get(uid+".first_send_time");
+ if (s_first == null)
+ this.first_send_time = -1;
+ else
+ this.first_send_time = Long.parseLong(s_first);
+
+ String s_last = this.index.get(uid+".last_send_time");
+ if (s_last == null)
+ this.last_send_time = -1;
+ else
+ this.last_send_time = Long.parseLong(s_last);
+
+ }
+
+ public FileInputStream getInputStream() throws
FileNotFoundException {
+ return new FileInputStream(this.file);
+ }
+
+ public FileOutputStream getOutputStream() throws
FileNotFoundException {
+ return new FileOutputStream(this.file);
+ }
+
+ public boolean saveProps() {
+ boolean suc = true;
+ suc &= this.index.put(uid+".slot", this.slot);
+ suc &= this.index.put(uid+".first_send_time",
this.first_send_time);
+ suc &= this.index.put(uid+".last_send_time",
this.last_send_time);
+
+ return suc;
+ }
+
+ public boolean delete() {
+ this.index.remove(this.uid+".slot");
+ this.index.remove(this.uid+".first_send_time");
+ this.index.remove(this.uid+".last_send_time");
+
+ return this.file.delete();
+ }
}
}
Modified: trunk/apps/Freemail/src/freemail/utils/PropsFile.java
===================================================================
--- trunk/apps/Freemail/src/freemail/utils/PropsFile.java 2006-07-26
21:12:13 UTC (rev 9785)
+++ trunk/apps/Freemail/src/freemail/utils/PropsFile.java 2006-07-26
21:20:00 UTC (rev 9786)
@@ -78,6 +78,10 @@
return true;
}
+ public boolean put(String key, long val) {
+ return this.put(key, Long.toString(val));
+ }
+
public boolean exists() {
return this.file.exists();
}
@@ -86,7 +90,14 @@
return this.data.keySet();
}
- public void remove(String key) {
+ public boolean remove(String key) {
this.data.remove(key);
+ try {
+ this.write();
+ } catch (IOException ioe) {
+ ioe.printStackTrace();
+ return false;
+ }
+ return true;
}
}