diff --git a/addresspublisher/build.xml b/addresspublisher/build.xml new file mode 100644 index 0000000..f104ee3 --- /dev/null +++ b/addresspublisher/build.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + Builds, tests, and runs the project addresspublisher. + + + + + + + Must set build.dir + + + + + + + + + + + diff --git a/addresspublisher/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar b/addresspublisher/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar new file mode 100644 index 0000000..5ee71d2 Binary files /dev/null and b/addresspublisher/lib/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar differ diff --git a/addresspublisher/lib/i2p.jar b/addresspublisher/lib/i2p.jar new file mode 100644 index 0000000..f04b208 Binary files /dev/null and b/addresspublisher/lib/i2p.jar differ diff --git a/addresspublisher/lib/javax.servlet.jar b/addresspublisher/lib/javax.servlet.jar new file mode 100644 index 0000000..08e759d Binary files /dev/null and b/addresspublisher/lib/javax.servlet.jar differ diff --git a/addresspublisher/lib/junit/junit-3.8.2-api.zip b/addresspublisher/lib/junit/junit-3.8.2-api.zip new file mode 100644 index 0000000..6d792fd Binary files /dev/null and b/addresspublisher/lib/junit/junit-3.8.2-api.zip differ diff --git a/addresspublisher/lib/junit/junit-3.8.2.jar b/addresspublisher/lib/junit/junit-3.8.2.jar new file mode 100644 index 0000000..d835872 Binary files /dev/null and b/addresspublisher/lib/junit/junit-3.8.2.jar differ diff --git a/addresspublisher/lib/junit_4/junit-4.5-api.zip b/addresspublisher/lib/junit_4/junit-4.5-api.zip new file mode 100644 index 0000000..5748c44 Binary files /dev/null and b/addresspublisher/lib/junit_4/junit-4.5-api.zip differ diff --git a/addresspublisher/lib/junit_4/junit-4.5-src.jar b/addresspublisher/lib/junit_4/junit-4.5-src.jar new file mode 100644 index 0000000..18774a5 Binary files /dev/null and b/addresspublisher/lib/junit_4/junit-4.5-src.jar differ diff --git a/addresspublisher/lib/junit_4/junit-4.5.jar b/addresspublisher/lib/junit_4/junit-4.5.jar new file mode 100644 index 0000000..83f8bc7 Binary files /dev/null and b/addresspublisher/lib/junit_4/junit-4.5.jar differ diff --git a/addresspublisher/lib/nblibraries.properties b/addresspublisher/lib/nblibraries.properties new file mode 100644 index 0000000..9137b06 --- /dev/null +++ b/addresspublisher/lib/nblibraries.properties @@ -0,0 +1,12 @@ +libs.CopyLibs.classpath=\ + ${base}/CopyLibs/org-netbeans-modules-java-j2seproject-copylibstask.jar +libs.junit.classpath=\ + ${base}/junit/junit-3.8.2.jar +libs.junit.javadoc=\ + ${base}/junit/junit-3.8.2-api.zip +libs.junit_4.classpath=\ + ${base}/junit_4/junit-4.5.jar +libs.junit_4.javadoc=\ + ${base}/junit_4/junit-4.5-api.zip +libs.junit_4.src=\ + ${base}/junit_4/junit-4.5-src.jar diff --git a/addresspublisher/nbproject/build-impl.xml b/addresspublisher/nbproject/build-impl.xml new file mode 100644 index 0000000..dcf3b0f --- /dev/null +++ b/addresspublisher/nbproject/build-impl.xml @@ -0,0 +1,916 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set src.dir + Must set test.src.dir + Must set build.dir + Must set dist.dir + Must set build.classes.dir + Must set dist.javadoc.dir + Must set build.test.classes.dir + Must set build.test.results.dir + Must set build.classes.excludes + Must set dist.jar + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + To run this application from the command line without Ant, try: + + + + + + + java -cp "${run.classpath.with.dist.jar}" ${main.class} + + + + + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + To run this application from the command line without Ant, try: + + java -jar "${dist.jar.resolved}" + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set run.class + + + + Must select one file in the IDE or set run.class + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set debug.class + + + + + Must select one file in the IDE or set debug.class + + + + + Must set fix.includes + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select some files in the IDE or set javac.includes + + + + + + + + + + + + + + + + + + + + Some tests failed; see details above. + + + + + + + + + Must select some files in the IDE or set test.includes + + + + Some tests failed; see details above. + + + + + Must select one file in the IDE or set test.class + + + + + + + + + + + + + + + + + + + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + Must select one file in the IDE or set applet.url + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/addresspublisher/nbproject/genfiles.properties b/addresspublisher/nbproject/genfiles.properties new file mode 100644 index 0000000..d9736b6 --- /dev/null +++ b/addresspublisher/nbproject/genfiles.properties @@ -0,0 +1,8 @@ +build.xml.data.CRC32=00fdd0af +build.xml.script.CRC32=3297d85f +build.xml.stylesheet.CRC32=28e38971@1.38.2.45 +# This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. +# Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. +nbproject/build-impl.xml.data.CRC32=00fdd0af +nbproject/build-impl.xml.script.CRC32=967d9836 +nbproject/build-impl.xml.stylesheet.CRC32=f33e10ff@1.38.2.45 diff --git a/addresspublisher/nbproject/private/config.properties b/addresspublisher/nbproject/private/config.properties new file mode 100644 index 0000000..e69de29 diff --git a/addresspublisher/nbproject/private/private.properties b/addresspublisher/nbproject/private/private.properties new file mode 100644 index 0000000..8994e0a --- /dev/null +++ b/addresspublisher/nbproject/private/private.properties @@ -0,0 +1,8 @@ +compile.on.save=true +do.depend=false +do.jar=true +file.reference.i2p.jar=/mnt/bb/dream/packages/mtn/i2p.scripts/addresspublisher/lib/i2p.jar +file.reference.javax.servlet.jar=/mnt/bb/dream/packages/mtn/i2p.scripts/addresspublisher/lib/javax.servlet.jar +javac.debug=true +javadoc.preview=true +user.properties.file=/mnt/bb/dream/.netbeans/6.9/build.properties diff --git a/addresspublisher/nbproject/private/private.xml b/addresspublisher/nbproject/private/private.xml new file mode 100644 index 0000000..c1f155a --- /dev/null +++ b/addresspublisher/nbproject/private/private.xml @@ -0,0 +1,4 @@ + + + + diff --git a/addresspublisher/nbproject/project.properties b/addresspublisher/nbproject/project.properties new file mode 100644 index 0000000..a8c91bc --- /dev/null +++ b/addresspublisher/nbproject/project.properties @@ -0,0 +1,76 @@ +annotation.processing.enabled=true +annotation.processing.enabled.in.editor=false +annotation.processing.run.all.processors=true +annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output +application.title=addresspublisher +application.vendor=dream +build.classes.dir=${build.dir}/classes +build.classes.excludes=**/*.java,**/*.form +# This directory is removed when the project is cleaned: +build.dir=build +build.generated.dir=${build.dir}/generated +build.generated.sources.dir=${build.dir}/generated-sources +# Only compile against the classpath explicitly listed here: +build.sysclasspath=ignore +build.test.classes.dir=${build.dir}/test/classes +build.test.results.dir=${build.dir}/test/results +# Uncomment to specify the preferred debugger connection transport: +#debug.transport=dt_socket +debug.classpath=\ + ${run.classpath} +debug.test.classpath=\ + ${run.test.classpath} +# This directory is removed when the project is cleaned: +dist.dir=dist +dist.jar=${dist.dir}/addresspublisher.jar +dist.javadoc.dir=${dist.dir}/javadoc +endorsed.classpath= +excludes= +file.reference.i2p.jar=lib/i2p.jar +file.reference.javax.servlet.jar=lib/javax.servlet.jar +includes=** +jar.compress=false +javac.classpath=\ + ${file.reference.javax.servlet.jar}:\ + ${file.reference.i2p.jar} +# Space-separated list of extra javac options +javac.compilerargs= +javac.deprecation=false +javac.processorpath=\ + ${javac.classpath} +javac.source=1.5 +javac.target=1.5 +javac.test.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir}:\ + ${libs.junit.classpath}:\ + ${libs.junit_4.classpath} +javac.test.processorpath=\ + ${javac.test.classpath} +javadoc.additionalparam= +javadoc.author=false +javadoc.encoding=${source.encoding} +javadoc.noindex=false +javadoc.nonavbar=false +javadoc.notree=false +javadoc.private=false +javadoc.splitindex=true +javadoc.use=true +javadoc.version=false +javadoc.windowtitle= +main.class=i2p.dream.addresspublisher.InspectHosts +meta.inf.dir=${src.dir}/META-INF +platform.active=default_platform +run.classpath=\ + ${javac.classpath}:\ + ${build.classes.dir} +# Space-separated list of JVM arguments used when running the project +# (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value +# or test-sys-prop.name=value to set system properties for unit tests): +run.jvmargs= +run.test.classpath=\ + ${javac.test.classpath}:\ + ${build.test.classes.dir} +source.encoding=UTF-8 +src.dir=src +test.src.dir=test diff --git a/addresspublisher/nbproject/project.xml b/addresspublisher/nbproject/project.xml new file mode 100644 index 0000000..c573ed6 --- /dev/null +++ b/addresspublisher/nbproject/project.xml @@ -0,0 +1,18 @@ + + + org.netbeans.modules.java.j2seproject + + + addresspublisher + + + + + + + + + ./lib/nblibraries.properties + + + diff --git a/addresspublisher/src/i2p/dream/addresspublisher/Configuration.java b/addresspublisher/src/i2p/dream/addresspublisher/Configuration.java new file mode 100644 index 0000000..1c97a97 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/Configuration.java @@ -0,0 +1,27 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.File; +import java.nio.charset.Charset; +import net.i2p.I2PAppContext; + +/** + * + * @author dream + */ +public class Configuration { + + public static File getConfDir() { + final File confDir = new File(I2PAppContext.getGlobalContext().getConfigDir(), + "addressbook"); + if(!confDir.exists()) + confDir.mkdirs(); + return confDir; + } + + static public final Charset charset = Charset.forName("UTF-8"); +} diff --git a/addresspublisher/src/i2p/dream/addresspublisher/InspectHosts.java b/addresspublisher/src/i2p/dream/addresspublisher/InspectHosts.java new file mode 100644 index 0000000..f344fb8 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/InspectHosts.java @@ -0,0 +1,142 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.Date; +import java.util.HashSet; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.i2p.I2PAppContext; +import net.i2p.data.DataFormatException; +import net.i2p.data.Destination; + +/** + * + * @author dream + */ +public class InspectHosts implements Runnable { + + static final File hosts = new File(I2PAppContext.getGlobalContext().getConfigDir(),"hosts.txt"); + static File getNames() { + return new File(Configuration.getConfDir(),"names.index"); + } + Set knownHosts = new HashSet(); + + /* The hosts.txt file doesn't change except the end. Hosts are added at the + * end and not reordered or anything. Thus, hax! + */ + PersistentLong lastPos = new PersistentLong(getNames()); + + /** + * @param args the command line arguments + */ + public void run() { + FileInputStream in = null; + try { + in = new FileInputStream(getNames()); + in.getChannel().position(lastPos.get()); + BufferedReader r = new BufferedReader( + new InputStreamReader(in,Configuration.charset)); + for(;;) { + String line = r.readLine(); + if(line==null) break; + knownHosts.add(line.hashCode()); + } + } catch(FileNotFoundException e) { + // index doesn't exist yet + } catch (IOException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + } finally { + if(in!=null) { + try { + lastPos.set(in.getChannel().position()); + lastPos.save(getNames()); + in.close(); + } catch (IOException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + FileOutputStream out = null; + try { + in = new FileInputStream(hosts); + BufferedReader b = new BufferedReader( + new InputStreamReader(in,Configuration.charset)); + out = new FileOutputStream(getNames(),true); + for(;;) { + String line = b.readLine(); + if(line==null) break; + int comment = line.indexOf("#"); + if(comment>0) + line = line.substring(0,comment) + .replaceAll(" ", "") + .replaceAll("\t", ""); + + if(line.length()==0) continue; + + String name = line.substring(0,line.indexOf("=")) + .replaceAll(" ", "") + .replaceAll("\t", ""); + + if(name.length()==0) continue; + + if(knownHosts.contains(name.hashCode())) continue; + + Record rec = RecordIndex.getInstance().newRecord(); + rec.setName(name); + Destination address = new Destination(); + try { + address.fromBase64(line.substring(name.length() + 1)); + } catch (DataFormatException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + continue; + } + rec.setAddress(address); + rec.setModified(new Date()); + try { + rec.maybeSave(); + } catch (DataFormatException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + continue; + } + knownHosts.add(name.hashCode()); + out.write((name+"\n") + .getBytes(Configuration.charset)); + + Logger.getLogger(InspectHosts.class.getName()).log(Level.INFO, + "Created new address record for {0}({1})", + new Object[]{name, rec.id}); + } + } catch (FileNotFoundException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + } catch(EOFException e) { + // Done reading hosts.txt + } catch (IOException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + } finally { + try { + if (in != null) { + in.close(); + } + if (out != null) { + out.close(); + } + } catch (IOException ex) { + Logger.getLogger(InspectHosts.class.getName()).log(Level.SEVERE, null, ex); + } + } + } +} diff --git a/addresspublisher/src/i2p/dream/addresspublisher/PersistentInteger.java b/addresspublisher/src/i2p/dream/addresspublisher/PersistentInteger.java new file mode 100644 index 0000000..9175048 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/PersistentInteger.java @@ -0,0 +1,65 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * + * @author dream + */ +class PersistentInteger { + int num; + PersistentInteger(File f) throws IOException { + InputStream in = null; + try { + try { + in = new FileInputStream(f); + } catch (FileNotFoundException ex) { + + } + byte[] buf = new byte[4]; + in.read(buf); + num = buf[0]<<0x18 & + buf[1]<<0x10 & + buf[2]<<0x8 & + buf[3]; + } finally { + if(in!=null) in.close(); + } + } + + public void save(File f) throws IOException { + byte[] buf = new byte[4]; + buf[0] = (byte) (num & 0xf); + buf[1] = (byte) ((num >> 8) & 0xf); + buf[2] = (byte) ((num >> 0x10) & 0xf); + buf[3] = (byte) ((num >> 0x18) & 0xf); + OutputStream out = null; + try { + out = new FileOutputStream(f); + out.write(buf); + } finally { + if(out!=null) + out.close(); + } + } + + public int get() { + return num; + } + + public void set(int n) { + num = n; + } + +} diff --git a/addresspublisher/src/i2p/dream/addresspublisher/PersistentLong.java b/addresspublisher/src/i2p/dream/addresspublisher/PersistentLong.java new file mode 100644 index 0000000..0b3ad7f --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/PersistentLong.java @@ -0,0 +1,81 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author dream + */ +class PersistentLong { + long num; + PersistentLong(File f) { + InputStream in = null; + try { + try { + in = new FileInputStream(f); + } catch (FileNotFoundException ex) { + + } + byte[] buf = new byte[4]; + in.read(buf); + num = buf[7]<<0x38 & + buf[6]<<0x30 & + buf[5]<<0x28 & + buf[4]<<0x20 & + buf[3]<<0x18 & + buf[2]<<0x10 & + buf[1]<<0x8 & + buf[0]; + } catch (IOException ex) { + Logger.getLogger(PersistentLong.class.getName()).log(Level.SEVERE, null, ex); + } finally { + if(in!=null) try { + in.close(); + } catch (IOException ex) { + Logger.getLogger(PersistentLong.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + public void save(File f) throws IOException { + byte[] buf = new byte[4]; + buf[0] = (byte) (num & 0xf); + buf[1] = (byte) ((num >> 8) & 0xf); + buf[2] = (byte) ((num >> 0x10) & 0xf); + buf[3] = (byte) ((num >> 0x18) & 0xf); + buf[4] = (byte) ((num >> 0x20) & 0xf); + buf[5] = (byte) ((num >> 0x28) & 0xf); + buf[6] = (byte) ((num >> 0x30) & 0xf); + buf[7] = (byte) ((num >> 0x38) & 0xf); + OutputStream out = null; + try { + out = new FileOutputStream(f); + out.write(buf); + } finally { + if(out!=null) + out.close(); + } + } + + public long get() { + return num; + } + + public void set(long n) { + num = n; + } + +} diff --git a/addresspublisher/src/i2p/dream/addresspublisher/Record.java b/addresspublisher/src/i2p/dream/addresspublisher/Record.java new file mode 100644 index 0000000..0e27bf0 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/Record.java @@ -0,0 +1,213 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.util.Date; +import net.i2p.data.Destination; +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.logging.Level; +import java.util.logging.Logger; +import net.i2p.data.DataFormatException; + + +class RecordCache extends LinkedHashMap { + // the list of records that don't get collected immediately... + + private static final int MAX_ENTRIES = 10; + + RecordCache() { + super(MAX_ENTRIES,0.75f,true); + } + + + @Override + protected boolean removeEldestEntry(Map.Entry eldest) + { + Record rec = eldest.getValue(); + try { + rec.maybeSave(); + } catch (IOException ex) { + Logger.getLogger(RecordCache.class.getName()).log(Level.SEVERE, null, ex); + } catch (DataFormatException ex) { + Logger.getLogger(RecordCache.class.getName()).log(Level.SEVERE, null, ex); + } + return size() > MAX_ENTRIES; + } +} + +/** + * + * @author dream + */ +class Record { + final int id; + private boolean needsLoad = true; + private boolean readyToSave = false; + private Date modified; + private String name; + private Destination address; + + protected Record(int id) { + this.id = id; + } + + static File getRecordDir() { + File dir = new File(Configuration.getConfDir(),"records"); + if(!dir.exists()) + dir.mkdir(); + return dir; + } + + void load() { + if(readyToSave) { + try { + save(); + } catch (IOException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } catch (DataFormatException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } + return; + } + File location = new File(getRecordDir(),Integer.toHexString(id)); + if(!location.exists()) { + modified = new Date(); + name = null; + address = null; + needsLoad = false; + return; + } + InputStream in = null; + ObjectInputStream o = null; + try { + in = new FileInputStream(location); + o = new ObjectInputStream(in); + modified = (Date) o.readObject(); + name = (String) o.readObject(); + address = new Destination(); + address.readBytes(o); + needsLoad = false; + } catch (IOException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } catch (DataFormatException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } catch (ClassNotFoundException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } + } + try { + o.close(); + } catch (IOException ex) { + Logger.getLogger(Record.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + + void save() throws IOException, DataFormatException { + File location = new File(getRecordDir(),Integer.toHexString(id)); + OutputStream out = null; + try { + out = new FileOutputStream(location); + final ObjectOutputStream o = new ObjectOutputStream(out); + o.writeObject(modified); + o.writeObject(name); + address.writeBytes(o); + readyToSave = false; + } finally { + if(out!=null) + out.close(); + } + } + + Date getModified() { + if(needsLoad) { + synchronized(this) { + load(); + } + } + return modified; + } + + + String getName() { + if(needsLoad) { + synchronized(this) { + load(); + } + } + return name; + } + + Destination getAddress() { + if(needsLoad) { + synchronized(this) { + load(); + } + } + return address; + } + + void setModified(Date d) { + getModified(); + modified = d; + readyToSave = true; + } + + + void setName(String s) { + getName(); + name = s; + readyToSave = true; + } + + void setAddress(Destination d) { + getAddress(); + address = d; + readyToSave = true; + } + + static RecordCache records; + static public Record get(int id) { + if(records.containsKey(id)) + return records.get(id); + Record record = new Record(id); + records.put(id, record); + return record; + } + + void maybeSave() throws IOException, DataFormatException { + if(readyToSave) save(); + } + + @Override + public boolean equals(Object o) { + if(o.getClass() != getClass()) + return false; + Record sib = (Record) o; + return sib.id == id; + } + + @Override + public int hashCode() { + return id; + } +} \ No newline at end of file diff --git a/addresspublisher/src/i2p/dream/addresspublisher/RecordIndex.java b/addresspublisher/src/i2p/dream/addresspublisher/RecordIndex.java new file mode 100644 index 0000000..19f0647 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/RecordIndex.java @@ -0,0 +1,72 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; + +// important to go from top down to zero, so that you get the most recent +// records to look at first, and cut off before reaching the old ones + +class RecordGetter implements Iterator { + + int cur; + final int top; + RecordGetter(int top) { + this.cur = top; + this.top = top; + } + + public boolean hasNext() { + return cur > 0; + } + + public Record next() { + return Record.get(--cur); + } + + public void remove() { + throw new UnsupportedOperationException("Not supported yet."); + } +} + +/** + * + * @author dream + */ +class RecordIndex implements Iterable { + PersistentInteger top; + + RecordIndex() throws IOException { + top = new PersistentInteger(indexFile()); + + } + + private File indexFile() { + return new File(Configuration.getConfDir(), "index"); + } + + Record newRecord() throws IOException { + synchronized (Record.class) { + top.set(top.get()+1); + top.save(indexFile()); + return Record.get(top.get()); + } + } + + + public Iterator iterator() { + return new RecordGetter(top.get()); + } + + static RecordIndex instance = null; + public static RecordIndex getInstance() throws IOException { + if(instance!=null) return instance; + instance = new RecordIndex(); + return instance; + } +} diff --git a/addresspublisher/src/i2p/dream/addresspublisher/Servlet.java b/addresspublisher/src/i2p/dream/addresspublisher/Servlet.java new file mode 100644 index 0000000..2fde037 --- /dev/null +++ b/addresspublisher/src/i2p/dream/addresspublisher/Servlet.java @@ -0,0 +1,121 @@ +/* + * To change this template, choose Tools | Templates + * and open the template in the editor. + */ + +package i2p.dream.addresspublisher; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * + * @author dream + */ + +class RepeatedInspect extends Thread { + InspectHosts guy = new InspectHosts(); + private boolean ready = false; + @Override + @SuppressWarnings("SleepWhileHoldingLock") + public void run() { + /* we can't wait/notify because java doesn't have inotify support, so + * polling is the only option. + * jnotify support would be really nice... + * at least it seeks to the lowest last position every time! + */ + for(;;) { + try { + guy.run(); + synchronized(this) { + ready = true; + this.notifyAll(); + } + } catch(Exception ex) { + // we never want this thread to die. + Logger.getLogger(RepeatedInspect.class.getName()).log(Level.SEVERE, null, ex); + } + try { + Thread.sleep(86400000); + } catch (InterruptedException ex) { + Logger.getLogger(RepeatedInspect.class.getName()).log(Level.SEVERE, null, ex); + } + } + } + + void waitUntilReady() throws InterruptedException { + synchronized(this) { + if(ready) return; + this.wait(10000); + } + } +} + +public class Servlet extends HttpServlet { + String myEtag; + long myModified; + private static RepeatedInspect inspect; + + @Override + public void init(ServletConfig config) throws ServletException { + myEtag = null; + myModified = 0; + if(inspect==null) { + inspect = new RepeatedInspect(); + inspect.start(); + } + } + + @Override + protected void doGet(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException + { + String etag = request.getHeader("Etag"); + long modified; + if(etag!=null) { + modified = Integer.decode(etag).longValue(); + } else { + modified = request.getDateHeader("If-Modified-Since"); + } + response.setContentType("text/plain"); + if(myEtag!=null) + response.setHeader("Etag",myEtag); + // set last modified taken care of below. + PrintWriter out = null; + try { + out = response.getWriter(); + recentHosts(modified,out); + out.println("# done"); + } finally { + if(out!=null) + out.close(); + } + + } + + private void recentHosts(long modified, PrintWriter out) throws IOException { + try { + inspect.waitUntilReady(); + } catch (InterruptedException ex) { + out.write("# not ready yet, still loading. Try again in a bit."); + return; + } + for(Record r : RecordIndex.getInstance()) { + if(r.getModified().before(new Date(modified))) + break; + out.write("# Modified="+r.getModified() + +"\n"+r.getName()+"="+r.getAddress().toBase64() + +"\n"); + } + } + +} diff --git a/enableAliases/nbproject/private/private.xml b/enableAliases/nbproject/private/private.xml index c1f155a..a61defd 100644 --- a/enableAliases/nbproject/private/private.xml +++ b/enableAliases/nbproject/private/private.xml @@ -1,4 +1,7 @@ + + file:/mnt/bb/dream/packages/mtn/i2p.scripts/enableAliases/src/i2p/dream/AliasEnabler.java +