forked from I2P_Developers/i2p.i2p
* Addressbook
- Store last-fetched time so we don't always fetch subscriptions after restart - Randomize first fetch time - Make most classes package private
This commit is contained in:
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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) {}
|
||||
|
||||
|
@ -27,7 +27,7 @@ package net.i2p.addressbook;
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class DaemonThread extends Thread {
|
||||
class DaemonThread extends Thread {
|
||||
|
||||
private String[] args;
|
||||
|
||||
|
@ -33,7 +33,7 @@ import java.util.Date;
|
||||
* @author Ragnarok
|
||||
*
|
||||
*/
|
||||
public class Log {
|
||||
class Log {
|
||||
|
||||
private File file;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/** @since 0.8.2 */
|
||||
public long getLastFetched() {
|
||||
return this.lastFetched;
|
||||
}
|
||||
|
||||
/** @since 0.8.2 */
|
||||
public void setLastFetched(long t) {
|
||||
this.lastFetched = t;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user