add plugin
68
build.xml
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||||
|
<project basedir="." default="all" name="prometheus">
|
||||||
|
<property file="override.properties"/>
|
||||||
|
|
||||||
|
<target name="all" depends="clean,plugin" />
|
||||||
|
|
||||||
|
<target name="war" >
|
||||||
|
<ant dir="src" target="build" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="plugin" depends="war">
|
||||||
|
<!-- get version number -->
|
||||||
|
<buildnumber file="scripts/build.number" />
|
||||||
|
<!-- change version in servlet when you change this -->
|
||||||
|
<property name="release.number" value="0.1" />
|
||||||
|
|
||||||
|
<!-- make the update su3 -->
|
||||||
|
<copy file="LICENSE.txt" todir="plugin/" overwrite="true" />
|
||||||
|
<copy file="README.txt" todir="plugin/" overwrite="true" />
|
||||||
|
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
|
||||||
|
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||||
|
<arg value="update-only=true" />
|
||||||
|
</exec>
|
||||||
|
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||||
|
<arg value="version=${release.number}-b${build.number}" />
|
||||||
|
</exec>
|
||||||
|
<mkdir dir="plugin/console/webapps" />
|
||||||
|
<copy file="src/build/prometheus.war" todir="plugin/console/webapps/" overwrite="true" />
|
||||||
|
<input message="Enter su3 signing key password:" addproperty="release.password.su3" />
|
||||||
|
<fail message="You must enter a password." >
|
||||||
|
<condition>
|
||||||
|
<equals arg1="${release.password.su3}" arg2=""/>
|
||||||
|
</condition>
|
||||||
|
</fail>
|
||||||
|
<!-- this will fail if no su3 keys exist, as it needs the password twice -->
|
||||||
|
<exec executable="scripts/makeplugin.sh" inputstring="${release.password.su3}" failonerror="true" >
|
||||||
|
<arg value="plugin" />
|
||||||
|
</exec>
|
||||||
|
<move file="prometheus.su3" tofile="prometheus-update.su3" overwrite="true" />
|
||||||
|
|
||||||
|
<!-- make the install su3 -->
|
||||||
|
<copy file="scripts/plugin.config" todir="plugin/" overwrite="true" />
|
||||||
|
<!-- Files in installer but not update. Be sure to Add to delete fileset above and clean target below -->
|
||||||
|
<exec executable="echo" osfamily="unix" failonerror="true" output="plugin/plugin.config" append="true">
|
||||||
|
<arg value="version=${release.number}-b${build.number}" />
|
||||||
|
</exec>
|
||||||
|
<exec executable="scripts/makeplugin.sh" inputstring="${release.password.su3}" failonerror="true" >
|
||||||
|
<arg value="plugin" />
|
||||||
|
</exec>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="distclean" depends="clean" />
|
||||||
|
|
||||||
|
<target name="clean" >
|
||||||
|
<ant dir="src" target="clean" />
|
||||||
|
<defaultexcludes remove="**/*~"/>
|
||||||
|
<delete>
|
||||||
|
<fileset dir="." includes="*/*.~ **/*.*~ */**/*.*~ *.*~" />
|
||||||
|
</delete>
|
||||||
|
<delete file="plugin/plugin.config" />
|
||||||
|
<delete file="plugin/console/webapps/prometheus.war" />
|
||||||
|
<delete file="plugin/LICENSE.txt" />
|
||||||
|
<delete file="plugin/README.txt" />
|
||||||
|
<delete file="prometheus.su3" />
|
||||||
|
<delete file="prometheus-update.su3" />
|
||||||
|
<delete file="plugin.zip" />
|
||||||
|
</target>
|
||||||
|
</project>
|
4
plugin/console/webapps/META-INF/MANIFEST.MF
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Ant-Version: Apache Ant 1.10.14
|
||||||
|
Created-By: 1.8.0_442-8u442-b06~us1-0ubuntu1~24.10-b06 (Private Build)
|
||||||
|
|
17
plugin/console/webapps/WEB-INF/web.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>io.prometheus.metrics.exporter.servlet.javax.PrometheusMetricsServlet</servlet-name>
|
||||||
|
<servlet-class>io.prometheus.metrics.exporter.servlet.javax.PrometheusMetricsServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<!-- precompiled servlets -->
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>io.prometheus.metrics.exporter.servlet.javax.PrometheusMetricsServlet</servlet-name>
|
||||||
|
<url-pattern>/</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
</web-app>
|
13
resources/collapse.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#configuration {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand {
|
||||||
|
display: inline-block !important;
|
||||||
|
z-index: 100 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collapse {
|
||||||
|
display: none !important;
|
||||||
|
z-index: -1 !important;
|
||||||
|
}
|
13
resources/expand.css
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#configuration {
|
||||||
|
display: table !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand {
|
||||||
|
display: none !important;
|
||||||
|
z-index: -1 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#collapse {
|
||||||
|
display: inline-block !important;
|
||||||
|
z-index: 100 !important;
|
||||||
|
}
|
BIN
resources/images/collapse.png
Normal file
After Width: | Height: | Size: 275 B |
1
resources/images/configure.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><radialGradient id="a" cx="31.93" cy="32" gradientTransform="matrix(.83 0 0 .81 5.44 5.97)" gradientUnits="userSpaceOnUse" r="17.66"><stop offset="0" stop-color="#ccc"/><stop offset="1" stop-color="#808080"/></radialGradient><path d="m31.93 14.34c-9.71 0-17.66 7.95-17.66 17.66s7.95 17.66 17.66 17.66 17.66-7.95 17.66-17.66-7.95-17.66-17.66-17.66zm0 25.02c-4.12 0-7.36-3.24-7.36-7.36s3.24-7.36 7.36-7.36 7.36 3.24 7.36 7.36-3.24 7.36-7.36 7.36z" fill="url(#a)" stroke="#808080"/><path d="m54.89 35.24c.15-1.03.29-2.06.29-3.24s-.15-2.21-.29-3.24l6.62-4.7c.6-.44.88-1.33.44-2.06l-6.47-10.9c-.44-.74-1.18-1.03-1.91-.6l-7.36 3.39a26.35 26.35 0 0 0 -5.59-3.24l-.74-8.1c-.15-.74-.74-1.33-1.47-1.33h-12.66c-.74 0-1.47.6-1.47 1.33l-.74 8.1c-2.06.88-3.97 1.91-5.59 3.24l-7.36-3.39c-.74-.29-1.62 0-1.91.6l-6.34 10.89c-.44.74-.15 1.62.44 2.06l6.62 4.7c-.15 1.03-.29 2.06-.29 3.24s.15 2.21.29 3.24l-6.92 4.7c-.6.44-.88 1.33-.44 2.06l6.33 10.9c.44.74 1.18 1.03 1.91.6l7.36-3.39a26.35 26.35 0 0 0 5.59 3.24l.74 8.1c.15.74.74 1.33 1.47 1.33h12.67c.74 0 1.47-.6 1.47-1.33l.74-8.1c2.06-.88 3.97-1.91 5.59-3.24l7.36 3.39c.74.29 1.62 0 1.91-.6l6.33-10.9c.44-.74.15-1.62-.44-2.06zm-22.96 11.48c-8.1 0-14.72-6.62-14.72-14.72s6.62-14.72 14.72-14.72 14.71 6.63 14.71 14.72-6.62 14.72-14.71 14.72z" fill="#e6e6e6" stroke="#4d4d4d" stroke-width="2.5"/></svg>
|
After Width: | Height: | Size: 1.4 KiB |
1
resources/images/cross.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path fill="red" d="M9.7 0c-1 0-2.1.4-3 1.2L1.3 7a4.2 4.2 0 000 5.8L20.6 32 1.3 51.3a4.2 4.2 0 000 5.9l5.6 5.6a4.2 4.2 0 005.9 0L32 43.5l19.2 19.3a4.2 4.2 0 005.9 0l5.6-5.6a4.2 4.2 0 000-5.9L43.5 32l19.2-19.3a4.1 4.1 0 000-5.9l-5.6-5.6a4.2 4.2 0 00-5.8 0L32 20.5 12.6 1.2A4.2 4.2 0 009.7 0z"/></svg>
|
After Width: | Height: | Size: 359 B |
BIN
resources/images/expand.png
Normal file
After Width: | Height: | Size: 281 B |
1
resources/images/infohelp.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 64 64"><defs><linearGradient xlink:href="#a" id="b" x1="26.9" x2="26.9" y1="17.2" y2="50.6" gradientUnits="userSpaceOnUse"/></defs><linearGradient id="a" x1="26.9" x2="26.9" y1="17.2" y2="50.6" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#59f"/><stop offset="1" stop-color="#2a7fff"/></linearGradient><path fill="url(#b)" stroke="#00002b" stroke-linejoin="round" stroke-width="6" d="M60.8 32a28.8 28.8 0 1 1-57.6 0 28.8 28.8 0 1 1 57.6 0z"/><path fill="url(#a)" stroke="#87aade" stroke-linejoin="round" stroke-width="4" d="M60.8 32a28.8 28.8 0 1 1-57.6 0 28.8 28.8 0 1 1 57.6 0z"/><path fill="none" stroke="#fff" stroke-linejoin="round" stroke-width="4" d="M57.2 32a25.2 25.2 0 0 1-50.4 0A25.2 25.2 0 0 1 32 7a25.2 25.2 0 0 1 25.2 25z"/><g fill="#fff"><path d="M35.6 48h-7.2V26.6h7.2z"/><circle cx="32" cy="19.7" r="3.6"/></g></svg>
|
After Width: | Height: | Size: 944 B |
50
resources/images/prometheus.svg
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||||
|
xmlns:cc="http://creativecommons.org/ns#"
|
||||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
version="1.1"
|
||||||
|
id="Layer_1"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
width="115.333px"
|
||||||
|
height="114px"
|
||||||
|
viewBox="0 0 115.333 114"
|
||||||
|
enable-background="new 0 0 115.333 114"
|
||||||
|
xml:space="preserve"
|
||||||
|
sodipodi:docname="prometheus_logo_orange.svg"
|
||||||
|
inkscape:version="0.92.1 r15371"><metadata
|
||||||
|
id="metadata4495"><rdf:RDF><cc:Work
|
||||||
|
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||||
|
id="defs4493" /><sodipodi:namedview
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#666666"
|
||||||
|
borderopacity="1"
|
||||||
|
objecttolerance="10"
|
||||||
|
gridtolerance="10"
|
||||||
|
guidetolerance="10"
|
||||||
|
inkscape:pageopacity="0"
|
||||||
|
inkscape:pageshadow="2"
|
||||||
|
inkscape:window-width="1484"
|
||||||
|
inkscape:window-height="886"
|
||||||
|
id="namedview4491"
|
||||||
|
showgrid="false"
|
||||||
|
inkscape:zoom="5.2784901"
|
||||||
|
inkscape:cx="60.603667"
|
||||||
|
inkscape:cy="60.329656"
|
||||||
|
inkscape:window-x="54"
|
||||||
|
inkscape:window-y="7"
|
||||||
|
inkscape:window-maximized="0"
|
||||||
|
inkscape:current-layer="Layer_1" /><g
|
||||||
|
id="Layer_2" /><path
|
||||||
|
style="fill:#e6522c;fill-opacity:1"
|
||||||
|
inkscape:connector-curvature="0"
|
||||||
|
id="path4486"
|
||||||
|
d="M 56.667,0.667 C 25.372,0.667 0,26.036 0,57.332 c 0,31.295 25.372,56.666 56.667,56.666 31.295,0 56.666,-25.371 56.666,-56.666 0,-31.296 -25.372,-56.665 -56.666,-56.665 z m 0,106.055 c -8.904,0 -16.123,-5.948 -16.123,-13.283 H 72.79 c 0,7.334 -7.219,13.283 -16.123,13.283 z M 83.297,89.04 H 30.034 V 79.382 H 83.298 V 89.04 Z M 83.106,74.411 H 30.186 C 30.01,74.208 29.83,74.008 29.66,73.802 24.208,67.182 22.924,63.726 21.677,60.204 c -0.021,-0.116 6.611,1.355 11.314,2.413 0,0 2.42,0.56 5.958,1.205 -3.397,-3.982 -5.414,-9.044 -5.414,-14.218 0,-11.359 8.712,-21.285 5.569,-29.308 3.059,0.249 6.331,6.456 6.552,16.161 3.252,-4.494 4.613,-12.701 4.613,-17.733 0,-5.21 3.433,-11.262 6.867,-11.469 -3.061,5.045 0.793,9.37 4.219,20.099 1.285,4.03 1.121,10.812 2.113,15.113 C 63.797,33.534 65.333,20.5 71,16 c -2.5,5.667 0.37,12.758 2.333,16.167 3.167,5.5 5.087,9.667 5.087,17.548 0,5.284 -1.951,10.259 -5.242,14.148 3.742,-0.702 6.326,-1.335 6.326,-1.335 l 12.152,-2.371 c 10e-4,-10e-4 -1.765,7.261 -8.55,14.254 z" /></svg>
|
After Width: | Height: | Size: 2.7 KiB |
1
resources/images/starting.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path fill="#141" stroke="#117" stroke-linejoin="round" stroke-width="5" d="M28.2 3.1v4.6A24.1 24.1 0 0 0 7.4 32a24.1 24.1 0 0 0 23.8 24.4v.1h.2l4.4 4.5v-4.6A24.1 24.1 0 0 0 56.6 32 24.1 24.1 0 0 0 32.8 7.7v-.1h-.2zm0 15.4v7l6.8-7a13.8 13.8 0 0 1 .8 27v-7l-6.9 7a13.8 13.8 0 0 1-11.2-13.6c0-6.5 4.5-12 10.5-13.4z"/><path fill="#59f" d="M31.2 7.5h1.5l-1.5 6.9V18a13.8 13.8 0 0 0-13.5 13.8 13.8 13.8 0 0 0 13.5 13.8l1.5-.2-1.5 10.7A24 24 0 0 1 7.4 32 24.1 24.1 0 0 1 31.2 7.5z"/><path fill="none" stroke="#117" stroke-width="5" d="M35.9 38.6 24.7 49.7l11.2 11.2"/><g fill="#0055d4"><path d="M32.7 56.5h-1.4l1.4-6.9v-3.7a13.8 13.8 0 0 0 0-27.6l-1.5.1 1.5-10.7c13.4.2 24 11.1 23.9 24.4a24.1 24.1 0 0 1-23.9 24.4z"/><path d="M35.8 60.8V38.6L24.6 49.7z"/></g><path fill="none" stroke="#117" stroke-width="5" d="m28.1 25.4 11.2-11.1L28 3"/><path fill="#59f" d="M28.2 3.1v22.3l11.2-11.1z"/></svg>
|
After Width: | Height: | Size: 948 B |
1
resources/images/tick.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><path fill="#71c837" d="M55.9 8.6a4.3 4.3 0 00-3 1.3l-31 30.8L11.3 30a4.4 4.4 0 00-6 0l-4 4.2a4.4 4.4 0 000 6L19 57.7a4.4 4.4 0 006 0l37.8-37.9a4.4 4.4 0 000-6l-4-4a4.3 4.3 0 00-3-1.3z"/></svg>
|
After Width: | Height: | Size: 253 B |
BIN
resources/images/tile2.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
557
resources/prometheus.css
Normal file
@ -0,0 +1,557 @@
|
|||||||
|
/* I2P Socks Proxy Plugin Theme by dr|z3d 2022 */
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--a: #3b6bbf;
|
||||||
|
--active: #f30;
|
||||||
|
--bevel: inset 0 0 0 1px #d0d0da, 0 0 1px 1px #97a2ce;
|
||||||
|
--bg: #a4a4cb;
|
||||||
|
--bg_status: var(--bg_table);
|
||||||
|
--bg_table: #f2f2ff;
|
||||||
|
--bodybg: var(--bg) url(images/tile2.png) fixed;
|
||||||
|
--bodyfont: 10.5pt Droid Sans, Open Sans, Noto Sans, Ubuntu, Segoe UI, Verdana, Helvetica Neue, sans-serif;
|
||||||
|
--border: 1px solid #6c6c93;
|
||||||
|
--border_inner: 1px solid #9898b3;
|
||||||
|
--btn_border: 1px solid #97a2ce;
|
||||||
|
--btn_hover: linear-gradient(180deg, #ddd, #fff);
|
||||||
|
--btn_active: var(--btn_hover);
|
||||||
|
--btn: linear-gradient(180deg, #fff, #e8e8ff);
|
||||||
|
--btn_shadow_active: var(--highlight), inset 4px 4px 4px rgba(0,0,0,.5);
|
||||||
|
--container: linear-gradient(90deg, #fff, #efefff, #fff);
|
||||||
|
--filter_shadow: drop-shadow(0 0 1px var(--hover)) drop-shadow(0 0 2px var(--hover));
|
||||||
|
--highlight: inset 0 0 0 1px #fff;
|
||||||
|
--highlight_notice: var(--highlight), inset 0 0 1px 1px #900, 0 0 2px 2px rgba(0,0,0,.2);
|
||||||
|
--hover: #f60;
|
||||||
|
--ink: #4f4f63;
|
||||||
|
--ink_light: #5b5b71;
|
||||||
|
--ink_status_hover: #292d3d;
|
||||||
|
--input_text: var(--bg_table);
|
||||||
|
--input_text_focus: #fff;
|
||||||
|
--monospaced: Droid Sans Mono, Noto Mono, DejaVu Sans Mono, Lucida Console, monospace;
|
||||||
|
--outline: 0 0 0 1px rgba(255,96,0,.5);
|
||||||
|
--rowEven: repeating-linear-gradient(135deg, rgba(252,252,255,.5) 2px, rgba(240, 240, 255, .3) 3px, #fafaff 5px) #f0f0ff;
|
||||||
|
--rowOdd: repeating-linear-gradient(45deg, rgba(255,255,255,.5) 2px, rgba(220, 220, 255, .3) 3px, #fafaff 5px), #fafaff;
|
||||||
|
--scrollbar_hover: rgba(16,16,48,.4) var(--bg);
|
||||||
|
--scrollbar: rgba(16,16,48,.3) rgba(0,0,0,0);
|
||||||
|
--selected: #77f;
|
||||||
|
--shadow_table: 0 0 1px 0 #bbc;
|
||||||
|
--shadow_input: var(--highlight), inset 1px 1px 1px 1px rgba(0,0,0,.6);
|
||||||
|
--th: linear-gradient(180deg, #fcfcff 50%, #f2f2ff 50%, #efefff);
|
||||||
|
--th_sub: linear-gradient(180deg, #fdfdff, #f0f0ff);
|
||||||
|
--txtshadow_title: 0 1px 1px #fff, 0 -1px 1px #e2e2ff, 0 2px 1px #ddf;
|
||||||
|
--visited: #2c4e8f;
|
||||||
|
--configure: url(images/configure.svg);
|
||||||
|
--cross: url(images/cross.svg);
|
||||||
|
--infohelp: url(images/infohelp.svg);
|
||||||
|
--socks: url(images/prometheus.svg);
|
||||||
|
--starting: url(images/starting.svg);
|
||||||
|
--tick: url(images/tick.svg);
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
#status .subtitle + tr, #status .subtitle + tr td {
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (prefers-color-scheme: dark) {
|
||||||
|
:root {
|
||||||
|
--a: #3b6bbf;
|
||||||
|
--active: #f30;
|
||||||
|
--bevel: inset 0 0 0 1px #000, 0 0 1px 1px #111, 0 0 0 2px #000;
|
||||||
|
--bodyfont: 10pt Droid Sans, Open Sans, Noto Sans, Ubuntu, Segoe UI, Verdana, Helvetica Neue, sans-serif;
|
||||||
|
--bg: #111;
|
||||||
|
--bg_status: #504a4a;
|
||||||
|
--bg_table: #222;
|
||||||
|
--bodybg: var(--bg);
|
||||||
|
--border: 1px solid #444;
|
||||||
|
--border_inner: 1px solid #181818;
|
||||||
|
--btn_border: 1px solid #97a2ce;
|
||||||
|
--btn_active: linear-gradient(180deg, #333, #444);
|
||||||
|
--btn_hover: linear-gradient(180deg, #444, #333 50%, #111);
|
||||||
|
--btn: linear-gradient(180deg, #333, #181818);
|
||||||
|
--container: #222;
|
||||||
|
--highlight: inset 0 0 0 1px rgba(255,255,255,.1);
|
||||||
|
--highlight_notice: var(--highlight), inset 0 0 1px 1px #300, 0 0 2px 2px rgba(0,0,0,.5);
|
||||||
|
--hover: #f60;
|
||||||
|
--ink: #ddd;
|
||||||
|
--ink_light: #eee;
|
||||||
|
--ink_status_hover: #fff;
|
||||||
|
--input_text_focus: #333;
|
||||||
|
--rowEven: #555;
|
||||||
|
--rowOdd: #444;
|
||||||
|
--scrollbar_hover: rgba(16,16,48,.4) var(--bg);
|
||||||
|
--scrollbar: rgba(16,16,48,.3) rgba(0,0,0,0);
|
||||||
|
--selected: #d30;
|
||||||
|
--shadow_table: 0 0 0 1px #222, 0 0 0 8px #333;
|
||||||
|
--th: linear-gradient(180deg, #303030 50%, #222 50%, #111);
|
||||||
|
--th_sub: linear-gradient(180deg, #333, #222);
|
||||||
|
--txtshadow_title: 0 0 0 1px #000;
|
||||||
|
--visited: #2c4e8f;
|
||||||
|
}
|
||||||
|
#expand img, #collapse img {
|
||||||
|
filter: invert(1) opacity(.7);
|
||||||
|
}
|
||||||
|
#expand:hover img, #collapse:hover img {
|
||||||
|
filter: invert(1) opacity(.95) var(--filter_shadow) !important;
|
||||||
|
}
|
||||||
|
#status {
|
||||||
|
border-collapse: separate;
|
||||||
|
border-spacing: 0;
|
||||||
|
border: var(--border) !important;
|
||||||
|
}
|
||||||
|
thead th, #configtitle {
|
||||||
|
box-shadow: inset 0 0 0 1px #444;
|
||||||
|
}
|
||||||
|
#expand, #collapse {
|
||||||
|
border-left: var(--border) !important;
|
||||||
|
}
|
||||||
|
#container {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
background: var(--bodybg);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 10px;
|
||||||
|
padding: 0;
|
||||||
|
min-width: 600px;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
body, table {
|
||||||
|
font: var(--bodyfont);
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
scrollbar-color: var(--scrollbar);
|
||||||
|
}
|
||||||
|
|
||||||
|
html:hover {
|
||||||
|
scrollbar-color: var(--scrollbar_hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
::selection {
|
||||||
|
text-shadow: none;
|
||||||
|
color: #fff;
|
||||||
|
background: var(--selected);
|
||||||
|
}
|
||||||
|
|
||||||
|
hr, .hidden {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:link, .node a:visited {
|
||||||
|
color: var(--a);
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:visited {
|
||||||
|
color: var(--visited);
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover, a:focus {
|
||||||
|
color: var(--hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:active {
|
||||||
|
color: var(--active);
|
||||||
|
}
|
||||||
|
|
||||||
|
#container {
|
||||||
|
margin: 15px 5px;
|
||||||
|
padding: 8px;
|
||||||
|
max-width: 1920px;
|
||||||
|
border: var(--border);
|
||||||
|
box-shadow: var(--bevel);
|
||||||
|
background: var(--container);
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
padding: 0 2px;
|
||||||
|
font-family: var(--monospaced);
|
||||||
|
color: #373;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
border: var(--border_inner);
|
||||||
|
background: var(--bg_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
tr {
|
||||||
|
border: var(--border_inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
#configtitle {
|
||||||
|
font-size: 13pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subtitle th {
|
||||||
|
padding: 6px 8px;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-transform: none;
|
||||||
|
font-size: 10.5pt;
|
||||||
|
background: var(--th_sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
border: var(--border_inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
#status th, #status td {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status th, #status td {
|
||||||
|
width: 20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status td {
|
||||||
|
padding: 9px 8px;
|
||||||
|
border: var(--border_inner);
|
||||||
|
background: var(--bg_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
#status td:first-child {
|
||||||
|
text-transform: lowercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status td:first-child::first-letter {
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status td::before {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#starting, #running, #registered, #notregistered {
|
||||||
|
vertical-align: middle;
|
||||||
|
font-size: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#starting::before, #running::before, #registered::before, #notregistered::before {
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
background: var(--starting) no-repeat center center / 22px;
|
||||||
|
content: "";
|
||||||
|
animation: spin linear 3s forwards infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
#running::before, #registered::before {
|
||||||
|
background: var(--tick) no-repeat center center / 16px;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#notregistered::before {
|
||||||
|
background: var(--cross) no-repeat center center / 16px;
|
||||||
|
animation: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.accept {
|
||||||
|
padding: 5px 9px 2px 26px;
|
||||||
|
background: var(--tick) no-repeat 9px center / 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
from {transform: rotate(0)}
|
||||||
|
to {transform: rotate(360deg)}
|
||||||
|
}
|
||||||
|
|
||||||
|
table table tr:not(.stream):nth-child(odd), #configuration tr:not(.stream):nth-child(odd) {
|
||||||
|
background: var(--rowOdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
table table tr:not(.stream):nth-child(even), #configuration tr:not(.stream):nth-child(even) {
|
||||||
|
background: var(--rowEven);
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
table table td::before {
|
||||||
|
min-height: 20px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
|
||||||
|
table table td, #configuration table td {
|
||||||
|
padding: 5px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, #configtitle {
|
||||||
|
padding: 6px 8px;
|
||||||
|
text-align: left;
|
||||||
|
letter-spacing: .08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: 11pt;
|
||||||
|
background: var(--th);
|
||||||
|
}
|
||||||
|
|
||||||
|
#title {
|
||||||
|
padding: 10px 8px 10px 44px;
|
||||||
|
font-size: 16pt;
|
||||||
|
letter-spacing: .08em !important;
|
||||||
|
line-height: 1.1;
|
||||||
|
text-shadow: var(--txtshadow_title);
|
||||||
|
background: var(--socks) no-repeat 6px center / 32px, var(--th);
|
||||||
|
}
|
||||||
|
|
||||||
|
#configsection, #configsection td {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configsection td {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configsection table td {
|
||||||
|
padding: 10px;
|
||||||
|
vertical-align: text-bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration {
|
||||||
|
position: relative;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration tr {
|
||||||
|
border-left: none !important;
|
||||||
|
border-right: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:first-child {
|
||||||
|
border-left: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:last-child {
|
||||||
|
border-right: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration tr:last-child, #configuration tr:last-child td {
|
||||||
|
border-bottom: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration th {
|
||||||
|
width: 25%;
|
||||||
|
letter-spacing: normal;
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:first-child {
|
||||||
|
border-left: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:last-child {
|
||||||
|
border-right: none !important;
|
||||||
|
line-height: 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#formaction td {
|
||||||
|
padding: 12px !important;
|
||||||
|
background: var(--th_sub);
|
||||||
|
}
|
||||||
|
|
||||||
|
#configtitle {
|
||||||
|
margin: -1px 0;
|
||||||
|
padding: 8px 8px 8px 32px;
|
||||||
|
width: 100%;
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
z-index: 99;
|
||||||
|
box-sizing: border-box;
|
||||||
|
text-transform: uppercase;
|
||||||
|
letter-spacing: .05em;
|
||||||
|
font-size: 12.5pt;
|
||||||
|
font-weight: bold;
|
||||||
|
border: var(--border_inner);
|
||||||
|
border-left: none;
|
||||||
|
border-right: none;
|
||||||
|
background: var(--configure) no-repeat 8px center / 18px, var(--th_sub) !important;
|
||||||
|
contain: paint;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand, #collapse {
|
||||||
|
display: inline-block !important;
|
||||||
|
position: absolute;
|
||||||
|
top: calc(50% - 18px);
|
||||||
|
right: -1px;
|
||||||
|
font-size: 0;
|
||||||
|
border-left: var(--border_inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
#collapse {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand img, #collapse img {
|
||||||
|
padding: 15px;
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
transform: scaleX(.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#collapse img {
|
||||||
|
transform: scaleY(.6);
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand:hover img, #collapse:hover img {
|
||||||
|
filter: var(--filter_shadow);
|
||||||
|
transform: scaleY(1.2) scaleX(.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#collapse:hover img {
|
||||||
|
transform: scaleX(1.2) scaleY(.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
#expand::before, #collapse::before {
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
background: #f00;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:nth-child(2) code {
|
||||||
|
line-height: 1.15;
|
||||||
|
color: #050;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:nth-child(2) code, #configuration td:nth-child(2) .nowrap {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nowrap {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: middle;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration .nowrap {
|
||||||
|
font-style: italic;
|
||||||
|
color: var(--ink);
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration i {
|
||||||
|
margin-right: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration tr {
|
||||||
|
border-top: var(--border_inner);
|
||||||
|
border-bottom: var(--border_inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
td, #configuration td {
|
||||||
|
border: var(--border_inner);
|
||||||
|
border-left-style: solid;
|
||||||
|
border-right-style: solid;
|
||||||
|
box-shadow: var(--highlight) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:first-child {
|
||||||
|
border-left: var(--border_inner) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td:last-child {
|
||||||
|
border-right: var(--border_inner) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#configuration td:first-child {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
#formaction {
|
||||||
|
background: var(--th);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text], input[type=password], input[type=submit] {
|
||||||
|
font: var(--bodyfont);
|
||||||
|
border: var(--border_inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text], input[type=password] {
|
||||||
|
padding: 7px 10px;
|
||||||
|
color: var(--ink_lighter);
|
||||||
|
background: var(--bg_table);
|
||||||
|
box-shadow: var(--shadow_input);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=text]:focus, input[type=password]:focus {
|
||||||
|
color: var(--ink);
|
||||||
|
background: var(--bg_table);
|
||||||
|
box-shadow: var(--btn_shadow_active), 0 0 0 1px rgba(255,96,0,.7);
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit] {
|
||||||
|
padding: 7px 14px 7px 30px;
|
||||||
|
color: var(--ink);
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: var(--highlight);
|
||||||
|
background: var(--tick) no-repeat 12px center / 12px, var(--btn);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit]:hover {
|
||||||
|
color: var(--ink_lighter);
|
||||||
|
background: var(--tick) no-repeat 12px center / 12px, var(--btn_hover);
|
||||||
|
box-shadow: var(--highlight), var(--outline);
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type=submit]:active {
|
||||||
|
box-shadow: var(--btn_shadow_active), var(--outline);
|
||||||
|
background: var(--tick) no-repeat 12px center / 12px, var(--btn_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
#message {
|
||||||
|
padding: 45px 15px 20px;
|
||||||
|
width: 400px;
|
||||||
|
display: inline-block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
right: -1000px;
|
||||||
|
text-align: center;
|
||||||
|
border: var(--border);
|
||||||
|
box-shadow: var(--highlight_notice);
|
||||||
|
background: var(--infohelp) no-repeat center 22px / 24px, var(--th_sub);
|
||||||
|
animation: slideLeft .75s ease-in .1s both, toast 2s ease 4s both;
|
||||||
|
filter: opacity(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#message td {
|
||||||
|
border: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes toast{
|
||||||
|
from {top: 0;}
|
||||||
|
to {top: -1000px}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes slideLeft {
|
||||||
|
from {top: 0; right: -800px; filter: opacity(0)}
|
||||||
|
to {top: 0; right: 0; filter: opacity(1)}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 1000px) {
|
||||||
|
body {margin: 3px}
|
||||||
|
body, table {font-size: 9.5pt}
|
||||||
|
#container {margin: 0}
|
||||||
|
#title {font-size: 14pt}
|
||||||
|
#configtitle {font-size: 12pt}
|
||||||
|
.subtitle th {font-size: 10pt}
|
||||||
|
#refresh {margin-top: 0}
|
||||||
|
}
|
60
resources/toggleConfig.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
var expandConfig = null;
|
||||||
|
var collapseConfig = null;
|
||||||
|
var config = null;
|
||||||
|
|
||||||
|
function initToggleConfig()
|
||||||
|
{
|
||||||
|
expandConfig = document.getElementById("expandConfig");
|
||||||
|
collapseConfig = document.getElementById("collapseConfig");
|
||||||
|
config = document.getElementById("configuration");
|
||||||
|
hideConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideConfig() {
|
||||||
|
if (!collapseConfig)
|
||||||
|
config.style.display = "none";
|
||||||
|
}
|
||||||
|
|
||||||
|
function showConfig() {
|
||||||
|
if (collapseConfig)
|
||||||
|
config.style.display = "block";
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean() {
|
||||||
|
if (expandConfig) {
|
||||||
|
expandConfig.remove();
|
||||||
|
}
|
||||||
|
if (collapseConfig) {
|
||||||
|
collapseConfig.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand() {
|
||||||
|
clean();
|
||||||
|
var x = document.createElement("link");
|
||||||
|
x.type="text/css";
|
||||||
|
x.rel="stylesheet";
|
||||||
|
x.href="/prometheus/resources/expand.css";
|
||||||
|
x.setAttribute("id", "expandConfig");
|
||||||
|
document.head.appendChild(x);
|
||||||
|
showConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function collapse() {
|
||||||
|
clean();
|
||||||
|
var c = document.createElement("link");
|
||||||
|
c.type="text/css";
|
||||||
|
c.rel="stylesheet";
|
||||||
|
c.href="/prometheus/resources/collapse.css";
|
||||||
|
c.setAttribute("id", "collapseConfig");
|
||||||
|
document.head.appendChild(c);
|
||||||
|
hideConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyText() {
|
||||||
|
document.execCommand("copy");
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function() {
|
||||||
|
initToggleConfig();
|
||||||
|
}, true);
|
130
scripts/makeplugin.sh
Executable file
@ -0,0 +1,130 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
#
|
||||||
|
# basic packaging up of a plugin
|
||||||
|
#
|
||||||
|
# usage: makeplugin.sh plugindir
|
||||||
|
#
|
||||||
|
# zzz 2010-02
|
||||||
|
# zzz 2014-08 added support for su3 files
|
||||||
|
#
|
||||||
|
|
||||||
|
if [ -z "$I2P" -a -d "$PWD/../i2p.i2p/pkg-temp" ]; then
|
||||||
|
export I2P=../i2p.i2p/pkg-temp
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d "$I2P" ]; then
|
||||||
|
echo "Can't locate your I2P installation. Please add a environment variable named I2P with the path to the folder as value"
|
||||||
|
echo "On OSX this solved with running: export I2P=/Applications/i2p if default install directory is used."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
PUBKEYDIR=$HOME/.i2p-plugin-keys
|
||||||
|
PUBKEYFILE=$PUBKEYDIR/plugin-public-signing.key
|
||||||
|
PRIVKEYFILE=$PUBKEYDIR/plugin-private-signing.key
|
||||||
|
B64KEYFILE=$PUBKEYDIR/plugin-public-signing.txt
|
||||||
|
PUBKEYSTORE=$PUBKEYDIR/plugin-su3-public-signing.crt
|
||||||
|
PRIVKEYSTORE=$PUBKEYDIR/plugin-su3-keystore.ks
|
||||||
|
KEYTYPE=RSA_SHA512_4096
|
||||||
|
|
||||||
|
PLUGINDIR=${1:-plugin}
|
||||||
|
|
||||||
|
PC=plugin.config
|
||||||
|
PCT=${PC}.tmp
|
||||||
|
|
||||||
|
if [ ! -d $PLUGINDIR ]
|
||||||
|
then
|
||||||
|
echo "You must have a $PLUGINDIR directory"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -f $PLUGINDIR/$PC ]
|
||||||
|
then
|
||||||
|
echo "You must have a $PLUGINDIR/$PC file"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
SIGNER=`grep '^signer=' $PLUGINDIR/$PC`
|
||||||
|
if [ "$?" -ne "0" ]
|
||||||
|
then
|
||||||
|
echo "You must have a plugin name in $PC"
|
||||||
|
echo 'For example name=foo'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
SIGNER=`echo $SIGNER | cut -f 2 -d '='`
|
||||||
|
|
||||||
|
if [ ! -f $PRIVKEYSTORE ]
|
||||||
|
then
|
||||||
|
echo "Creating new SU3 $KEYTYPE keys for $SIGNER"
|
||||||
|
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File keygen -t $KEYTYPE $PUBKEYSTORE $PRIVKEYSTORE $SIGNER || exit 1
|
||||||
|
echo '*** Save your password in a safe place!!! ***'
|
||||||
|
rm -rf logs/
|
||||||
|
# copy to the router dir so verify will work
|
||||||
|
CDIR=$I2P/certificates/plugin
|
||||||
|
mkdir -p $CDIR || exit 1
|
||||||
|
CFILE=$CDIR/`echo $SIGNER | sed s/@/_at_/`.crt
|
||||||
|
cp $PUBKEYSTORE $CFILE
|
||||||
|
chmod 444 $PUBKEYSTORE
|
||||||
|
chmod 400 $PRIVKEYSTORE
|
||||||
|
chmod 644 $CFILE
|
||||||
|
echo "Created new SU3 keys: $PUBKEYSTORE $PRIVKEYSTORE"
|
||||||
|
echo "Copied public key to $CFILE for testing"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f plugin.zip
|
||||||
|
|
||||||
|
OPWD=$PWD
|
||||||
|
cd $PLUGINDIR
|
||||||
|
|
||||||
|
grep -q '^name=' $PC
|
||||||
|
if [ "$?" -ne "0" ]
|
||||||
|
then
|
||||||
|
echo "You must have a plugin name in $PC"
|
||||||
|
echo 'For example name=foo'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
grep -q '^version=' $PC
|
||||||
|
if [ "$?" -ne "0" ]
|
||||||
|
then
|
||||||
|
echo "You must have a version in $PC"
|
||||||
|
echo 'For example version=0.1.2'
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# update the date
|
||||||
|
grep -v '^date=' $PC > $PCT
|
||||||
|
DATE=`date '+%s000'`
|
||||||
|
echo "date=$DATE" >> $PCT
|
||||||
|
mv $PCT $PC || exit 1
|
||||||
|
|
||||||
|
# add our Base64 key
|
||||||
|
grep -v '^key=' $PC > $PCT
|
||||||
|
B64KEY=`cat $B64KEYFILE`
|
||||||
|
echo "key=$B64KEY" >> $PCT || exit 1
|
||||||
|
mv $PCT $PC || exit 1
|
||||||
|
|
||||||
|
# zip it
|
||||||
|
zip -r $OPWD/plugin.zip * || exit 1
|
||||||
|
|
||||||
|
# get the version and use it for the sud header
|
||||||
|
VERSION=`grep '^version=' $PC | cut -f 2 -d '='`
|
||||||
|
# get the name and use it for the file name
|
||||||
|
NAME=`grep '^name=' $PC | cut -f 2 -d '='`
|
||||||
|
SU3=${NAME}.su3
|
||||||
|
cd $OPWD
|
||||||
|
|
||||||
|
# sign it
|
||||||
|
echo 'Signing. ...'
|
||||||
|
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File sign -c PLUGIN -t $KEYTYPE plugin.zip $SU3 $PRIVKEYSTORE $VERSION $SIGNER || exit 1
|
||||||
|
rm -f plugin.zip
|
||||||
|
|
||||||
|
# verify
|
||||||
|
echo "Verifying with $PUBKEYSTORE ..."
|
||||||
|
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File showversion $SU3 || exit 1
|
||||||
|
java -cp $I2P/lib/i2p.jar net.i2p.crypto.SU3File verifysig -k $PUBKEYSTORE $SU3 || exit 1
|
||||||
|
rm -rf logs/
|
||||||
|
|
||||||
|
echo 'Plugin files created: '
|
||||||
|
wc -c $SU3
|
||||||
|
|
||||||
|
exit 0
|
10
scripts/plugin.config
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name=prometheus
|
||||||
|
consoleLinkName=Prometheus Metrics
|
||||||
|
consoleLinkURL=/prometheus/status.html
|
||||||
|
console-icon=/resources/images/prometheus.svg
|
||||||
|
signer=zzz-plugin@mail.i2p
|
||||||
|
description=Prometheus Metrics Server
|
||||||
|
author=zzz
|
||||||
|
updateURL.su3=http://stats.i2p/i2p/plugins/prometheus-update.su3
|
||||||
|
websiteURL=http://zzz.i2p/forums/16
|
||||||
|
license=Apache 2.0
|
77
src/build.xml
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project basedir="." default="all" name="prometheus">
|
||||||
|
<property name="i2pbase" value="../../i2p.i2p"/>
|
||||||
|
<property name="i2plib" value="${i2pbase}/build"/>
|
||||||
|
<property name="jettylib" value="${i2pbase}/apps/jetty/jettylib"/>
|
||||||
|
<path id="cp">
|
||||||
|
<pathelement path="${java.class.path}" />
|
||||||
|
<pathelement location="${i2plib}/i2p.jar" />
|
||||||
|
<pathelement location="${jettylib}/jasper-runtime.jar" />
|
||||||
|
<pathelement location="${jettylib}/javax.servlet.jar" />
|
||||||
|
<pathelement location="${jettylib}/jetty-util.jar" />
|
||||||
|
</path>
|
||||||
|
|
||||||
|
<target name="all" depends="clean, build" />
|
||||||
|
<target name="build" depends="war" />
|
||||||
|
<target name="builddep">
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<property name="prom.version" value="1.3.6" />
|
||||||
|
|
||||||
|
<property name="javac.compilerargs" value="" />
|
||||||
|
<property name="javac.version" value="1.8" />
|
||||||
|
|
||||||
|
<target name="jar" >
|
||||||
|
<jar destfile="build/prometheus.jar" >
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-config-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-core-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-exporter-common-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-exporter-servlet-javax-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-exposition-textformats-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-instrumentation-jvm-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-model-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-tracer-common-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
<zipfileset src="../lib/prometheus-metrics-tracer-initializer-${prom.version}.jar" excludes="META-INF META-INF/**/*" />
|
||||||
|
</jar>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="compile" depends="jar" >
|
||||||
|
<mkdir dir="./build" />
|
||||||
|
<mkdir dir="./build/obj" />
|
||||||
|
<javac
|
||||||
|
srcdir="./java"
|
||||||
|
debug="true" deprecation="on" source="${javac.version}" target="${javac.version}"
|
||||||
|
destdir="./build/obj"
|
||||||
|
includeAntRuntime="false"
|
||||||
|
classpath="${i2plib}/i2p.jar:${jettylib}/javax.servlet.jar:build/prometheus.jar" >
|
||||||
|
<compilerarg line="${javac.compilerargs}" />
|
||||||
|
</javac>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="precompilejsp" depends="compile" >
|
||||||
|
<mkdir dir="build" />
|
||||||
|
<mkdir dir="build/war/WEB-INF/classes" />
|
||||||
|
<copy file="jsp/WEB-INF/web.xml" tofile="build/web.xml" overwrite="true" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="war" depends="precompilejsp">
|
||||||
|
<!-- add css and resources -->
|
||||||
|
<copy todir="build/war/resources" overwrite="true" >
|
||||||
|
<fileset dir="../resources" />
|
||||||
|
</copy>
|
||||||
|
<war destfile="build/prometheus.war" webxml="build/web.xml">
|
||||||
|
<classes dir="./build/obj" />
|
||||||
|
<fileset dir="./build/war" />
|
||||||
|
<zipfileset src="build/prometheus.jar" excludes="META-INF META-INF/**/*" prefix="WEB-INF/classes/" />
|
||||||
|
</war>
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="clean">
|
||||||
|
<delete dir="./build" />
|
||||||
|
</target>
|
||||||
|
|
||||||
|
<target name="cleandep" depends="clean">
|
||||||
|
</target>
|
||||||
|
<target name="distclean" depends="clean">
|
||||||
|
</target>
|
||||||
|
</project>
|
175
src/java/net/i2p/prometheus/PromManager.java
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
package net.i2p.prometheus;
|
||||||
|
/*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
import java.net.Socket;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.SortedSet;
|
||||||
|
|
||||||
|
import io.prometheus.metrics.core.metrics.GaugeWithCallback;
|
||||||
|
import io.prometheus.metrics.instrumentation.jvm.JvmMetrics;
|
||||||
|
import io.prometheus.metrics.model.registry.PrometheusRegistry;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.app.*;
|
||||||
|
import static net.i2p.app.ClientAppState.*;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.stat.Rate;
|
||||||
|
import net.i2p.stat.RateStat;
|
||||||
|
import net.i2p.stat.StatManager;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author zzz
|
||||||
|
*/
|
||||||
|
public class PromManager implements ClientApp {
|
||||||
|
private final I2PAppContext _context;
|
||||||
|
private final Log _log;
|
||||||
|
private final ClientAppManager _mgr;
|
||||||
|
private int i2pCount, jvmCount;
|
||||||
|
|
||||||
|
private ClientAppState _state = UNINITIALIZED;
|
||||||
|
|
||||||
|
public PromManager(I2PAppContext ctx, ClientAppManager mgr, String args[]) {
|
||||||
|
_context = ctx;
|
||||||
|
_log = ctx.logManager().getLog(PromManager.class);
|
||||||
|
_mgr = mgr;
|
||||||
|
_state = INITIALIZED;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getJVMCount() { return jvmCount; }
|
||||||
|
public int getI2PCount() { return i2pCount; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Not supported
|
||||||
|
*/
|
||||||
|
public synchronized static void main(String args[]) {
|
||||||
|
throw new UnsupportedOperationException("Must use ClientApp interface");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This adds the stats present at plugin startup.
|
||||||
|
* TODO: add a monitor to add stats that appear later.
|
||||||
|
*/
|
||||||
|
private void addStats() {
|
||||||
|
StatManager sm = _context.statManager();
|
||||||
|
Map<String, SortedSet<String>> groups = sm.getStatsByGroup();
|
||||||
|
int n = 0;
|
||||||
|
for (Map.Entry<String, SortedSet<String>> e : groups.entrySet()) {
|
||||||
|
//String pfx = "i2p." + e.getKey() + '.';
|
||||||
|
String pfx = "i2p.";
|
||||||
|
for (String s : e.getValue()) {
|
||||||
|
RateStat rs = sm.getRate(s);
|
||||||
|
if (rs == null)
|
||||||
|
continue;
|
||||||
|
String desc = rs.getDescription();
|
||||||
|
if (desc == null)
|
||||||
|
desc = "";
|
||||||
|
long[] pers = rs.getPeriods();
|
||||||
|
final long per = pers[0];
|
||||||
|
final Rate rate = rs.getRate(per);
|
||||||
|
if (rate == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
String name = pfx + s + '.' + DataHelper.formatDuration(per);
|
||||||
|
name = name.replace(".", "_");
|
||||||
|
name = name.replace("-", "_");
|
||||||
|
// https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
|
||||||
|
// Prevent IllegalArgumentExceptions
|
||||||
|
if (name.replaceAll("[a-zA-Z0-9_]", "").length() != 0) {
|
||||||
|
if (_log.shouldWarn())
|
||||||
|
_log.warn("skipping stat with illegal chars: " + name);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.debug("adding gauge " + name);
|
||||||
|
|
||||||
|
GaugeWithCallback.builder()
|
||||||
|
.name(name)
|
||||||
|
.help(desc)
|
||||||
|
.labelNames("state")
|
||||||
|
.callback(callback -> {
|
||||||
|
callback.call(rate.getAvgOrLifetimeAvg(), "average");
|
||||||
|
})
|
||||||
|
.register();
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i2pCount = n;
|
||||||
|
if (_log.shouldDebug())
|
||||||
|
_log.info(n + " PromManager I2P metrics registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/////// ClientApp methods
|
||||||
|
|
||||||
|
public synchronized void startup() throws Exception {
|
||||||
|
if (_state != STOPPED && _state != INITIALIZED && _state != START_FAILED) {
|
||||||
|
_log.error("Start while state = " + _state);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_log.info("PromManager startup");
|
||||||
|
JvmMetrics.builder().register();
|
||||||
|
jvmCount = PrometheusRegistry.defaultRegistry.scrape().size();
|
||||||
|
if (_log.shouldInfo())
|
||||||
|
_log.info(jvmCount + " PromManager JVM metrics registered");
|
||||||
|
|
||||||
|
addStats();
|
||||||
|
changeState(RUNNING);
|
||||||
|
_mgr.register(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void shutdown(String[] args) {
|
||||||
|
_log.warn("PromManager shutdown");
|
||||||
|
if (_state == STOPPED)
|
||||||
|
return;
|
||||||
|
changeState(STOPPING);
|
||||||
|
// clear() supported as of v1.3.2
|
||||||
|
PrometheusRegistry.defaultRegistry.clear();
|
||||||
|
_mgr.unregister(this);
|
||||||
|
changeState(STOPPED);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClientAppState getState() {
|
||||||
|
return _state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return "prometheus";
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return "PromManager Metrics";
|
||||||
|
}
|
||||||
|
|
||||||
|
/////// end ClientApp methods
|
||||||
|
|
||||||
|
private synchronized void changeState(ClientAppState state) {
|
||||||
|
if (state == _state)
|
||||||
|
return;
|
||||||
|
_state = state;
|
||||||
|
_mgr.notify(this, state, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void changeState(ClientAppState state, String msg, Exception e) {
|
||||||
|
if (state == _state)
|
||||||
|
return;
|
||||||
|
_state = state;
|
||||||
|
_mgr.notify(this, state, msg, e);
|
||||||
|
}
|
||||||
|
}
|
151
src/java/net/i2p/prometheus/web/BasicServlet.java
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// Copyright 199-2004 Mort Bay Consulting Pty. Ltd.
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
// ========================================================================
|
||||||
|
|
||||||
|
package net.i2p.prometheus.web;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.net.MalformedURLException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.UnavailableException;
|
||||||
|
import javax.servlet.http.HttpServlet;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
import net.i2p.data.ByteArray;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.util.ByteCache;
|
||||||
|
import net.i2p.util.Log;
|
||||||
|
import net.i2p.util.SystemVersion;
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/**
|
||||||
|
* Based on DefaultServlet from Jetty 6.1.26, heavily simplified
|
||||||
|
* and modified to remove all dependencies on Jetty libs.
|
||||||
|
*
|
||||||
|
* Supports HEAD and GET only, for resources from the .war and local files.
|
||||||
|
* Supports files and resource only.
|
||||||
|
* Supports MIME types with local overrides and additions.
|
||||||
|
* Supports Last-Modified.
|
||||||
|
* Supports single request ranges.
|
||||||
|
*
|
||||||
|
* Does not support directories or "welcome files".
|
||||||
|
* Does not support gzip.
|
||||||
|
* Does not support multiple request ranges.
|
||||||
|
* Does not cache.
|
||||||
|
*
|
||||||
|
* POST returns 405.
|
||||||
|
* Directories return 403.
|
||||||
|
* Jar resources are sent with a long cache directive.
|
||||||
|
*
|
||||||
|
* ------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The default servlet.
|
||||||
|
* This servlet, normally mapped to /, provides the handling for static
|
||||||
|
* content, OPTION and TRACE methods for the context.
|
||||||
|
* The following initParameters are supported, these can be set
|
||||||
|
* on the servlet itself:
|
||||||
|
* <PRE>
|
||||||
|
*
|
||||||
|
* resourceBase Set to replace the context resource base
|
||||||
|
|
||||||
|
* warBase Path allowed for resource in war
|
||||||
|
*
|
||||||
|
* </PRE>
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @author Greg Wilkins (gregw)
|
||||||
|
* @author Nigel Canonizado
|
||||||
|
*
|
||||||
|
* @since Jetty 7
|
||||||
|
*/
|
||||||
|
class BasicServlet extends HttpServlet
|
||||||
|
{
|
||||||
|
protected final I2PAppContext _context;
|
||||||
|
protected final Log _log;
|
||||||
|
protected File _resourceBase;
|
||||||
|
private String _warBase;
|
||||||
|
|
||||||
|
/** same as PeerState.PARTSIZE */
|
||||||
|
private static final int BUFSIZE = 16*1024;
|
||||||
|
private ByteCache _cache = ByteCache.getInstance(16, BUFSIZE);
|
||||||
|
|
||||||
|
private static final int WAR_CACHE_CONTROL_SECS = 24*60*60;
|
||||||
|
private static final int FILE_CACHE_CONTROL_SECS = 24*60*60;
|
||||||
|
|
||||||
|
public BasicServlet() {
|
||||||
|
super();
|
||||||
|
_context = I2PAppContext.getGlobalContext();
|
||||||
|
_log = _context.logManager().getLog(getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
public void init(ServletConfig cfg) throws ServletException {
|
||||||
|
super.init(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
protected void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------ */
|
||||||
|
/* (non-Javadoc)
|
||||||
|
* @see javax.servlet.http.HttpServlet#doTrace(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
|
||||||
|
*/
|
||||||
|
protected void doTrace(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doOptions(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
response.sendError(405);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple version of URIUtil.addPaths()
|
||||||
|
* @param path may be null
|
||||||
|
*/
|
||||||
|
protected static String addPaths(String base, String path) {
|
||||||
|
if (path == null)
|
||||||
|
return base;
|
||||||
|
String rv = (new File(base, path)).toString();
|
||||||
|
if (SystemVersion.isWindows())
|
||||||
|
rv = rv.replace("\\", "/");
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
}
|
254
src/java/net/i2p/prometheus/web/PrometheusServlet.java
Normal file
@ -0,0 +1,254 @@
|
|||||||
|
package net.i2p.prometheus.web;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import javax.servlet.ServletConfig;
|
||||||
|
import javax.servlet.ServletException;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
|
import net.i2p.app.ClientAppManager;
|
||||||
|
import net.i2p.app.ClientAppState;
|
||||||
|
import net.i2p.data.DataHelper;
|
||||||
|
import net.i2p.prometheus.PromManager;
|
||||||
|
import net.i2p.util.I2PAppThread;
|
||||||
|
import net.i2p.util.PortMapper;
|
||||||
|
import net.i2p.util.Translate;
|
||||||
|
|
||||||
|
import net.i2p.I2PAppContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From socksoutproxy
|
||||||
|
*/
|
||||||
|
public class PrometheusServlet extends BasicServlet {
|
||||||
|
private String _contextPath;
|
||||||
|
private String _contextName;
|
||||||
|
private volatile PromManager _manager;
|
||||||
|
private volatile boolean _isRunning;
|
||||||
|
private static long _nonce;
|
||||||
|
|
||||||
|
private static final String DEFAULT_NAME = "prometheus";
|
||||||
|
private static final String DOCTYPE = "<!DOCTYPE HTML>\n";
|
||||||
|
private static final String FOOTER = "</table>\n</div>\n<span id=\"endOfPage\" data-iframe-height></span>\n</body>\n</html>";
|
||||||
|
// for now, use console bundle, hope to pick up a few translations for free
|
||||||
|
private static final String BUNDLE = "net.i2p.router.web.messages";
|
||||||
|
private static final String RESOURCES = "/prometheus/resources/";
|
||||||
|
private static final String VERSION = "0.1";
|
||||||
|
|
||||||
|
public PrometheusServlet() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(ServletConfig cfg) throws ServletException {
|
||||||
|
super.init(cfg);
|
||||||
|
String cpath = getServletContext().getContextPath();
|
||||||
|
_contextPath = cpath == "" ? "/" : cpath;
|
||||||
|
_contextName = cpath == "" ? DEFAULT_NAME : cpath.substring(1).replace("/", "_");
|
||||||
|
_nonce = _context.random().nextLong();
|
||||||
|
_isRunning = true;
|
||||||
|
(new Starter()).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for the ClientAppManager
|
||||||
|
*/
|
||||||
|
private class Starter extends I2PAppThread {
|
||||||
|
public Starter() {
|
||||||
|
super("Prometheus Starter");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run() {
|
||||||
|
try {
|
||||||
|
run2();
|
||||||
|
} catch (Throwable t) {
|
||||||
|
// class problems, old router version, ...
|
||||||
|
_log.error("Unable to start Prometheus", t);
|
||||||
|
_isRunning = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run2() throws Exception {
|
||||||
|
File f = new File(_context.getConfigDir(), "plugins");
|
||||||
|
f = new File(f, _contextName);
|
||||||
|
String[] args = new String[] { f.toString() };
|
||||||
|
while (_isRunning) {
|
||||||
|
ClientAppManager cam = _context.clientAppManager();
|
||||||
|
if (cam != null) {
|
||||||
|
_manager = new PromManager(_context, cam, args);
|
||||||
|
_manager.startup();
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
Thread.sleep(10*1000);
|
||||||
|
} catch (InterruptedException ie) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void destroy() {
|
||||||
|
_isRunning = false;
|
||||||
|
if (_manager != null)
|
||||||
|
_manager.shutdown(null);
|
||||||
|
super.destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle what we can here, calling super.doGet() for the rest.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
doGetAndPost(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle what we can here, calling super.doPost() for the rest.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
doGetAndPost(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle all here
|
||||||
|
*/
|
||||||
|
private void doGetAndPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||||
|
PromManager c = _manager;
|
||||||
|
String method = req.getMethod();
|
||||||
|
String msg = null;
|
||||||
|
if (c != null) {
|
||||||
|
if (c.getState() != ClientAppState.RUNNING) {
|
||||||
|
try {
|
||||||
|
c.startup();
|
||||||
|
msg = "Prometheus started";
|
||||||
|
} catch (Exception e) {
|
||||||
|
msg = "Prometheus failure: " + e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the part after /orchid
|
||||||
|
String path = req.getServletPath();
|
||||||
|
resp.setHeader("X-Frame-Options", "SAMEORIGIN");
|
||||||
|
|
||||||
|
req.setCharacterEncoding("UTF-8");
|
||||||
|
resp.setCharacterEncoding("UTF-8");
|
||||||
|
resp.setContentType("text/html; charset=UTF-8");
|
||||||
|
|
||||||
|
PrintWriter out = resp.getWriter();
|
||||||
|
out.write(DOCTYPE + "<html>\n<head>\n<title>");
|
||||||
|
out.write(_t("Prometheus Metrics Client"));
|
||||||
|
out.write("</title>\n");
|
||||||
|
out.write("<script src=\"" + RESOURCES + "toggleConfig.js\" type=\"application/javascript\"></script>\n");
|
||||||
|
out.write("<meta http-equiv=\"Content-Security-Policy\" content=\"script-src \'self\' \'unsafe-inline\';\">\n");
|
||||||
|
out.write("<link rel=\"icon\" href=\"" + RESOURCES + "images/prometheus.svg\">\n");
|
||||||
|
out.write("<link href=\"" + RESOURCES + "prometheus.css?" + VERSION + "\" rel=\"stylesheet\" type=\"text/css\">\n");
|
||||||
|
out.write("<noscript><style>.script, #expand, #collapse {display: none !important} #configuration {display: table !important} " +
|
||||||
|
"*::selection {color: #fff; background: #77f}");
|
||||||
|
out.write("</style></noscript>\n</head>\n");
|
||||||
|
out.write("<body id=\"prometheus\">\n<div id=\"container\">\n<table id=\"main\" width=\"100%\">\n" +
|
||||||
|
"<thead><tr><th id=\"title\" align=\"left\">" + _t("Prometheus Metrics Client") + "</th></tr></thead>\n");
|
||||||
|
out.write("<tbody>\n<tr><td>\n<hr>\n<table id=\"status\" width=\"100%\">\n<tr class=\"subtitle\">" +
|
||||||
|
"<th width=\"20%\">" + _t("Status") + "</th>" +
|
||||||
|
"<th width=\"20%\">" + _t("Registered with I2P") + "</th>" +
|
||||||
|
"<th width=\"20%\">" + _t("Plugin Version") + "</th>" +
|
||||||
|
"<th width=\"20%\">" + _t("I2P Metrics") + "</th>" +
|
||||||
|
"<th width=\"20%\">" + _t("Java Metrics") + "</th>");
|
||||||
|
out.write("</tr>\n<tr><td align=\"center\">");
|
||||||
|
if (c != null) {
|
||||||
|
ClientAppState status = c.getState();
|
||||||
|
if (status == ClientAppState.RUNNING)
|
||||||
|
out.write("<span id=\"running\">" + _t("Running") + "</span>");
|
||||||
|
else if (status == ClientAppState.STARTING)
|
||||||
|
out.write("<span id=\"starting\">" + _t("Starting") + "...</span>");
|
||||||
|
else if (status == ClientAppState.START_FAILED)
|
||||||
|
out.write("<span id=\"notregistered\">" + _t("Start failed") + "</span>");
|
||||||
|
else
|
||||||
|
out.write(status.toString());
|
||||||
|
} else {
|
||||||
|
out.write(_t("Not initialized"));
|
||||||
|
}
|
||||||
|
out.write("</td><td align=\"center\">");
|
||||||
|
ClientAppManager cam = _context.clientAppManager();
|
||||||
|
if (c != null && cam != null && cam.getRegisteredApp(DEFAULT_NAME) == c) {
|
||||||
|
out.write("<span id=\"registered\">" + _t("Yes") + "</span>");
|
||||||
|
} else {
|
||||||
|
out.write("<span id=\"notregistered\">" + _t("No") + "</span>");
|
||||||
|
}
|
||||||
|
out.write("</td><td align=\"center\">" + VERSION + "</td>\n");
|
||||||
|
if (c != null)
|
||||||
|
out.write("</td><td align=\"center\">" + c.getI2PCount() + "</td>\n");
|
||||||
|
else
|
||||||
|
out.write("</td><td align=\"center\">--</td>\n");
|
||||||
|
if (c != null)
|
||||||
|
out.write("</td><td align=\"center\">" + c.getJVMCount() + "</td>\n");
|
||||||
|
else
|
||||||
|
out.write("</td><td align=\"center\">--</td></tr>\n");
|
||||||
|
if (msg != null)
|
||||||
|
out.write("<tr id=\"message\"><td colspan=\"5\" align=\"center\"><b>" + msg + "</b></td></tr>\n");
|
||||||
|
out.write("</table>\n");
|
||||||
|
if (c != null) {
|
||||||
|
out.write("<tr id=\"configsection\"><td>\n<hr>\n<div id=\"configtitle\"><b>Configuration</b> \n" +
|
||||||
|
"<a class=\"script\" id=\"expand\" href=\"#\" onclick=\"clean();expand();\">" +
|
||||||
|
"<img alt=\"Expand\" src=\"/prometheus/resources/images/expand.png\" title=\"Expand\"></a>\n" +
|
||||||
|
"<a class=\"script\" id=\"collapse\" href=\"#\" onclick=\"clean();collapse();\">" +
|
||||||
|
"<img alt=\"Collapse\" src=\"/prometheus/resources/images/collapse.png\" title=\"Collapse\"></a></div>\n");
|
||||||
|
out.write(getHTMLConfig(c));
|
||||||
|
}
|
||||||
|
out.write(FOOTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getHTMLConfig(PromManager tc) {
|
||||||
|
StringBuilder buf = new StringBuilder(1024);
|
||||||
|
buf.append("<hr>\n<div id=\"configuration\" width=\"100%\">\n");
|
||||||
|
boolean full = _context.getBooleanProperty("stat.full");
|
||||||
|
if (full)
|
||||||
|
buf.append("<p>Full stats are enabled.</p>\n");
|
||||||
|
else
|
||||||
|
buf.append("<p>For more metrics, <a href=\"/configstats\">enable full stats</a> and restart.</p>\n");
|
||||||
|
buf.append("<p>Prometheus server configuration - add to /etc/prometheus/prometheus.yml:</p>\n");
|
||||||
|
int port = _context.portMapper().getPort(PortMapper.SVC_CONSOLE);
|
||||||
|
if (port <= 0)
|
||||||
|
port = 7657;
|
||||||
|
buf.append("<pre>" +
|
||||||
|
" - job_name: i2p\n" +
|
||||||
|
" scrape_interval: 60s\n" +
|
||||||
|
" metrics_path: /prometheus/metrics\n" +
|
||||||
|
" static_configs:\n" +
|
||||||
|
" - targets: ['localhost:").append(port).append("']\n" +
|
||||||
|
"</pre>\n");
|
||||||
|
buf.append("</div>\n");
|
||||||
|
return buf.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** translate */
|
||||||
|
private String _t(String s) {
|
||||||
|
return Translate.getString(s, _context, BUNDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** translate */
|
||||||
|
private String _t(String s, Object o) {
|
||||||
|
return Translate.getString(s, o, _context, BUNDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** translate */
|
||||||
|
private String _t(String s, Object o, Object o2) {
|
||||||
|
return Translate.getString(s, o, o2, _context, BUNDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** translate (ngettext) @since 0.7.14 */
|
||||||
|
private String ngettext(String s, String p, int n) {
|
||||||
|
return Translate.getString(n, s, p, _context, BUNDLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** dummy for tagging */
|
||||||
|
private static String ngettext(String s, String p) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
60
src/jsp/WEB-INF/web.xml
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<servlet-class>net.i2p.prometheus.web.PrometheusServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>PrometheusMetricsServlet</servlet-name>
|
||||||
|
<servlet-class>io.prometheus.metrics.exporter.servlet.javax.PrometheusMetricsServlet</servlet-class>
|
||||||
|
<load-on-startup>1</load-on-startup>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
|
<!-- precompiled servlets -->
|
||||||
|
|
||||||
|
<!--
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/index.jsp</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/index.html</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/status</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/status.html</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusServlet</servlet-name>
|
||||||
|
<url-pattern>/status.jsp</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusMetricsServlet</servlet-name>
|
||||||
|
<url-pattern>/metrics</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>PrometheusMetricsServlet</servlet-name>
|
||||||
|
<url-pattern>/metrics/</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
|
</web-app>
|