Console: Custom icons for non-webapp plugins, from cacapo (ticket #1550)

This commit is contained in:
zzz
2016-02-03 13:20:22 +00:00
parent bf51d5d9c4
commit acdaa60de3
4 changed files with 132 additions and 0 deletions

View File

@ -0,0 +1,90 @@
package net.i2p.router.web;
import java.io.IOException;
import java.io.OutputStream;
import java.io.File;
import java.util.Arrays;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import net.i2p.data.Base64;
/**
*
* @author cacapo
*/
public class CodedIconRendererServlet extends HttpServlet {
public static final long serialVersionUID = 16851750L;
String base = net.i2p.I2PAppContext.getGlobalContext().getBaseDir().getAbsolutePath();
String file = "docs" + java.io.File.separatorChar + "themes" + java.io.File.separatorChar + "console" + java.io.File.separatorChar + "images" + java.io.File.separatorChar + "plugin.png";
@Override
protected void service(HttpServletRequest srq, HttpServletResponse srs) throws ServletException, IOException {
byte[] data;
String name = srq.getParameter("plugin");
data = NavHelper.getBinary(name);
//set as many headers as are common to any outcome
srs.setContentType("image/png");
srs.setDateHeader("Expires", net.i2p.I2PAppContext.getGlobalContext().clock().now() + 86400000l);
srs.setHeader("Cache-Control", "public, max-age=86400");
OutputStream os = srs.getOutputStream();
//Binary data is present
if(data != null){
srs.setHeader("Content-Length", Integer.toString(data.length));
int content = Arrays.hashCode(data);
int chksum = srq.getIntHeader("If-None-Match");//returns -1 if no such header
//Don't render if icon already present
if(content != chksum){
srs.setIntHeader("ETag", content);
try{
os.write(data);
os.flush();
os.close();
}catch(IOException e){
net.i2p.I2PAppContext.getGlobalContext().logManager().getLog(getClass()).warn("Error writing binary image data for plugin", e);
}
} else {
srs.sendError(304, "Not Modified");
}
} else {
//Binary data is not present but must be substituted by file on disk
File pfile = new java.io.File(base, file);
srs.setHeader("Content-Length", Long.toString(pfile.length()));
try{
long lastmod = pfile.lastModified();
if(lastmod > 0){
long iflast = srq.getDateHeader("If-Modified-Since");
if(iflast >= ((lastmod/1000) * 1000)){
srs.sendError(304, "Not Modified");
} else {
srs.setDateHeader("Last-Modified", lastmod);
net.i2p.util.FileUtil.readFile(file, base, os);
}
}
} catch(java.io.IOException e) {
if (!srs.isCommitted()) {
srs.sendError(403, e.toString());
} else {
net.i2p.I2PAppContext.getGlobalContext().logManager().getLog(getClass()).warn("Error serving plugin.png", e);
throw e;
}
}
}
}
}

View File

@ -13,6 +13,7 @@ public class NavHelper {
private static final Map<String, String> _apps = new ConcurrentHashMap<String, String>(4);
private static final Map<String, String> _tooltips = new ConcurrentHashMap<String, String>(4);
private static final Map<String, String> _icons = new ConcurrentHashMap<String, String>(4);
private static final Map<String, byte[]> _binary = new ConcurrentHashMap<String, byte[]>(4);
/**
* To register a new client application so that it shows up on the router
@ -40,6 +41,20 @@ public class NavHelper {
_icons.remove(name);
}
public static byte[] getBinary(String name){
if(name != null)
return _binary.get(name);
else
return null;
}
public static void setBinary(String name, byte[] arr){
_binary.put(name, arr);
}
/**
* Translated string is loaded by PluginStarter
* @param ctx unused

View File

@ -22,6 +22,7 @@ import net.i2p.I2PAppContext;
import net.i2p.app.ClientApp;
import net.i2p.app.ClientAppState;
import net.i2p.data.DataHelper;
import net.i2p.data.Base64;
import net.i2p.router.RouterContext;
import net.i2p.router.RouterVersion;
import net.i2p.router.startup.ClientAppConfig;
@ -353,6 +354,20 @@ public class PluginStarter implements Runnable {
}
}
//handle console icons for plugins without web-resources through prop icon-code
String fullprop = props.getProperty("icon-code");
if(fullprop != null && fullprop.length() > 1){
byte[] decoded = Base64.decode(fullprop);
if(decoded != null) {
NavHelper.setBinary(appName, decoded);
iconfile = "/Plugins/pluginicon?plugin=" + appName;
} else {
iconfile = "/themes/console/images/plugin.png";
}
}
// load and start things in clients.config
File clientConfig = new File(pluginDir, "clients.config");
if (clientConfig.exists()) {