support plugin themes
This commit is contained in:
@ -1,6 +1,7 @@
|
|||||||
package net.i2p.router.web;
|
package net.i2p.router.web;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@ -19,6 +20,8 @@ public class ConfigUIHelper extends HelperBase {
|
|||||||
return buf.toString();
|
return buf.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static final String PROP_THEME_PFX = "routerconsole.theme.";
|
||||||
|
|
||||||
/** @return standard and user-installed themes, sorted (untranslated) */
|
/** @return standard and user-installed themes, sorted (untranslated) */
|
||||||
private Set<String> themeSet() {
|
private Set<String> themeSet() {
|
||||||
Set<String> rv = new TreeSet();
|
Set<String> rv = new TreeSet();
|
||||||
@ -33,6 +36,13 @@ public class ConfigUIHelper extends HelperBase {
|
|||||||
if (files[i].isDirectory() && ! name.equals("images"))
|
if (files[i].isDirectory() && ! name.equals("images"))
|
||||||
rv.add(name);
|
rv.add(name);
|
||||||
}
|
}
|
||||||
|
// user themes
|
||||||
|
Set props = _context.getPropertyNames();
|
||||||
|
for (Iterator iter = props.iterator(); iter.hasNext(); ) {
|
||||||
|
String prop = (String) iter.next();
|
||||||
|
if (prop.startsWith(PROP_THEME_PFX) && prop.length() > PROP_THEME_PFX.length())
|
||||||
|
rv.add(prop.substring(PROP_THEME_PFX.length()));
|
||||||
|
}
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import java.lang.reflect.Method;
|
|||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -26,7 +27,9 @@ import org.mortbay.jetty.Server;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start plugins that are already installed
|
* Start/stop/delete plugins that are already installed
|
||||||
|
* Get properties of installed plugins
|
||||||
|
* Get or change settings in plugins.config
|
||||||
*
|
*
|
||||||
* @since 0.7.12
|
* @since 0.7.12
|
||||||
* @author zzz
|
* @author zzz
|
||||||
@ -35,6 +38,10 @@ public class PluginStarter implements Runnable {
|
|||||||
private RouterContext _context;
|
private RouterContext _context;
|
||||||
static final String PREFIX = "plugin.";
|
static final String PREFIX = "plugin.";
|
||||||
static final String ENABLED = ".startOnLoad";
|
static final String ENABLED = ".startOnLoad";
|
||||||
|
private static final String[] STANDARD_WEBAPPS = { "i2psnark", "i2ptunnel", "susidns",
|
||||||
|
"susimail", "addressbook", "routerconsole" };
|
||||||
|
private static final String[] STANDARD_THEMES = { "images", "light", "dark", "classic",
|
||||||
|
"midnight" };
|
||||||
|
|
||||||
public PluginStarter(RouterContext ctx) {
|
public PluginStarter(RouterContext ctx) {
|
||||||
_context = ctx;
|
_context = ctx;
|
||||||
@ -81,6 +88,18 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
//log.error("Starting plugin: " + appName);
|
//log.error("Starting plugin: " + appName);
|
||||||
|
|
||||||
|
// register themes
|
||||||
|
File dir = new File(pluginDir, "console/themes");
|
||||||
|
File[] tfiles = dir.listFiles();
|
||||||
|
if (tfiles != null) {
|
||||||
|
for (int i = 0; i < tfiles.length; i++) {
|
||||||
|
String name = tfiles[i].getName();
|
||||||
|
if (tfiles[i].isDirectory() && (!Arrays.asList(STANDARD_THEMES).contains(tfiles[i])))
|
||||||
|
ctx.router().setConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name, tfiles[i].getAbsolutePath());
|
||||||
|
// we don't need to save
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// load and start things in clients.config
|
// load and start things in clients.config
|
||||||
File clientConfig = new File(pluginDir, "clients.config");
|
File clientConfig = new File(pluginDir, "clients.config");
|
||||||
if (clientConfig.exists()) {
|
if (clientConfig.exists()) {
|
||||||
@ -103,9 +122,7 @@ public class PluginStarter implements Runnable {
|
|||||||
String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
||||||
//log.error("Found webapp: " + warName);
|
//log.error("Found webapp: " + warName);
|
||||||
// check for duplicates in $I2P
|
// check for duplicates in $I2P
|
||||||
// easy way for now...
|
if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) {
|
||||||
if (warName.equals("i2psnark") || warName.equals("susidns") || warName.equals("i2ptunnel") ||
|
|
||||||
warName.equals("susimail") || warName.equals("addressbook")) {
|
|
||||||
log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
|
log.error("Skipping duplicate webapp " + warName + " in plugin " + appName);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -147,8 +164,6 @@ public class PluginStarter implements Runnable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add themes in console/themes
|
|
||||||
|
|
||||||
// add summary bar link
|
// add summary bar link
|
||||||
Properties props = pluginProperties(ctx, appName);
|
Properties props = pluginProperties(ctx, appName);
|
||||||
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
|
String name = ConfigClientsHelper.stripHTML(props, "consoleLinkName_" + Messages.getLanguage(ctx));
|
||||||
@ -192,8 +207,7 @@ public class PluginStarter implements Runnable {
|
|||||||
if (fileNames != null) {
|
if (fileNames != null) {
|
||||||
for (int i = 0; i < fileNames.length; i++) {
|
for (int i = 0; i < fileNames.length; i++) {
|
||||||
String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
String warName = fileNames[i].substring(0, fileNames[i].lastIndexOf(".war"));
|
||||||
if (warName.equals("i2psnark") || warName.equals("susidns") || warName.equals("i2ptunnel") ||
|
if (Arrays.asList(STANDARD_WEBAPPS).contains(warName)) {
|
||||||
warName.equals("susimail") || warName.equals("addressbook")) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
WebAppStarter.stopWebApp(server, warName);
|
WebAppStarter.stopWebApp(server, warName);
|
||||||
@ -213,12 +227,12 @@ public class PluginStarter implements Runnable {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @return true on success - call stopPlugin() first */
|
/** @return true on success - caller should call stopPlugin() first */
|
||||||
static boolean deletePlugin(RouterContext ctx, String appName) throws IOException {
|
static boolean deletePlugin(RouterContext ctx, String appName) throws IOException {
|
||||||
Log log = ctx.logManager().getLog(PluginStarter.class);
|
Log log = ctx.logManager().getLog(PluginStarter.class);
|
||||||
File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
|
File pluginDir = new File(ctx.getAppDir(), PluginUpdateHandler.PLUGIN_DIR + '/' + appName);
|
||||||
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
|
if ((!pluginDir.exists()) || (!pluginDir.isDirectory())) {
|
||||||
log.error("Cannot stop nonexistent plugin: " + appName);
|
log.error("Cannot delete nonexistent plugin: " + appName);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// uninstall things in clients.config
|
// uninstall things in clients.config
|
||||||
@ -229,6 +243,24 @@ public class PluginStarter implements Runnable {
|
|||||||
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
|
List<ClientAppConfig> clients = ClientAppConfig.getClientApps(clientConfig);
|
||||||
runClientApps(ctx, pluginDir, clients, "uninstall");
|
runClientApps(ctx, pluginDir, clients, "uninstall");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// unregister themes, and switch to default if we are unregistering the current theme
|
||||||
|
File dir = new File(pluginDir, "console/themes");
|
||||||
|
File[] tfiles = dir.listFiles();
|
||||||
|
if (tfiles != null) {
|
||||||
|
String current = ctx.getProperty(CSSHelper.PROP_THEME_NAME);
|
||||||
|
for (int i = 0; i < tfiles.length; i++) {
|
||||||
|
String name = tfiles[i].getName();
|
||||||
|
if (tfiles[i].isDirectory() && (!name.equals("images")) && (!name.equals("classic")) &&
|
||||||
|
(!name.equals("dark")) && (!name.equals("light")) && (!name.equals("midnight"))) {
|
||||||
|
ctx.router().removeConfigSetting(ConfigUIHelper.PROP_THEME_PFX + name);
|
||||||
|
if (name.equals(current))
|
||||||
|
ctx.router().setConfigSetting(CSSHelper.PROP_THEME_NAME, CSSHelper.DEFAULT_THEME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.router().saveConfig();
|
||||||
|
}
|
||||||
|
|
||||||
FileUtil.rmdir(pluginDir, false);
|
FileUtil.rmdir(pluginDir, false);
|
||||||
Properties props = pluginProperties();
|
Properties props = pluginProperties();
|
||||||
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
|
for (Iterator iter = props.keySet().iterator(); iter.hasNext(); ) {
|
||||||
|
@ -20,7 +20,29 @@ if (uri.endsWith(".css")) {
|
|||||||
response.setContentType("image/x-icon");
|
response.setContentType("image/x-icon");
|
||||||
}
|
}
|
||||||
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
response.setHeader("Cache-Control", "max-age=86400"); // cache for a day
|
||||||
String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath() +
|
/*
|
||||||
|
* User or plugin themes
|
||||||
|
* If the request is for /themes/console/foo/bar/baz,
|
||||||
|
* and the property routerconsole.theme.foo=/path/to/foo,
|
||||||
|
* get the file from /path/to/foo/bar/baz
|
||||||
|
*/
|
||||||
|
String themePath = null;
|
||||||
|
final String PFX = "/themes/console/";
|
||||||
|
if (uri.startsWith(PFX) && uri.length() > PFX.length() + 1) {
|
||||||
|
String theme = uri.substring(PFX.length());
|
||||||
|
int slash = theme.indexOf('/');
|
||||||
|
if (slash > 0) {
|
||||||
|
theme = theme.substring(0, slash);
|
||||||
|
themePath = net.i2p.I2PAppContext.getGlobalContext().getProperty("routerconsole.theme." + theme);
|
||||||
|
if (themePath != null)
|
||||||
|
uri = uri.substring(PFX.length() + theme.length()); // /bar/baz
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String base;
|
||||||
|
if (themePath != null)
|
||||||
|
base = themePath;
|
||||||
|
else
|
||||||
|
base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath() +
|
||||||
java.io.File.separatorChar + "docs";
|
java.io.File.separatorChar + "docs";
|
||||||
net.i2p.util.FileUtil.readFile(uri, base, response.getOutputStream());
|
net.i2p.util.FileUtil.readFile(uri, base, response.getOutputStream());
|
||||||
%>
|
%>
|
Reference in New Issue
Block a user