forked from I2P_Developers/i2p.i2p
Begin i2p.i2p.zzz.confsplit branch
Code from Jan. 2018, never checked in, probably untested, definitely incomplete.
This commit is contained in:
@@ -1,17 +1,22 @@
|
||||
package net.i2p.router.startup;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.data.DataHelper;
|
||||
import net.i2p.router.RouterContext;
|
||||
import net.i2p.util.SecureFileOutputStream;
|
||||
import net.i2p.util.FileUtil;
|
||||
import net.i2p.util.Log;
|
||||
import net.i2p.util.ObjectCounter;
|
||||
import net.i2p.util.OrderedProperties;
|
||||
import net.i2p.util.SecureDirectory;
|
||||
|
||||
|
||||
/**
|
||||
@@ -71,6 +76,7 @@ public class ClientAppConfig {
|
||||
|
||||
private static final String PROP_CLIENT_CONFIG_FILENAME = "router.clientConfigFile";
|
||||
private static final String DEFAULT_CLIENT_CONFIG_FILENAME = "clients.config";
|
||||
private static final String CLIENT_CONFIG_DIR = "clients.config.d";
|
||||
private static final String PREFIX = "clientApp.";
|
||||
|
||||
// let's keep this really simple
|
||||
@@ -86,6 +92,8 @@ public class ClientAppConfig {
|
||||
public final String stopargs;
|
||||
/** @since 0.7.12 */
|
||||
public final String uninstallargs;
|
||||
/** @since 0.0.34 */
|
||||
private File configFile;
|
||||
|
||||
public ClientAppConfig(String cl, String client, String a, long d, boolean dis) {
|
||||
this(cl, client, a, d, dis, null, null, null);
|
||||
@@ -111,51 +119,104 @@ public class ClientAppConfig {
|
||||
return cfgFile;
|
||||
}
|
||||
|
||||
private static Properties getClientAppProps(RouterContext ctx) {
|
||||
Properties rv = new Properties();
|
||||
File cfgFile = configFile(ctx);
|
||||
|
||||
// fall back to use router.config's clientApp.* lines
|
||||
if (!cfgFile.exists()) {
|
||||
System.out.println("Warning - No client config file " + cfgFile.getAbsolutePath());
|
||||
rv.putAll(ctx.router().getConfigMap());
|
||||
return rv;
|
||||
}
|
||||
|
||||
try {
|
||||
DataHelper.loadProps(rv, cfgFile);
|
||||
} catch (IOException ioe) {
|
||||
System.out.println("Error loading the client app properties from " + cfgFile.getAbsolutePath() + ' ' + ioe);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the properties, and return a List of ClientAppConfig structures
|
||||
* Go through the files, and return a List of ClientAppConfig structures
|
||||
* This is for the router.
|
||||
*/
|
||||
public static List<ClientAppConfig> getClientApps(RouterContext ctx) {
|
||||
Properties clientApps = getClientAppProps(ctx);
|
||||
List<ClientAppConfig> rv = getClientApps(clientApps);
|
||||
MigrateJetty.migrate(ctx, rv);
|
||||
public synchronized static List<ClientAppConfig> getClientApps(RouterContext ctx) {
|
||||
File dir = new SecureDirectory(ctx.getConfigDir(), CLIENT_CONFIG_DIR);
|
||||
// clients.config
|
||||
List<ClientAppConfig> rv = new ArrayList<ClientAppConfig>(8);
|
||||
File cf = configFile(ctx);
|
||||
try {
|
||||
List<ClientAppConfig> cacs = getClientApps(cf);
|
||||
if (!cacs.isEmpty()) {
|
||||
MigrateJetty.migrate(ctx, cacs);
|
||||
boolean ok = migrate(ctx, cacs, cf, dir);
|
||||
if (!ok)
|
||||
rv.addAll(cacs);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ctx.logManager().getLog(ClientAppConfig.class).error("Error loading the client app properties from " + cf, ioe);
|
||||
System.out.println("Error loading the client app properties from " + cf + ' ' + ioe);
|
||||
}
|
||||
// clients.config.d
|
||||
if (dir.isDirectory()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
// sort so the returned order is consistent
|
||||
Arrays.sort(files);
|
||||
for (File f : files) {
|
||||
if (!f.getName().endsWith(".config"))
|
||||
continue;
|
||||
if (!f.isFile())
|
||||
continue;
|
||||
try {
|
||||
List<ClientAppConfig> cacs = getClientApps(f);
|
||||
if (!cacs.isEmpty()) {
|
||||
rv.addAll(cacs);
|
||||
} else {
|
||||
ctx.logManager().getLog(ClientAppConfig.class).error("Error loading the client app properties from " + f);
|
||||
System.out.println("Error loading the client app properties from " + f);
|
||||
}
|
||||
} catch (IOException ioe) {
|
||||
ctx.logManager().getLog(ClientAppConfig.class).error("Error loading the client app properties from " + f, ioe);
|
||||
System.out.println("Error loading the client app properties from " + f + ' ' + ioe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the properties, and return a List of ClientAppConfig structures
|
||||
* This is for plugins.
|
||||
* Go through the file, and return a List of ClientAppConfig structures
|
||||
*
|
||||
* @since 0.7.12
|
||||
*/
|
||||
public static List<ClientAppConfig> getClientApps(File cfgFile) {
|
||||
public synchronized static List<ClientAppConfig> getClientApps(File cfgFile) throws IOException {
|
||||
if (!cfgFile.isFile())
|
||||
return new ArrayList<ClientAppConfig>();
|
||||
Properties clientApps = new Properties();
|
||||
try {
|
||||
DataHelper.loadProps(clientApps, cfgFile);
|
||||
} catch (IOException ioe) {
|
||||
return Collections.emptyList();
|
||||
DataHelper.loadProps(clientApps, cfgFile);
|
||||
List<ClientAppConfig> rv = getClientApps(clientApps);
|
||||
for (ClientAppConfig cac : rv) {
|
||||
cac.configFile = cfgFile;
|
||||
}
|
||||
return getClientApps(clientApps);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Migrate apps from file to individual files in dir
|
||||
*
|
||||
* @return success
|
||||
* @since 0.9.34
|
||||
*/
|
||||
private static boolean migrate(I2PAppContext ctx, List<ClientAppConfig> apps, File from, File dir) {
|
||||
if (!dir.isDirectory() && !dir.mkdirs())
|
||||
return false;
|
||||
boolean ok = true;
|
||||
for (int i = 0; i < apps.size(); i++) {
|
||||
ClientAppConfig cac = apps.get(i);
|
||||
String name = i + "-" + cac.className + "-clients.config";
|
||||
if (i < 10)
|
||||
name = '0' + name;
|
||||
File f = new File(dir, name);
|
||||
cac.configFile = f;
|
||||
try {
|
||||
writeClientAppConfig(ctx, cac);
|
||||
} catch (IOException ioe) {
|
||||
ctx.logManager().getLog(ClientAppConfig.class).error("Error migrating the client app properties to " + f, ioe);
|
||||
System.out.println("Error migrating the client app properties to " + f + ' ' + ioe);
|
||||
cac.configFile = from;
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (ok) {
|
||||
if (!FileUtil.rename(from, new File(from.getAbsolutePath() + ".bak")))
|
||||
from.delete();
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -167,18 +228,34 @@ public class ClientAppConfig {
|
||||
List<ClientAppConfig> rv = new ArrayList<ClientAppConfig>(8);
|
||||
int i = 0;
|
||||
while (true) {
|
||||
String className = clientApps.getProperty(PREFIX + i + ".main");
|
||||
if (className == null)
|
||||
ClientAppConfig cac = getClientApp(clientApps, PREFIX + i);
|
||||
if (cac == null)
|
||||
break;
|
||||
String clientName = clientApps.getProperty(PREFIX + i + ".name");
|
||||
String args = clientApps.getProperty(PREFIX + i + ".args");
|
||||
String delayStr = clientApps.getProperty(PREFIX + i + ".delay");
|
||||
String onBoot = clientApps.getProperty(PREFIX + i + ".onBoot");
|
||||
String disabled = clientApps.getProperty(PREFIX + i + ".startOnLoad");
|
||||
String classpath = clientApps.getProperty(PREFIX + i + ".classpath");
|
||||
String stopargs = clientApps.getProperty(PREFIX + i + ".stopargs");
|
||||
String uninstallargs = clientApps.getProperty(PREFIX + i + ".uninstallargs");
|
||||
i++;
|
||||
rv.add(cac);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Go through the properties, and get a single ClientAppConfig structure
|
||||
* with this prefix
|
||||
*
|
||||
* @return null if none
|
||||
* @since 0.9.34 split out from above
|
||||
*/
|
||||
private static ClientAppConfig getClientApp(Properties clientApps, String prefix) {
|
||||
String className = clientApps.getProperty(prefix + ".main");
|
||||
if (className == null)
|
||||
return null;
|
||||
String clientName = clientApps.getProperty(prefix + ".name");
|
||||
String args = clientApps.getProperty(prefix + ".args");
|
||||
String delayStr = clientApps.getProperty(prefix + ".delay");
|
||||
String onBoot = clientApps.getProperty(prefix + ".onBoot");
|
||||
String disabled = clientApps.getProperty(prefix + ".startOnLoad");
|
||||
String classpath = clientApps.getProperty(prefix + ".classpath");
|
||||
String stopargs = clientApps.getProperty(prefix + ".stopargs");
|
||||
String uninstallargs = clientApps.getProperty(prefix + ".uninstallargs");
|
||||
boolean dis = disabled != null && "false".equals(disabled);
|
||||
|
||||
boolean onStartup = false;
|
||||
@@ -196,33 +273,143 @@ public class ClientAppConfig {
|
||||
if (delayStr != null)
|
||||
try { delay = 1000*Integer.parseInt(delayStr); } catch (NumberFormatException nfe) {}
|
||||
}
|
||||
rv.add(new ClientAppConfig(className, clientName, args, delay, dis,
|
||||
classpath, stopargs, uninstallargs));
|
||||
}
|
||||
return rv;
|
||||
return new ClientAppConfig(className, clientName, args, delay, dis,
|
||||
classpath, stopargs, uninstallargs);
|
||||
}
|
||||
|
||||
/** classpath and stopargs not supported */
|
||||
public static void writeClientAppConfig(RouterContext ctx, List<ClientAppConfig> apps) {
|
||||
File cfgFile = configFile(ctx);
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new SecureFileOutputStream(cfgFile);
|
||||
StringBuilder buf = new StringBuilder(2048);
|
||||
for(int i = 0; i < apps.size(); i++) {
|
||||
ClientAppConfig app = apps.get(i);
|
||||
buf.append(PREFIX).append(i).append(".main=").append(app.className).append("\n");
|
||||
buf.append(PREFIX).append(i).append(".name=").append(app.clientName).append("\n");
|
||||
if (app.args != null)
|
||||
buf.append(PREFIX).append(i).append(".args=").append(app.args).append("\n");
|
||||
buf.append(PREFIX).append(i).append(".delay=").append(app.delay / 1000).append("\n");
|
||||
buf.append(PREFIX).append(i).append(".startOnLoad=").append(!app.disabled).append("\n");
|
||||
}
|
||||
fos.write(buf.toString().getBytes("UTF-8"));
|
||||
} catch (IOException ioe) {
|
||||
} finally {
|
||||
if (fos != null) try { fos.close(); } catch (IOException ioe) {}
|
||||
/**
|
||||
* Classpath and stopargs not supported.
|
||||
* All other apps in the file will be deleted.
|
||||
* Do not use if multiple apps in a single file - use writeClientAppConfig(ctx, apps).
|
||||
* If app.configFile is null, a new file will be created and assigned.
|
||||
*
|
||||
* @since 0.9.34
|
||||
*/
|
||||
public synchronized static void writeClientAppConfig(I2PAppContext ctx, ClientAppConfig app) throws IOException {
|
||||
if (app.configFile == null) {
|
||||
File dir = new SecureDirectory(ctx.getConfigDir(), CLIENT_CONFIG_DIR);
|
||||
if (!dir.isDirectory() && !dir.mkdirs())
|
||||
throw new IOException("Can't create " + dir);
|
||||
int i = 0;
|
||||
String[] files = dir.list();
|
||||
if (files != null)
|
||||
i = files.length;
|
||||
File f;
|
||||
do {
|
||||
String name = i + "-" + app.className + "-clients.config";
|
||||
if (i < 10)
|
||||
name = '0' + name;
|
||||
f = new File(dir, name);
|
||||
i++;
|
||||
} while (f.exists());
|
||||
app.configFile = f;
|
||||
}
|
||||
writeClientAppConfig(Collections.singletonList(app), app.configFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* Classpath and stopargs not supported.
|
||||
* All other apps in the files will be deleted.
|
||||
* Do not add apps with this method - use writeClientAppConfig(ctx, app).
|
||||
* Do not delete apps with this method - use deleteClientAppConfig().
|
||||
*
|
||||
* @since 0.9.34 split out from above
|
||||
*/
|
||||
public synchronized static void writeClientAppConfig(I2PAppContext ctx, List<ClientAppConfig> apps) throws IOException {
|
||||
// Gather the set of config files
|
||||
ObjectCounter<File> counter = new ObjectCounter<File>();
|
||||
for (ClientAppConfig cac : apps) {
|
||||
File f = cac.configFile;
|
||||
if (f == null)
|
||||
throw new IllegalArgumentException("No file for " + cac.className);
|
||||
counter.increment(f);
|
||||
}
|
||||
IOException e = null;
|
||||
// Write the config files
|
||||
Set<File> files = counter.objects();
|
||||
// For each file, write all the configs for that file
|
||||
for (File f : files) {
|
||||
// Gather configs for this file
|
||||
List<ClientAppConfig> cacs = new ArrayList<ClientAppConfig>(8);
|
||||
for (ClientAppConfig cac : apps) {
|
||||
if (cac.configFile.equals(f))
|
||||
cacs.add(cac);
|
||||
}
|
||||
try {
|
||||
writeClientAppConfig(cacs, f);
|
||||
} catch (IOException ioe) {
|
||||
if (e == null)
|
||||
e = ioe;
|
||||
}
|
||||
}
|
||||
if (e != null)
|
||||
throw e;
|
||||
}
|
||||
|
||||
/**
|
||||
* All to a single file, apps.configFile ignored
|
||||
*
|
||||
* @throws IllegalArgumentException if null cfgFile
|
||||
* @since 0.9.34 split out from above
|
||||
*/
|
||||
private static void writeClientAppConfig(List<ClientAppConfig> apps, File cfgFile) throws IOException {
|
||||
if (cfgFile == null)
|
||||
throw new IllegalArgumentException("No file");
|
||||
Properties props = new OrderedProperties();
|
||||
for(int i = 0; i < apps.size(); i++) {
|
||||
ClientAppConfig app = apps.get(i);
|
||||
String pfx = PREFIX + i;
|
||||
props.setProperty(pfx + ".main", app.className);
|
||||
props.setProperty(pfx + ".name", app.clientName);
|
||||
if (app.args != null)
|
||||
props.setProperty(pfx + ".args", app.args);
|
||||
props.setProperty(pfx + ".delay", Long.toString(app.delay / 1000));
|
||||
props.setProperty(pfx + ".startOnLoad", Boolean.toString(!app.disabled));
|
||||
}
|
||||
DataHelper.storeProps(props, cfgFile);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return success
|
||||
* @throws IllegalArgumentException if cac has a null configfile
|
||||
* @since 0.9.34
|
||||
*/
|
||||
public synchronized static boolean deleteClientAppConfig(ClientAppConfig cac) throws IOException {
|
||||
File f = cac.configFile;
|
||||
if (f == null)
|
||||
throw new IllegalArgumentException("No file for " + cac.className);
|
||||
List<ClientAppConfig> cacs = getClientApps(f);
|
||||
if (cacs.remove(cac)) {
|
||||
if (cacs.isEmpty())
|
||||
return f.delete();
|
||||
writeClientAppConfig(cacs, f);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 0.9.34
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return DataHelper.hashCode(className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches on class, args, and name only
|
||||
* @since 0.9.34
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) return true;
|
||||
if (o == null) return false;
|
||||
if (o instanceof ClientAppConfig) {
|
||||
ClientAppConfig cac = (ClientAppConfig) o;
|
||||
return DataHelper.eq(className, cac.className) &&
|
||||
DataHelper.eq(clientName, cac.clientName) &&
|
||||
DataHelper.eq(args, cac.args);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -196,8 +196,17 @@ abstract class MigrateJetty {
|
||||
File cfgFile = ClientAppConfig.configFile(ctx);
|
||||
boolean ok = backupFile(cfgFile);
|
||||
if (ok) {
|
||||
ClientAppConfig.writeClientAppConfig(ctx, apps);
|
||||
System.err.println("WARNING: Migrated clients config file " + cfgFile +
|
||||
try {
|
||||
ClientAppConfig.writeClientAppConfig(ctx, apps);
|
||||
System.err.println("WARNING: Migrated clients config file " + cfgFile +
|
||||
" from Jetty 5/6 " + OLD_CLASS + '/' + OLD_CLASS_6 +
|
||||
" to Jetty 9 " + NEW_CLASS);
|
||||
} catch (IOException ioe) {
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
if (!ok) {
|
||||
System.err.println("WARNING: Failed to migrate clients config file " + cfgFile +
|
||||
" from Jetty 5/6 " + OLD_CLASS + '/' + OLD_CLASS_6 +
|
||||
" to Jetty 9 " + NEW_CLASS);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user