diff --git a/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java index 30536f4ae43c32d85313350706e706c89fc06829..22bf33b5c6e45a6d2b451baa36d89fd1954d12b4 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/AddressBook.java @@ -38,7 +38,7 @@ import net.i2p.util.EepGet; * @author Ragnarok * */ -public class AddressBook { +class AddressBook { private String location; @@ -88,6 +88,8 @@ public class AddressBook { * read or cannot be read, return an empty AddressBook. * Set a maximum size of the remote book to make it a little harder for a malicious book-sender. * + * Yes, the EepGet fetch() is done in this constructor. + * * @param subscription * A Subscription instance pointing at a remote address book. * @param proxyHost hostname of proxy @@ -102,6 +104,7 @@ public class AddressBook { if (get.fetch()) { subscription.setEtag(get.getETag()); subscription.setLastModified(get.getLastModified()); + subscription.setLastFetched(I2PAppContext.getGlobalContext().clock().now()); } try { this.addresses = ConfigParser.parse(tmp); diff --git a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java index 44bbbe7813cd035e4887e6760e7bde0c9c1b6a7c..ac471df80c321164d930f6f934af56e6defedb6c 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/ConfigParser.java @@ -47,7 +47,7 @@ import net.i2p.util.SecureFileOutputStream; * * @author Ragnarok */ -public class ConfigParser { +class ConfigParser { /** * Strip the comments from a String. Lines that begin with '#' and ';' are @@ -143,7 +143,7 @@ public class ConfigParser { * @param file * A File to attempt to parse. * @param map - * A Map to use as the default, if file fails. + * A Map containing values to use as defaults. * @return A Map containing the key, value pairs from file, or if file * cannot be read, map. */ @@ -151,6 +151,11 @@ public class ConfigParser { Map result; try { result = ConfigParser.parse(file); + for (Iterator iter = map.keySet().iterator(); iter.hasNext(); ) { + String key = (String) iter.next(); + if (!result.containsKey(key)) + result.put(key, map.get(key)); + } } catch (IOException exp) { result = map; try { diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java index 2588010118eb7156ba390464c942a1d3c4325174..274fa8c4f6401e78fd991a26e481c88a17e3e782 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Daemon.java @@ -38,7 +38,7 @@ import net.i2p.util.SecureDirectory; * */ public class Daemon { - public static final String VERSION = "2.0.3"; + public static final String VERSION = "2.0.4"; private static final Daemon _instance = new Daemon(); private boolean _running; @@ -66,6 +66,7 @@ public class Daemon { router.merge(master, true, null); Iterator iter = subscriptions.iterator(); while (iter.hasNext()) { + // yes, the EepGet fetch() is done in next() router.merge((AddressBook) iter.next(), false, log); } router.write(); @@ -97,6 +98,15 @@ public class Daemon { File etagsFile = new File(home, (String) settings.get("etags")); File lastModifiedFile = new File(home, (String) settings .get("last_modified")); + File lastFetchedFile = new File(home, (String) settings + .get("last_fetched")); + long delay; + try { + delay = Long.parseLong((String) settings.get("update_delay")); + } catch (NumberFormatException nfe) { + delay = 12; + } + delay *= 60 * 60 * 1000; AddressBook master = new AddressBook(masterFile); AddressBook router = new AddressBook(routerFile); @@ -106,7 +116,7 @@ public class Daemon { defaultSubs.add("http://www.i2p2.i2p/hosts.txt"); SubscriptionList subscriptions = new SubscriptionList(subscriptionFile, - etagsFile, lastModifiedFile, defaultSubs, (String) settings + etagsFile, lastModifiedFile, lastFetchedFile, delay, defaultSubs, (String) settings .get("proxy_host"), Integer.parseInt((String) settings.get("proxy_port"))); Log log = new Log(logFile); @@ -150,6 +160,7 @@ public class Daemon { defaultSettings.put("subscriptions", "subscriptions.txt"); defaultSettings.put("etags", "etags"); defaultSettings.put("last_modified", "last_modified"); + defaultSettings.put("last_fetched", "last_fetched"); defaultSettings.put("update_delay", "12"); if (!homeFile.exists()) { @@ -165,7 +176,7 @@ public class Daemon { Map settings = ConfigParser.parse(settingsFile, defaultSettings); // wait try { - Thread.sleep(5*60*1000); + Thread.sleep(5*60*1000 + I2PAppContext.getGlobalContext().random().nextLong(5*60*1000)); // Static method, and redundent Thread.currentThread().sleep(5*60*1000); } catch (InterruptedException ie) {} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java index 7c9e65994fc513571253e6d947b35aa7c264c434..b2ff2c5112a2ddeef4606c152af77f78af482299 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/DaemonThread.java @@ -27,7 +27,7 @@ package net.i2p.addressbook; * @author Ragnarok * */ -public class DaemonThread extends Thread { +class DaemonThread extends Thread { private String[] args; diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Log.java b/apps/addressbook/java/src/net/i2p/addressbook/Log.java index a1ba1a2fcb9996bf5ef2a12e92b7e175a8424c01..d0f01904f9ae3dc8ff113ff4393c13e2fd117116 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Log.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Log.java @@ -33,7 +33,7 @@ import java.util.Date; * @author Ragnarok * */ -public class Log { +class Log { private File file; diff --git a/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java index a97635b1285c15ca5f22223badccbf2946ad9191..e391d11e231ec83a30ae3d6f9b5f6794f6e6b748 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/Subscription.java @@ -27,13 +27,14 @@ package net.i2p.addressbook; * @author Ragnarok * */ -public class Subscription { +class Subscription { private String location; private String etag; private String lastModified; + private long lastFetched; /** * Construct a Subscription pointing to the address book at location, that @@ -47,11 +48,17 @@ public class Subscription { * @param lastModified * the last-modified header we recieved the last time we read * this subscription. + * @param lastFetched when the subscription was last fetched (Java time, as a String) */ - public Subscription(String location, String etag, String lastModified) { + public Subscription(String location, String etag, String lastModified, String lastFetched) { this.location = location; this.etag = etag; this.lastModified = lastModified; + if (lastFetched != null) { + try { + this.lastFetched = Long.parseLong(lastFetched); + } catch (NumberFormatException nfe) {} + } } /** @@ -102,4 +109,14 @@ public class Subscription { public void setLastModified(String lastModified) { this.lastModified = lastModified; } -} \ No newline at end of file + + /** @since 0.8.2 */ + public long getLastFetched() { + return this.lastFetched; + } + + /** @since 0.8.2 */ + public void setLastFetched(long t) { + this.lastFetched = t; + } +} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java index b033181e0011d04f7ead63677ef180c2c63c9b83..6a362b8475a67efbc33e444b7476c2928b65d65e 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionIterator.java @@ -21,31 +21,39 @@ package net.i2p.addressbook; +import java.util.Collections; import java.util.Iterator; import java.util.List; +import net.i2p.I2PAppContext; +import net.i2p.data.DataHelper; // debug + /** * An iterator over the subscriptions in a SubscriptionList. Note that this iterator * returns AddressBook objects, and not Subscription objects. + * Yes, the EepGet fetch() is done in here in next(). * * @author Ragnarok */ -public class SubscriptionIterator implements Iterator { +class SubscriptionIterator implements Iterator { private Iterator subIterator; private String proxyHost; private int proxyPort; + private final long delay; /** * Construct a SubscriptionIterator using the Subscriprions in List subscriptions. * * @param subscriptions * List of Subscription objects that represent address books. + * @param delay the minimum delay since last fetched for the iterator to actually fetch * @param proxyHost proxy hostname * @param proxyPort proxt port number */ - public SubscriptionIterator(List subscriptions, String proxyHost, int proxyPort) { + public SubscriptionIterator(List subscriptions, long delay, String proxyHost, int proxyPort) { this.subIterator = subscriptions.iterator(); + this.delay = delay; this.proxyHost = proxyHost; this.proxyPort = proxyPort; } @@ -58,12 +66,24 @@ public class SubscriptionIterator implements Iterator { return this.subIterator.hasNext(); } - /* (non-Javadoc) - * @see java.util.Iterator#next() + /** + * Yes, the EepGet fetch() is done in here in next(). + * + * see java.util.Iterator#next() + * @return an AddressBook (empty if the minimum delay has not been met) */ public Object next() { Subscription sub = (Subscription) this.subIterator.next(); - return new AddressBook(sub, this.proxyHost, this.proxyPort); + if (sub.getLastFetched() + this.delay < I2PAppContext.getGlobalContext().clock().now()) { + //System.err.println("Fetching addressbook from " + sub.getLocation()); + return new AddressBook(sub, this.proxyHost, this.proxyPort); + } else { + //System.err.println("Addressbook " + sub.getLocation() + " was last fetched " + + // DataHelper.formatDuration(I2PAppContext.getGlobalContext().clock().now() - sub.getLastFetched()) + + // " ago but the minimum delay is " + + // DataHelper.formatDuration(this.delay)); + return new AddressBook(Collections.EMPTY_MAP); + } } /* (non-Javadoc) @@ -72,4 +92,4 @@ public class SubscriptionIterator implements Iterator { public void remove() { throw new UnsupportedOperationException(); } -} \ No newline at end of file +} diff --git a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java index ac5d3236dcad7f69699a6795e075e5f9f96575e3..d67cd9af53d4eb3b8bb2d062874e89b754d09ff9 100644 --- a/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java +++ b/apps/addressbook/java/src/net/i2p/addressbook/SubscriptionList.java @@ -35,13 +35,15 @@ import java.util.Map; * @author Ragnarok * */ -public class SubscriptionList { +class SubscriptionList { private List subscriptions; private File etagsFile; private File lastModifiedFile; + private File lastFetchedFile; + private final long delay; private String proxyHost; @@ -60,20 +62,24 @@ public class SubscriptionList { * @param lastModifiedFile * A file containg the last-modified headers used for conditional * GET. The file is in the format "url=leastmodified". + * @param delay the minimum delay since last fetched for the iterator to actually fetch * @param defaultSubs default subscription file * @param proxyHost proxy hostname * @param proxyPort proxy port number */ public SubscriptionList(File locationsFile, File etagsFile, - File lastModifiedFile, List defaultSubs, String proxyHost, + File lastModifiedFile, File lastFetchedFile, long delay, List defaultSubs, String proxyHost, int proxyPort) { this.subscriptions = new LinkedList(); this.etagsFile = etagsFile; this.lastModifiedFile = lastModifiedFile; + this.lastFetchedFile = lastFetchedFile; + this.delay = delay; this.proxyHost = proxyHost; this.proxyPort = proxyPort; Map etags; Map lastModified; + Map lastFetched; String location; List locations = ConfigParser.parseSubscriptions(locationsFile, defaultSubs); @@ -87,11 +93,17 @@ public class SubscriptionList { } catch (IOException exp) { lastModified = new HashMap(); } + try { + lastFetched = ConfigParser.parse(lastFetchedFile); + } catch (IOException exp) { + lastFetched = new HashMap(); + } Iterator iter = locations.iterator(); while (iter.hasNext()) { location = (String) iter.next(); - this.subscriptions.add(new Subscription(location, (String) etags - .get(location), (String) lastModified.get(location))); + this.subscriptions.add(new Subscription(location, (String) etags.get(location), + (String) lastModified.get(location), + (String) lastFetched.get(location))); } } @@ -102,18 +114,22 @@ public class SubscriptionList { * @return A SubscriptionIterator. */ public SubscriptionIterator iterator() { - return new SubscriptionIterator(this.subscriptions, this.proxyHost, + return new SubscriptionIterator(this.subscriptions, this.delay, this.proxyHost, this.proxyPort); } /** - * Write the etag and last-modified headers for each Subscription to files. + * Write the etag and last-modified headers, + * and the last-fetched time, for each Subscription to files. + * BUG - If the subscription URL is a cgi containing an '=' the files + * won't be read back correctly; the '=' should be escaped. */ public void write() { Iterator iter = this.subscriptions.iterator(); Subscription sub; Map etags = new HashMap(); Map lastModified = new HashMap(); + Map lastFetched = new HashMap(); while (iter.hasNext()) { sub = (Subscription) iter.next(); if (sub.getEtag() != null) { @@ -122,11 +138,13 @@ public class SubscriptionList { if (sub.getLastModified() != null) { lastModified.put(sub.getLocation(), sub.getLastModified()); } + lastFetched.put(sub.getLocation(), "" + sub.getLastFetched()); } try { ConfigParser.write(etags, this.etagsFile); ConfigParser.write(lastModified, this.lastModifiedFile); + ConfigParser.write(lastFetched, this.lastFetchedFile); } catch (IOException exp) { } } -} \ No newline at end of file +}