From f308ebee74b6b2183169f35b38f6903f9dfd2aa6 Mon Sep 17 00:00:00 2001 From: idk Date: Thu, 25 May 2023 03:39:18 +0000 Subject: [PATCH 1/3] bump rc --- router/java/src/net/i2p/router/RouterVersion.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/router/java/src/net/i2p/router/RouterVersion.java b/router/java/src/net/i2p/router/RouterVersion.java index ed7e15522a..e59e596518 100644 --- a/router/java/src/net/i2p/router/RouterVersion.java +++ b/router/java/src/net/i2p/router/RouterVersion.java @@ -18,10 +18,10 @@ public class RouterVersion { /** deprecated */ public final static String ID = "Git"; public final static String VERSION = CoreVersion.VERSION; - public final static long BUILD = 0; + public final static long BUILD = 1; /** for example "-test" */ - public final static String EXTRA = ""; + public final static String EXTRA = "rc"; public final static String FULL_VERSION = VERSION + "-" + BUILD + EXTRA; public static void main(String args[]) { System.out.println("I2P Router version: " + FULL_VERSION); From 43b4364918eca15f38626fc25b61b602d25d22e5 Mon Sep 17 00:00:00 2001 From: idk Date: Wed, 31 May 2023 14:34:18 +0000 Subject: [PATCH 2/3] start implementing congestion caps handling by adding... --- .../i2p/router/peermanager/CapacityCalculator.java | 13 ++++++++++--- .../i2p/router/tunnel/pool/TunnelPeerSelector.java | 2 +- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java b/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java index f4de528c43..d8bf6843c2 100644 --- a/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java +++ b/router/java/src/net/i2p/router/peermanager/CapacityCalculator.java @@ -34,6 +34,11 @@ class CapacityCalculator { private static final double PENALTY_NO_R_CAP = 1; private static final double PENALTY_U_CAP = 2; private static final double PENALTY_LAST_SEND_FAIL = 4; + // congestion cap penalty not yet applied + //private static final double PENALTY_D_CAP = 0; + // congestion cap penalty not yet applied + //private static final double PENALTY_E_CAP = 0; + //private static final double PENALTY_G_CAP = 0; private static final double PENALTY_RECENT_SEND_FAIL = 4; private static final double BONUS_LAST_SEND_SUCCESS = 1; private static final double BONUS_RECENT_SEND_SUCCESS = 1; @@ -124,11 +129,13 @@ public static double calc(PeerProfile profile) { capacity -= PENALTY_U_CAP; if (caps.indexOf(Router.CAPABILITY_BW32) >= 0) capacity -= PENALTY_L_CAP; -/* TODO - if (caps.indexOf(Router.CAPABILITY_CONGESTION_MODERATE) >= 0) +/* TODO */ + /*if (caps.indexOf(Router.CAPABILITY_CONGESTION_MODERATE) >= 0) capacity -= PENALTY_D_CAP; else if (caps.indexOf(Router.CAPABILITY_CONGESTION_SEVERE) >= 0) - capacity -= PENALTY_E_CAP; + capacity -= PENALTY_E_CAP;*/ +/* TODO: G caps can be excluded in TunnelPeerSelector by adding it to DEFAULT_EXCLUDE_CAPS + decide what other handling if any is needed here. else if (caps.indexOf(Router.CAPABILITY_NO_TUNNELS) >= 0) capacity -= PENALTY_G_CAP; */ diff --git a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java index 1518d17b9f..773de2b778 100644 --- a/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java +++ b/router/java/src/net/i2p/router/tunnel/pool/TunnelPeerSelector.java @@ -42,7 +42,7 @@ */ public abstract class TunnelPeerSelector extends ConnectChecker { - private static final String DEFAULT_EXCLUDE_CAPS = String.valueOf(Router.CAPABILITY_BW12); + private static final String DEFAULT_EXCLUDE_CAPS = String.valueOf(Router.CAPABILITY_BW12)+String.valueOf(Router.CAPABILITY_CONGESTION_SEVERE); protected TunnelPeerSelector(RouterContext context) { super(context); From 785fc52a144a12cd93c8476bdbd3369573f1945f Mon Sep 17 00:00:00 2001 From: idk Date: Wed, 31 May 2023 14:39:53 +0000 Subject: [PATCH 3/3] Adds a Menu API to the DTG --- .../src/net/i2p/desktopgui/ExternalMain.java | 89 ++++++++- .../src/net/i2p/desktopgui/Main.java | 88 ++++++++- .../src/net/i2p/desktopgui/TrayManager.java | 171 +++++++++++++++++- .../klomp/snark/standalone/RunStandalone.java | 15 ++ core/java/src/net/i2p/app/MenuCallback.java | 16 ++ core/java/src/net/i2p/app/MenuHandle.java | 15 ++ core/java/src/net/i2p/app/MenuService.java | 55 ++++++ 7 files changed, 445 insertions(+), 4 deletions(-) create mode 100644 core/java/src/net/i2p/app/MenuCallback.java create mode 100644 core/java/src/net/i2p/app/MenuHandle.java create mode 100644 core/java/src/net/i2p/app/MenuService.java diff --git a/apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java b/apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java index 7d44c50103..e70cbf502e 100644 --- a/apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java +++ b/apps/desktopgui/src/net/i2p/desktopgui/ExternalMain.java @@ -13,6 +13,9 @@ import net.i2p.app.ClientAppManager; import net.i2p.app.ClientApp; import net.i2p.app.ClientAppState; +import net.i2p.app.MenuCallback; +import net.i2p.app.MenuHandle; +import net.i2p.app.MenuService; import net.i2p.app.NotificationService; import net.i2p.util.Log; import net.i2p.util.SystemVersion; @@ -24,7 +27,7 @@ * * @since 0.9.54 */ -public class ExternalMain implements ClientApp, NotificationService { +public class ExternalMain implements ClientApp, NotificationService, MenuService { private final I2PAppContext _appContext; private final ClientAppManager _mgr; @@ -60,7 +63,6 @@ public static void main(String[] args) { * @throws AWTException on startup error, including systray not supported */ private synchronized void startUp() throws Exception { - final TrayManager trayManager; boolean useSwingDefault = !(SystemVersion.isWindows() || SystemVersion.isMac()); boolean useSwing = _appContext.getProperty(PROP_SWING, useSwingDefault); _trayManager = new ExternalTrayManager(_appContext, useSwing); @@ -200,6 +202,89 @@ public boolean update(int id, String title, String message, String path) { return false; } + /////// MenuService methods + + /** + * Menu will start out shown and enabled, in the root menu + * + * @param message for the menu, translated + * @param callback fired on click + * @return null on error + * @since 0.9.59 + */ + public MenuHandle addMenu(String message, MenuCallback callback) { + return addMenu(message, callback, null); + } + + /** + * Menu will start out enabled, as a submenu + * + * @param message for the menu, translated + * @param callback fired on click + * @param parent the parent menu this will be a submenu of, or null for top level + * @return null on error + * @since 0.9.59 + */ + public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) { + if (_trayManager == null) + return null; + return _trayManager.addMenu(message, callback, parent); + } + + /** + * @since 0.9.59 + */ + public void removeMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.removeMenu(item); + } + + /** + * @since 0.9.59 + */ + public void showMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.showMenu(item); + } + + /** + * @since 0.9.59 + */ + public void hideMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.hideMenu(item); + } + + /** + * @since 0.9.59 + */ + public void enableMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.enableMenu(item); + } + + /** + * @since 0.9.59 + */ + public void disableMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.disableMenu(item); + } + + /** + * @since 0.9.59 + */ + public void updateMenu(String message, MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.updateMenu(message, item); + } + /////// ClientApp methods public synchronized void startup() { diff --git a/apps/desktopgui/src/net/i2p/desktopgui/Main.java b/apps/desktopgui/src/net/i2p/desktopgui/Main.java index 0a7e3f9bc2..921efaa055 100644 --- a/apps/desktopgui/src/net/i2p/desktopgui/Main.java +++ b/apps/desktopgui/src/net/i2p/desktopgui/Main.java @@ -17,6 +17,9 @@ import net.i2p.app.ClientAppManager; import net.i2p.app.ClientAppState; import static net.i2p.app.ClientAppState.*; +import net.i2p.app.MenuCallback; +import net.i2p.app.MenuHandle; +import net.i2p.app.MenuService; import net.i2p.app.NotificationService; import net.i2p.desktopgui.router.RouterManager; import net.i2p.router.RouterContext; @@ -29,7 +32,7 @@ /** * The main class of the application. */ -public class Main implements RouterApp, NotificationService { +public class Main implements RouterApp, NotificationService, MenuService { // non-null private final I2PAppContext _appContext; @@ -245,6 +248,89 @@ public boolean update(int id, String title, String message, String path) { return false; } + /////// MenuService methods + + /** + * Menu will start out shown and enabled, in the root menu + * + * @param message for the menu, translated + * @param callback fired on click + * @return null on error + * @since 0.9.59 + */ + public MenuHandle addMenu(String message, MenuCallback callback) { + return addMenu(message, callback, null); + } + + /** + * Menu will start out enabled, as a submenu + * + * @param message for the menu, translated + * @param callback fired on click + * @param parent the parent menu this will be a submenu of, or null for top level + * @return null on error + * @since 0.9.59 + */ + public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent) { + if (_trayManager == null) + return null; + return _trayManager.addMenu(message, callback, parent); + } + + /** + * @since 0.9.59 + */ + public void removeMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.removeMenu(item); + } + + /** + * @since 0.9.59 + */ + public void showMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.showMenu(item); + } + + /** + * @since 0.9.59 + */ + public void hideMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.hideMenu(item); + } + + /** + * @since 0.9.59 + */ + public void enableMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.enableMenu(item); + } + + /** + * @since 0.9.59 + */ + public void disableMenu(MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.disableMenu(item); + } + + /** + * @since 0.9.59 + */ + public void updateMenu(String message, MenuHandle item) { + if (_trayManager == null) + return; + _trayManager.updateMenu(message, item); + } + /////// ClientApp methods /** @since 0.9.26 */ diff --git a/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java b/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java index 0261c107d3..a7390d7fb6 100644 --- a/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java +++ b/apps/desktopgui/src/net/i2p/desktopgui/TrayManager.java @@ -4,6 +4,7 @@ import java.awt.Dimension; import java.awt.Font; import java.awt.Image; +import java.awt.MenuItem; import java.awt.PopupMenu; import java.awt.SystemTray; import java.awt.Toolkit; @@ -16,8 +17,10 @@ import java.awt.event.MouseListener; import java.io.IOException; import java.net.URL; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; -import java.awt.MenuItem; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; @@ -28,6 +31,8 @@ import javax.swing.event.PopupMenuListener; import net.i2p.I2PAppContext; +import net.i2p.app.MenuCallback; +import net.i2p.app.MenuHandle; import net.i2p.apps.systray.UrlLauncher; import net.i2p.desktopgui.i18n.DesktopguiTranslator; import net.i2p.util.Log; @@ -47,6 +52,9 @@ abstract class TrayManager { protected volatile boolean _showNotifications; protected MenuItem _notificationItem1, _notificationItem2; protected JMenuItem _jnotificationItem1, _jnotificationItem2; + private final AtomicInteger _id = new AtomicInteger(); + private final List _menus; + private JPopupMenu _jPopupMenu; private static final String PNG_DIR = "/desktopgui/resources/images/"; private static final String MAC_ICON = "itoopie_black_24.png"; @@ -61,6 +69,7 @@ abstract class TrayManager { protected TrayManager(I2PAppContext ctx, boolean useSwing) { _appContext = ctx; _useSwing = useSwing; + _menus = new ArrayList(); } /** @@ -109,6 +118,7 @@ private TrayIcon getSwingTrayIcon(String tooltip) throws AWTException { frame.setMinimumSize(new Dimension(0, 0)); frame.setSize(0, 0); final JPopupMenu menu = getSwingMainMenu(); + _jPopupMenu = menu; menu.setFocusable(true); frame.add(menu); TrayIcon ti = new TrayIcon(getTrayImage(), tooltip, null); @@ -375,6 +385,165 @@ protected Object doInBackground() throws Exception { _jnotificationItem1 = notificationItem1; } + /////// MenuService delegation methods + + /** + * @since 0.9.59 + */ + public MenuHandle addMenu(String message, final MenuCallback callback, MenuHandle p) { + MenuInternal parent = p != null ? (MenuInternal) p : null; + final int id = _id.incrementAndGet(); + final MenuInternal rv; + if (_useSwing) { + final JMenuItem m = new JMenuItem(message); + rv = new MenuInternal(null, m, callback, id); + m.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + rv.cb.clicked(rv); + return null; + } + }.execute(); + } + }); + _jPopupMenu.add(m); + } else { + final MenuItem m = new MenuItem(message); + rv = new MenuInternal(m, null, callback, id); + m.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent arg0) { + new SwingWorker() { + @Override + protected Object doInBackground() throws Exception { + rv.cb.clicked(rv); + return null; + } + }.execute(); + } + }); + trayIcon.getPopupMenu().add(m); + } + synchronized(_menus) { + _menus.add(rv); + } + updateMenu(); + return rv; + } + + /** + * @since 0.9.59 + */ + public void removeMenu(MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + if (_useSwing) { + _jPopupMenu.remove(mi.jm); + } else { + trayIcon.getPopupMenu().remove(mi.m); + } + updateMenu(); + } + + /** + * @since 0.9.59 + */ + public void showMenu(MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + mi.setVisible(true); + updateMenu(); + } + + /** + * @since 0.9.59 + */ + public void hideMenu(MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + mi.setVisible(false); + updateMenu(); + } + + /** + * @since 0.9.59 + */ + public void enableMenu(MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + mi.setEnabled(true); + updateMenu(); + } + + /** + * @since 0.9.59 + */ + public void disableMenu(MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + mi.setEnabled(false); + updateMenu(); + } + + /** + * @since 0.9.59 + */ + public void updateMenu(String message, MenuHandle item) { + MenuInternal mi = (MenuInternal) item; + mi.setText(message); + updateMenu(); + } + + /////// MenuService internals + + /** + * @since 0.9.59 + */ + private MenuInternal getMenu(int id) { + synchronized(_menus) { + for (MenuInternal mi : _menus) { + if (mi.getID() == id) + return mi; + } + } + return null; + } + + /** + * @since 0.9.59 + */ + private static class MenuInternal implements MenuHandle { + private final MenuItem m; + private final JMenuItem jm; + private final MenuCallback cb; + private final int id; + + public MenuInternal(MenuItem mm, JMenuItem jmm, MenuCallback cbb, int idd) { + m = mm; jm = jmm; cb = cbb; id = idd; + } + + public int getID() { return id; } + + private void setEnabled(boolean yes) { + if (m != null) + m.setEnabled(yes); + else + jm.setEnabled(yes); + } + + private void setVisible(boolean yes) { + if (m != null) + m.setEnabled(yes); + else + jm.setVisible(yes); + } + + private void setText(String text) { + if (m != null) + m.setLabel(text); + else + jm.setText(text); + } + } + protected String _t(String s) { return DesktopguiTranslator._t(_appContext, s); } diff --git a/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java b/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java index 4cce5e8fdd..1800816138 100644 --- a/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java +++ b/apps/i2psnark/java/src/org/klomp/snark/standalone/RunStandalone.java @@ -8,6 +8,8 @@ import org.eclipse.jetty.util.log.Log; import net.i2p.I2PAppContext; +import net.i2p.app.MenuCallback; +import net.i2p.app.MenuHandle; import net.i2p.apps.systray.UrlLauncher; import net.i2p.data.DataHelper; import net.i2p.desktopgui.ExternalMain; @@ -133,9 +135,22 @@ private void startTrayApp() { System.setProperty("java.awt.headless", "false"); ExternalMain dtg = new ExternalMain(_context, _context.clientAppManager(), null); dtg.startup(); + try { + Thread.sleep(1000); + } catch (InterruptedException ie) {} + Callback cb = new Callback(); + MenuHandle mh = dtg.addMenu("i2psnark is running", cb); + if (mh == null) + System.out.println("addMenu failed!"); } } catch (Throwable t) { t.printStackTrace(); } } + + private static class Callback implements MenuCallback { + public void clicked(MenuHandle handle) { + System.out.println("Clicked! " + handle.getID()); + } + } } diff --git a/core/java/src/net/i2p/app/MenuCallback.java b/core/java/src/net/i2p/app/MenuCallback.java new file mode 100644 index 0000000000..a88fcd455b --- /dev/null +++ b/core/java/src/net/i2p/app/MenuCallback.java @@ -0,0 +1,16 @@ +package net.i2p.app; + +/** + * The callback when a user clicks a MenuHandle. + * + * @since 0.9.59 + */ +public interface MenuCallback { + + /** + * Called when the user clicks the menu + * + * @param menu the menu handle clicked + */ + public void clicked(MenuHandle menu); +} diff --git a/core/java/src/net/i2p/app/MenuHandle.java b/core/java/src/net/i2p/app/MenuHandle.java new file mode 100644 index 0000000000..b4a93df212 --- /dev/null +++ b/core/java/src/net/i2p/app/MenuHandle.java @@ -0,0 +1,15 @@ +package net.i2p.app; + +/** + * An opaque handle for the menu, returned from MenuService.addMenuHandle() + * + * @since 0.9.59 + */ +public interface MenuHandle { + + /** + * @return a unique identifier for this MenuHandle + */ + public int getID(); + +} diff --git a/core/java/src/net/i2p/app/MenuService.java b/core/java/src/net/i2p/app/MenuService.java new file mode 100644 index 0000000000..02ccebe038 --- /dev/null +++ b/core/java/src/net/i2p/app/MenuService.java @@ -0,0 +1,55 @@ +package net.i2p.app; + +/** + * A service to provide a menu to users. + * This service is currently provided by desktopgui (when supported and enabled). + * Other applications may support this interface in the future. + * + * This API is independent of any particular UI framework, e.g. AWT or Swing. + * + * Example usage: + * + *
+ *     ClientAppManager cmgr = _context.clientAppManager();
+ *     if (cmgr != null) {
+ *         MenuService ms = (MenuService) cmgr.getRegisteredApp("desktopgui");
+ *         if (ms != null)
+ *             ms.addMenuHandle(_t("foo"), new Callback());
+ *     }
+ * 
+ * + * @since 0.9.59 + */ +public interface MenuService { + + /** + * Menu will start out shown and enabled, in the root menu + * + * @param message for the menu, translated + * @param callback fired on click + * @return null on error + */ + public MenuHandle addMenu(String message, MenuCallback callback); + + /** + * Menu will start out enabled, as a submenu + * + * @param message for the menu, translated + * @param callback fired on click + * @param parent the parent menu this will be a submenu of, or null for top level + * @return null on error + */ + public MenuHandle addMenu(String message, MenuCallback callback, MenuHandle parent); + + public void removeMenu(MenuHandle item); + + public void showMenu(MenuHandle item); + + public void hideMenu(MenuHandle item); + + public void enableMenu(MenuHandle item); + + public void disableMenu(MenuHandle item); + + public void updateMenu(String message, MenuHandle item); +}