Author: nextgens
Date: 2007-11-03 11:56:23 +0000 (Sat, 03 Nov 2007)
New Revision: 15667

Added:
   trunk/freenet/src/freenet/clients/http/StartupToadletServer.java
Modified:
   trunk/freenet/src/freenet/node/Node.java
   trunk/freenet/src/freenet/node/NodeClientCore.java
Log:
Display a dirty toadlet using a dummy ToadletServer when the node is starting 
up.

~ I didn't test it much...

Added: trunk/freenet/src/freenet/clients/http/StartupToadletServer.java
===================================================================
--- trunk/freenet/src/freenet/clients/http/StartupToadletServer.java            
                (rev 0)
+++ trunk/freenet/src/freenet/clients/http/StartupToadletServer.java    
2007-11-03 11:56:23 UTC (rev 15667)
@@ -0,0 +1,271 @@
+/* This code is part of Freenet. It is distributed under the GNU General
+ * Public License, version 2 (or at your option any later version). See
+ * http://www.gnu.org/ for further details of the GPL. */
+package freenet.clients.http;
+
+import freenet.support.HTMLNode;
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.JarURLConnection;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import freenet.io.NetworkInterface;
+import freenet.l10n.L10n;
+import freenet.support.Logger;
+import freenet.support.OOMHandler;
+import freenet.support.SimpleFieldSet;
+import freenet.support.Executor;
+import freenet.support.api.BucketFactory;
+import freenet.support.api.HTTPRequest;
+import freenet.support.io.ArrayBucketFactory;
+
+/**
+ * A Placeholder displayed before fproxy starts up.
+ * 
+ * @author nextgens
+ * 
+ * TODO: Maybe add a progress bar or something ?
+ * TODO: What about userAlerts ?
+ * TODO: Shall l10n be loaded before ?
+ */
+public class StartupToadletServer implements Runnable {
+
+    private int port;
+    private final NetworkInterface networkInterface;
+    private String cssName;
+    private Thread myThread;
+    private final PageMaker pageMaker;
+    private String formPassword;
+    private Executor executor;
+    private final BucketFactory bf = new ArrayBucketFactory();
+    private final File configFile = new File("freenet.ini");
+    private final ToadletContainer container = new ToadletContainer() {
+
+        public void register(Toadlet t, String urlPrefix, boolean atFront, 
boolean fullAccessOnly) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+
+        public Toadlet findToadlet(URI uri) {
+            return startupToadlet;
+        }
+
+        public String getCSSName() {
+            return cssName;
+        }
+
+        public String getFormPassword() {
+            return formPassword;
+        }
+
+        public boolean isAllowedFullAccess(InetAddress remoteAddr) {
+            return false;
+        }
+
+        public boolean doRobots() {
+            return true;
+        }
+
+        public HTMLNode addFormChild(HTMLNode parentNode, String target, 
String name) {
+            throw new UnsupportedOperationException("Not supported yet.");
+        }
+    };
+    
+    private final Toadlet startupToadlet = new Toadlet(null) {
+        public void handleGet(URI uri, HTTPRequest req, ToadletContext ctx) 
throws ToadletContextClosedException, IOException, RedirectException {
+            String path = uri.getPath();
+            if(path.startsWith(StaticToadlet.ROOT_URL)) {
+                staticToadlet.handleGet(uri, req, ctx);
+            } else {
+                String desc = "Freenet is starting up";
+                HTMLNode pageNode = ctx.getPageMaker().getPageNode(desc, 
false, ctx);
+               HTMLNode contentNode = 
ctx.getPageMaker().getContentNode(pageNode);
+               
+               HTMLNode infobox = 
contentNode.addChild(ctx.getPageMaker().getInfobox("infobox-error", desc));
+               HTMLNode infoboxContent = 
ctx.getPageMaker().getContentNode(infobox);
+               infoboxContent.addChild("#", "Your freenet node is starting up, 
please hold on.");
+                
+                //TODO: send a Retry-After header ?
+                writeHTMLReply(ctx, 503, desc, pageNode.generate());
+            }
+       }
+        
+        public String supportedMethods() {
+            return "GET";
+        }
+    };
+    
+    private final StaticToadlet staticToadlet = new StaticToadlet(null);
+
+    /**
+        * Create a SimpleToadletServer, using the settings from the SubConfig 
(the fproxy.*
+        * config).
+        */
+    public StartupToadletServer(Executor executor) {
+        int configItemOrder = 0;
+        this.executor = executor;
+        formPassword = String.valueOf(this.getClass().hashCode());
+
+        List themes = new ArrayList();
+        try {
+            URL url = getClass().getResource("staticfiles/themes/");
+            URLConnection urlConnection = url.openConnection();
+            if (url.getProtocol().equals("file")) {
+                File themesDirectory = new 
File(URLDecoder.decode(url.getPath(), "ISO-8859-1").replaceAll("\\|", ":"));
+                File[] themeDirectories = themesDirectory.listFiles();
+                for (int themeIndex = 0; (themeDirectories != null) && 
(themeIndex < themeDirectories.length); themeIndex++) {
+                    File themeDirectory = themeDirectories[themeIndex];
+                    if (themeDirectory.isDirectory() && 
!themeDirectory.getName().startsWith(".")) {
+                        themes.add(themeDirectory.getName());
+                    }
+                }
+            } else if (urlConnection instanceof JarURLConnection) {
+                JarURLConnection jarUrlConnection = (JarURLConnection) 
urlConnection;
+                JarFile jarFile = jarUrlConnection.getJarFile();
+                Enumeration entries = jarFile.entries();
+                while (entries.hasMoreElements()) {
+                    JarEntry entry = (JarEntry) entries.nextElement();
+                    String name = entry.getName();
+                    if 
(name.startsWith("freenet/clients/http/staticfiles/themes/")) {
+                        name = 
name.substring("freenet/clients/http/staticfiles/themes/".length());
+                        if (name.indexOf('/') != -1) {
+                            String themeName = name.substring(0, 
name.indexOf('/'));
+                            if (!themes.contains(themeName)) {
+                                themes.add(themeName);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (IOException ioe1) {
+            Logger.error(this, "error creating list of themes", ioe1);
+        } catch (NullPointerException npe) {
+            Logger.error(this, "error creating list of themes", npe);
+        } finally {
+            if (!themes.contains("clean")) {
+                themes.add("clean");
+            }
+        }
+
+        // hack ... we don't have the config framework yet
+        try {
+            SimpleFieldSet config = SimpleFieldSet.readFrom(configFile, false, 
false);
+            port = config.getInt("fproxy.port");
+            cssName = config.get("fproxy.css");
+        } catch (Exception e) {
+            port = SimpleToadletServer.DEFAULT_FPROXY_PORT;
+            cssName = PageMaker.DEFAULT_THEME;
+        }
+        
+        pageMaker = new PageMaker(cssName);
+
+        boolean start = true;
+        NetworkInterface ni = null;
+        try {
+            ni = NetworkInterface.create(port, 
SimpleToadletServer.DEFAULT_BIND_TO, SimpleToadletServer.DEFAULT_BIND_TO, 
executor);
+        } catch (IOException e) {
+            Logger.error(this, "Error starting SimpleToadletServer on " + 
port);
+            System.err.println("Error starting SimpleToadletServer on " + 
port);
+            start = false;
+        }
+        this.networkInterface = ni;
+        
+        if (start) {
+            myThread = new Thread(this, "SimpleToadletServer");
+            myThread.setDaemon(true);
+            myThread.start();
+            Logger.normal(this, "Starting SimpleToadletServer on " + port);
+            System.out.println("Starting SimpleToadletServer on " + port);
+        }
+    }
+
+    public void run() {
+        try {
+            networkInterface.setSoTimeout(500);
+        } catch (SocketException e1) {
+            Logger.error(this, "Could not set so-timeout to 500ms; on-the-fly 
disabling of the interface will not work");
+        }
+        while (true) {
+            synchronized (this) {
+                if (myThread == null) {
+                    return;
+                }
+            }
+            try {
+                Socket conn = networkInterface.accept();
+                if (Logger.shouldLog(Logger.MINOR, this)) {
+                    Logger.minor(this, "Accepted connection");
+                }
+                SocketHandler sh = new SocketHandler(conn);
+                sh.start();
+            } catch (SocketTimeoutException e) {
+            // Go around again, this introduced to avoid blocking forever when 
told to quit
+            }
+        }
+    }
+
+    public synchronized void kill() throws IOException {
+        myThread = null;
+        networkInterface.close();
+    }
+
+    public class SocketHandler implements Runnable {
+
+        Socket sock;
+
+        public SocketHandler(Socket conn) {
+            this.sock = conn;
+        }
+
+        void start() {
+            executor.execute(this, "SimpleToadletServer$SocketHandler@" + 
hashCode());
+        }
+
+        public void run() {
+            freenet.support.Logger.OSThread.logPID(this);
+            boolean logMINOR = Logger.shouldLog(Logger.MINOR, this);
+            if (logMINOR) {
+                Logger.minor(this, "Handling connection");
+            }
+            try {
+                ToadletContextImpl.handle(sock, container, bf, pageMaker);
+            } catch (OutOfMemoryError e) {
+                OOMHandler.handleOOM(e);
+                System.err.println("SimpleToadletServer request above 
failed.");
+            } catch (Throwable t) {
+                System.err.println("Caught in SimpleToadletServer: " + t);
+                t.printStackTrace();
+                Logger.error(this, "Caught in SimpleToadletServer: " + t, t);
+            }
+            if (logMINOR) {
+                Logger.minor(this, "Handled connection");
+            }
+        }
+    }
+
+    public String getCSSName() {
+        return this.cssName;
+    }
+
+    public void setCSSName(String name) {
+        this.cssName = name;
+    }
+
+    private static String l10n(String key, String pattern, String value) {
+        return L10n.getString("SimpleToadletServer." + key, pattern, value);
+    }
+
+    private static String l10n(String key) {
+        return L10n.getString("SimpleToadletServer." + key);
+    }
+}

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2007-11-03 11:49:44 UTC (rev 
15666)
+++ trunk/freenet/src/freenet/node/Node.java    2007-11-03 11:56:23 UTC (rev 
15667)
@@ -38,6 +38,7 @@
 import com.sleepycat.je.util.DbDump;

 import freenet.client.FetchContext;
+import freenet.clients.http.StartupToadletServer;
 import freenet.config.EnumerableOptionCallback;
 import freenet.config.FreenetFilePersistentConfig;
 import freenet.config.InvalidConfigValueException;
@@ -360,6 +361,8 @@

        public final long bootID;
        public final long startupTime;
+        
+        public final StartupToadletServer startupPageHolder;

        public final NodeClientCore clientCore;

@@ -538,6 +541,9 @@
                if(logConfigHandler != lc)
                        logConfigHandler=lc;
                startupTime = System.currentTimeMillis();
+                // Will be set up properly afterwards
+                L10n.setLanguage(L10n.FALLBACK_DEFAULT);
+                startupPageHolder = new StartupToadletServer(executor);
                nodeNameUserAlert = new MeaningfulNodeNameUserAlert(this);
                recentlyCompletedIDs = new LRUQueue();
                this.config = config;
@@ -1255,7 +1261,7 @@

                nodeStats = new NodeStats(this, sortOrder, new 
SubConfig("node.load", config), oldThrottleFS, obwLimit, ibwLimit);

-               clientCore = new NodeClientCore(this, config, nodeConfig, 
nodeDir, getDarknetPortNumber(), sortOrder, oldThrottleFS == null ? null : 
oldThrottleFS.subset("RequestStarters"));
+               clientCore = new NodeClientCore(this, config, nodeConfig, 
nodeDir, getDarknetPortNumber(), sortOrder, oldThrottleFS == null ? null : 
oldThrottleFS.subset("RequestStarters"), startupPageHolder);

                nodeConfig.register("disableHangCheckers", false, sortOrder++, 
true, false, "Node.disableHangCheckers", "Node.disableHangCheckersLong", new 
BooleanCallback() {


Modified: trunk/freenet/src/freenet/node/NodeClientCore.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeClientCore.java  2007-11-03 11:49:44 UTC 
(rev 15666)
+++ trunk/freenet/src/freenet/node/NodeClientCore.java  2007-11-03 11:56:23 UTC 
(rev 15667)
@@ -16,6 +16,7 @@
 import freenet.clients.http.bookmark.BookmarkManager;
 import freenet.clients.http.FProxyToadlet;
 import freenet.clients.http.SimpleToadletServer;
+import freenet.clients.http.StartupToadletServer;
 import freenet.clients.http.filter.FilterCallback;
 import freenet.clients.http.filter.FoundURICallback;
 import freenet.clients.http.filter.GenericReadFilterCallback;
@@ -113,7 +114,7 @@
        static final long MAX_ARCHIVED_FILE_SIZE = 1024*1024; // arbitrary... 
FIXME
        static final int MAX_CACHED_ELEMENTS = 256*1024; // equally arbitrary! 
FIXME hopefully we can cache many of these though

-       NodeClientCore(Node node, Config config, SubConfig nodeConfig, File 
nodeDir, int portNumber, int sortOrder, SimpleFieldSet oldThrottleFS) throws 
NodeInitException {
+       NodeClientCore(Node node, Config config, SubConfig nodeConfig, File 
nodeDir, int portNumber, int sortOrder, SimpleFieldSet oldThrottleFS, 
StartupToadletServer sts) throws NodeInitException {
                this.node = node;
                this.nodeStats = node.nodeStats;
                this.random = node.random;
@@ -351,6 +352,7 @@
                // FProxy
                // FIXME this is a hack, the real way to do this is plugins
                try {
+                        sts.kill();
                        toadletContainer = 
FProxyToadlet.maybeCreateFProxyEtc(this, node, config, fproxyConfig);
                } catch (IOException e) {
                        e.printStackTrace();


Reply via email to