Author: nextgens
Date: 2006-05-21 13:29:03 +0000 (Sun, 21 May 2006)
New Revision: 8817

Added:
   trunk/freenet/src/freenet/node/NodeUpdater.java
Modified:
   trunk/freenet/src/freenet/node/Node.java
Log:
First version of the NodeUpdater (disabled for now)

We just advertize on the welcome toadlet that a new version is out.

Modified: trunk/freenet/src/freenet/node/Node.java
===================================================================
--- trunk/freenet/src/freenet/node/Node.java    2006-05-21 13:17:35 UTC (rev 
8816)
+++ trunk/freenet/src/freenet/node/Node.java    2006-05-21 13:29:03 UTC (rev 
8817)
@@ -43,6 +43,7 @@
 import freenet.client.async.USKManager;
 import freenet.clients.http.FproxyToadlet;
 import freenet.clients.http.SimpleToadletServer;
+import freenet.config.BooleanCallback;
 import freenet.config.Config;
 import freenet.config.FilePersistentConfig;
 import freenet.config.IntCallback;
@@ -507,6 +508,7 @@
        static final int EXIT_COULD_NOT_START_FPROXY = 18;
        static final int EXIT_COULD_NOT_START_TMCI = 19;
        public static final int EXIT_DATABASE_REQUIRES_RESTART = 20;
+       public static final int EXIT_COULD_NOT_START_UPDATER = 21;

     public final long bootID;
     public final long startupTime;
@@ -539,6 +541,9 @@
     FproxyToadlet fproxyServlet;
     SimpleToadletServer toadletContainer;

+    /** NodeUpdater **/
+    public NodeUpdater nodeUpdater;
+    
     // Persistent temporary buckets
     public final PersistentTempBucketFactory persistentTempBucketFactory;

@@ -786,7 +791,7 @@
     static class NodeInitException extends Exception {
        // One of the exit codes from above
        public final int exitCode;
-       private static final long serialVersionUID = 0;
+       private static final long serialVersionUID = -1;

        NodeInitException(int exitCode, String msg) {
                super(msg+" ("+exitCode+")");
@@ -1250,7 +1255,7 @@
                        new NodeNameCallback(this));
         nodeNameUserAlert = new MeaningfulNodeNameUserAlert();
         myName = nodeConfig.getString("name");
-        
+         
         nodeConfig.finishedInitialization();
         writeNodeFile();

@@ -1340,6 +1345,16 @@
                        throw new 
NodeInitException(EXIT_COULD_NOT_START_FPROXY, "Could not start fproxy: "+e);   
              
                }

+        
+        // Node Updater
+               try{
+                       nodeUpdater = NodeUpdater.maybeCreate(this, config);
+                       Logger.normal(this, "Starting the node updater");
+        }catch (NodeInitException e) {
+                       e.printStackTrace();
+                       throw new 
NodeInitException(EXIT_COULD_NOT_START_UPDATER, "Could not start Updater: "+e);
+               }
+               
                /*
         SimpleToadletServer server = new SimpleToadletServer(port+2000);
         FproxyToadlet fproxy = new 
FproxyToadlet(n.makeClient(RequestStarter.INTERACTIVE_PRIORITY_CLASS));
@@ -2572,6 +2587,10 @@
         System.exit(0);
        }

+       public NodeUpdater getNodeUpdater(){
+               return nodeUpdater;
+       }
+       
        public void setTMCI(TextModeClientInterfaceServer server) {
                this.tmci = server;
        }

Added: trunk/freenet/src/freenet/node/NodeUpdater.java
===================================================================
--- trunk/freenet/src/freenet/node/NodeUpdater.java     2006-05-21 13:17:35 UTC 
(rev 8816)
+++ trunk/freenet/src/freenet/node/NodeUpdater.java     2006-05-21 13:29:03 UTC 
(rev 8817)
@@ -0,0 +1,291 @@
+package freenet.node;
+
+import java.net.MalformedURLException;
+
+import freenet.client.FetchException;
+import freenet.client.FetchResult;
+import freenet.client.FetcherContext;
+import freenet.client.InserterException;
+import freenet.client.async.BaseClientPutter;
+import freenet.client.async.ClientCallback;
+import freenet.client.async.ClientGetter;
+import freenet.client.async.USKCallback;
+import freenet.config.BooleanCallback;
+import freenet.config.Config;
+import freenet.config.InvalidConfigValueException;
+import freenet.config.StringCallback;
+import freenet.config.SubConfig;
+import freenet.keys.FreenetURI;
+import freenet.keys.USK;
+import freenet.node.Node.NodeInitException;
+import freenet.support.Logger;
+
+class PrivkeyHasBeenBlownException extends Exception{  
+       private static final long serialVersionUID = -1;
+       
+       PrivkeyHasBeenBlownException(String msg) {
+               super("The project's private key has been blown, meaning that 
it has been compromized"+
+                         "and shouldn't be trusted anymore. Please get a new 
build by hand and verify CAREFULLY"+
+                         "its signature and CRC. Here is the revocation 
message: "+msg);
+       }
+}
+
+class UpdaterEnabledCallback implements BooleanCallback {
+       
+       final Node node;
+       
+       UpdaterEnabledCallback(Node n) {
+               this.node = n;
+       }
+       
+       public boolean get() {
+               return node.getNodeUpdater() != null;
+       }
+       
+       public void set(boolean val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               // FIXME implement
+               throw new InvalidConfigValueException("Cannot be updated on the 
fly");
+       }
+}
+
+class AutoUpdateAllowedCallback implements BooleanCallback {
+       
+       final Node node;
+       
+       AutoUpdateAllowedCallback(Node n) {
+               this.node = n;
+       }
+       
+       public boolean get() {
+               NodeUpdater nu = node.getNodeUpdater();
+               return nu.isAutoUpdateAllowed;
+       }
+       
+       public void set(boolean val) throws InvalidConfigValueException {
+               if(val == get()) return;
+               // Good idea to prevent it ?
+               throw new InvalidConfigValueException("Cannot be updated on the 
fly for security concerns");
+       }
+}
+
+class UpdateURICallback implements StringCallback{
+
+       private final Node node;
+       private final String baseURI="freenet:USK at 
XC-ntr3FcUblbYWjLkV9ci6BwnXqvIuKKWcWQHDjlFw,YcCSs5lraAMOKx5VMbrvL-28Waf4elHpz~lvVL~hEDk,AQABAAE/update/";
+       
+       public UpdateURICallback(Node node) {
+               this.node = node;
+       }
+       
+       public String get() {
+               NodeUpdater nu = node.getNodeUpdater();
+               if (nu != null)
+                       return nu.getUpdateKey().toString(true);
+               else
+                       return baseURI+Version.buildNumber()+"/";
+       }
+
+       public void set(String val) {
+               if(val == get()) return;
+               // Good idea to prevent it ? 
+               //
+               // Maybe it NEEDS to be implemented
+               Logger.error(this, "Node's updater URI can't be updated on the 
fly");
+               return;
+       }       
+}
+
+class UpdatedVersionAviableUserAlert implements UserAlert {
+       private boolean isValid=true;
+       private int version;
+
+       UpdatedVersionAviableUserAlert(int version){
+               this.version=version;
+       }
+       
+       public boolean userCanDismiss() {
+               return false;
+       }
+
+       public String getTitle() {
+               return "A new stable version of Freenet is aviable";
+       }
+
+       public String getText() {
+               return "It seems that your node isn't running the latest 
version of the software. "+
+               "Updating to "+version+" is advised.";
+       }
+
+       public short getPriorityClass() {
+               return UserAlert.MINOR;
+       }
+       
+       public boolean isValid() {
+               return isValid;
+       }
+       
+       public void isValid(boolean b){
+               if(userCanDismiss()) isValid=b;
+       }
+}
+
+
+public class NodeUpdater implements ClientCallback, USKCallback {
+       private FetcherContext ctx;
+       private final FreenetURI URI;
+       private final Node node;
+       
+       private final int currentVersion;
+       private int aviableVersion;
+       
+       private String revocationMessage;
+       private boolean hasBeenBlown;
+       
+       private boolean isRunning = false;
+       
+       public final boolean isAutoUpdateAllowed;
+       
+       private UpdatedVersionAviableUserAlert alert;
+       
+       public NodeUpdater(Node n, boolean isAutoUpdateAllowed, FreenetURI URI) 
{
+               super();
+               this.URI = URI;
+               this.node = n;
+               this.currentVersion = Version.buildNumber();
+               this.aviableVersion = Version.buildNumber();
+               this.hasBeenBlown = false;
+               this.isRunning = true;
+               this.isAutoUpdateAllowed = isAutoUpdateAllowed;
+               this.alert=null;
+               
+               FetcherContext ctx = 
n.makeClient((short)0).getFetcherContext();                
+               ctx.allowSplitfiles = true;
+               ctx.dontEnterImplicitArchives = false;
+               ctx.maxArchiveRestarts = 0;
+               ctx.maxMetadataSize = 256;
+               ctx.maxNonSplitfileRetries = 10;
+               ctx.maxOutputLength = 4096;
+               ctx.maxRecursionLevel = 2;
+               ctx.maxTempLength = 4096;
+               this.ctx = ctx;
+               
+               try{            
+                       ctx.uskManager.subscribe(USK.create(URI), this, true);
+               }catch(MalformedURLException e){
+                       Logger.error(this,"The auto-update URI isn't valid and 
can't be used");
+                       this.hasBeenBlown=true;
+                       this.revocationMessage = new String("The auto-update 
URI isn't valid and can't be used");
+               }
+       }
+       
+       public void onFoundEdition(long l, USK key){
+               // FIXME : Check if it has been blown
+               int found = (int)key.suggestedEdition;
+               
+               if(found > aviableVersion){
+                       this.aviableVersion = found;
+                       
+                       synchronized(this){
+                               Logger.normal(this, "Found a new version!, 
setting up a new UpdatedVersionAviableUserAlert");
+                               
+                               if(alert != null){
+                                       System.out.println("unregistering 
"+alert.hashCode()+":"+alert);
+                                       node.alerts.unregister(alert);
+                               }
+                               alert = new 
UpdatedVersionAviableUserAlert(aviableVersion);
+                               System.out.println("registering 
"+alert.hashCode()+":"+alert);
+                               node.alerts.register(new 
UpdatedVersionAviableUserAlert(aviableVersion));
+                       }
+                       
+                       maybeUpdate();
+               }
+       }
+
+       public synchronized void maybeUpdate(){
+               try{
+                       if(isRunning || !isUpdatable()) return;
+               }catch (PrivkeyHasBeenBlownException e){
+                       // how to handle it ? a new UserAlert or an imediate 
exit?
+                       Logger.error(this, "Private key has been blown!");
+                       node.exit();
+               }
+               
+               //TODO maybe a UpdateInProgress alert ?
+               
+               if(isAutoUpdateAllowed){
+                       Logger.normal(this,"Starting the update process");
+               }else{
+                       Logger.normal(this,"Not starting the update process as 
it's not allowed");
+               }
+       }
+       
+       public void onSuccess(FetchResult result, ClientGetter state) {
+       }
+
+       public void onFailure(FetchException e, ClientGetter state) {
+       }
+
+       public void onSuccess(BaseClientPutter state) {
+               // Impossible
+       }
+
+       public void onFailure(InserterException e, BaseClientPutter state) {
+               // Impossible
+       }
+
+       public void onGeneratedURI(FreenetURI uri, BaseClientPutter state) {
+               // Impossible
+       }
+
+       public boolean isUpdatable() throws PrivkeyHasBeenBlownException{
+               if(hasBeenBlown) 
+                       throw new 
PrivkeyHasBeenBlownException(revocationMessage);
+               else 
+                       return (currentVersion<aviableVersion);
+       }
+       
+       public boolean isRunning(){
+               return isRunning;
+       }
+       
+       public FreenetURI getUpdateKey(){
+               return URI;
+       }
+       
+       public static NodeUpdater maybeCreate(Node node, Config config) throws 
NodeInitException {
+        SubConfig updaterConfig = new SubConfig("node.updater", config);
+         
+        updaterConfig.register("enabled", false, 1, false, "Enable Node's 
updater?",
+                       "Whether to enable the node's updater. It won't 
auto-update unless node.updater.autoupdate is true, it will just warn",
+                       new UpdaterEnabledCallback(node));
+        
+        boolean enabled = updaterConfig.getBoolean("enabled");
+
+        if(enabled) {
+               // is the auto-update allowed ?
+               updaterConfig.register("autoupdate", false, 2, false, "Is the 
node allowed to auto-update?", "Is the node allowed to auto-update?",
+                               new AutoUpdateAllowedCallback(node));
+               boolean autoUpdateAllowed = 
updaterConfig.getBoolean("autoupdate");
+               
+               updaterConfig.register("URI",
+                               "freenet:USK at 
XC-ntr3FcUblbYWjLkV9ci6BwnXqvIuKKWcWQHDjlFw,YcCSs5lraAMOKx5VMbrvL-28Waf4elHpz~lvVL~hEDk,AQABAAE/update/"+Version.buildNumber()+"/",
+                               3, true, "Where should the node look for 
updates?",
+                               "Where should the node look for updates?",
+                               new UpdateURICallback(node));
+               
+               String URI = updaterConfig.getString("URI");
+               
+               updaterConfig.finishedInitialization();
+               try{
+                       return new NodeUpdater(node , autoUpdateAllowed, new 
FreenetURI(URI));
+               }catch(Exception e){
+                       Logger.error(node, "Error starting the NodeUpdater: 
"+e);
+                       throw new 
NodeInitException(node.EXIT_COULD_NOT_START_UPDATER,"Unable to start the 
NodeUpdater up");
+               }
+        } else {
+               updaterConfig.finishedInitialization();
+               return null;
+        }
+       }
+}


Reply via email to