PluginManager: require start/stop to be invoked on the EDT
The current way of invoking it on the executor would let the client have a start and a stop for a plugin sitting in the executor's queue, making it toggle endlessly. This only was because we were using invokeAndWait in startPlugin, which can't be invoked on the EDT because it would deadlock with itself.
This commit is contained in:
@@ -33,6 +33,7 @@ import com.google.common.hash.HashingInputStream;
|
|||||||
import com.google.common.io.Files;
|
import com.google.common.io.Files;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -44,6 +45,7 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import net.runelite.client.RuneLite;
|
import net.runelite.client.RuneLite;
|
||||||
import net.runelite.client.RuneLiteProperties;
|
import net.runelite.client.RuneLiteProperties;
|
||||||
@@ -240,11 +242,21 @@ public class ExternalPluginManager
|
|||||||
for (Plugin p : remove)
|
for (Plugin p : remove)
|
||||||
{
|
{
|
||||||
log.info("Stopping external plugin \"{}\"", p.getClass());
|
log.info("Stopping external plugin \"{}\"", p.getClass());
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeAndWait(() ->
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pluginManager.stopPlugin(p);
|
pluginManager.stopPlugin(p);
|
||||||
}
|
}
|
||||||
catch (PluginInstantiationException e)
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (InterruptedException | InvocationTargetException e)
|
||||||
{
|
{
|
||||||
log.warn("Unable to stop external plugin \"{}\"", p.getClass().getName(), e);
|
log.warn("Unable to stop external plugin \"{}\"", p.getClass().getName(), e);
|
||||||
}
|
}
|
||||||
@@ -272,16 +284,26 @@ public class ExternalPluginManager
|
|||||||
clazzes.add(cl.loadClass(className));
|
clazzes.add(cl.loadClass(className));
|
||||||
}
|
}
|
||||||
|
|
||||||
newPlugins = pluginManager.loadPlugins(clazzes, null);
|
List<Plugin> newPlugins2 = newPlugins = pluginManager.loadPlugins(clazzes, null);
|
||||||
if (!startup)
|
if (!startup)
|
||||||
{
|
{
|
||||||
pluginManager.loadDefaultPluginConfiguration(newPlugins);
|
pluginManager.loadDefaultPluginConfiguration(newPlugins);
|
||||||
|
|
||||||
for (Plugin p : newPlugins)
|
SwingUtilities.invokeAndWait(() ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (Plugin p : newPlugins2)
|
||||||
{
|
{
|
||||||
pluginManager.startPlugin(p);
|
pluginManager.startPlugin(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
catch (PluginInstantiationException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -289,13 +311,24 @@ public class ExternalPluginManager
|
|||||||
if (newPlugins != null)
|
if (newPlugins != null)
|
||||||
{
|
{
|
||||||
for (Plugin p : newPlugins)
|
for (Plugin p : newPlugins)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeAndWait(() ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pluginManager.stopPlugin(p);
|
pluginManager.stopPlugin(p);
|
||||||
}
|
}
|
||||||
catch (Exception inner)
|
catch (Exception e2)
|
||||||
{
|
{
|
||||||
|
throw new RuntimeException(e2);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (InterruptedException | InvocationTargetException e2)
|
||||||
|
{
|
||||||
|
log.info("Unable to fully stop plugin \"{}\"", manifest.getInternalName(), e2);
|
||||||
}
|
}
|
||||||
pluginManager.remove(p);
|
pluginManager.remove(p);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -132,8 +132,9 @@ public class PluginManager
|
|||||||
private void refreshPlugins()
|
private void refreshPlugins()
|
||||||
{
|
{
|
||||||
loadDefaultPluginConfiguration(null);
|
loadDefaultPluginConfiguration(null);
|
||||||
getPlugins()
|
SwingUtilities.invokeLater(() ->
|
||||||
.forEach(plugin -> executor.submit(() ->
|
{
|
||||||
|
for (Plugin plugin : getPlugins())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -153,7 +154,8 @@ public class PluginManager
|
|||||||
{
|
{
|
||||||
log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), e);
|
log.warn("Error during starting/stopping plugin {}", plugin.getClass().getSimpleName(), e);
|
||||||
}
|
}
|
||||||
}));
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Config getPluginConfigProxy(Plugin plugin)
|
public Config getPluginConfigProxy(Plugin plugin)
|
||||||
@@ -212,6 +214,10 @@ public class PluginManager
|
|||||||
List<Plugin> scannedPlugins = new ArrayList<>(plugins);
|
List<Plugin> scannedPlugins = new ArrayList<>(plugins);
|
||||||
int loaded = 0;
|
int loaded = 0;
|
||||||
for (Plugin plugin : scannedPlugins)
|
for (Plugin plugin : scannedPlugins)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
SwingUtilities.invokeAndWait(() ->
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -222,6 +228,12 @@ public class PluginManager
|
|||||||
log.warn("Unable to start plugin {}", plugin.getClass().getSimpleName(), ex);
|
log.warn("Unable to start plugin {}", plugin.getClass().getSimpleName(), ex);
|
||||||
plugins.remove(plugin);
|
plugins.remove(plugin);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (InterruptedException | InvocationTargetException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
|
||||||
loaded++;
|
loaded++;
|
||||||
SplashScreen.stage(.80, 1, null, "Starting plugins", loaded, scannedPlugins.size(), false);
|
SplashScreen.stage(.80, 1, null, "Starting plugins", loaded, scannedPlugins.size(), false);
|
||||||
@@ -325,8 +337,11 @@ public class PluginManager
|
|||||||
return newPlugins;
|
return newPlugins;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean startPlugin(Plugin plugin) throws PluginInstantiationException
|
public boolean startPlugin(Plugin plugin) throws PluginInstantiationException
|
||||||
{
|
{
|
||||||
|
// plugins always start in the EDT
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
|
||||||
if (activePlugins.contains(plugin) || !isPluginEnabled(plugin))
|
if (activePlugins.contains(plugin) || !isPluginEnabled(plugin))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -334,20 +349,9 @@ public class PluginManager
|
|||||||
|
|
||||||
activePlugins.add(plugin);
|
activePlugins.add(plugin);
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// plugins always start in the event thread
|
|
||||||
SwingUtilities.invokeAndWait(() ->
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.startUp();
|
plugin.startUp();
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.debug("Plugin {} is now running", plugin.getClass().getSimpleName());
|
log.debug("Plugin {} is now running", plugin.getClass().getSimpleName());
|
||||||
if (!isOutdated && sceneTileManager != null)
|
if (!isOutdated && sceneTileManager != null)
|
||||||
@@ -363,7 +367,7 @@ public class PluginManager
|
|||||||
schedule(plugin);
|
schedule(plugin);
|
||||||
eventBus.post(new PluginChanged(plugin, true));
|
eventBus.post(new PluginChanged(plugin, true));
|
||||||
}
|
}
|
||||||
catch (InterruptedException | InvocationTargetException | IllegalArgumentException ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new PluginInstantiationException(ex);
|
throw new PluginInstantiationException(ex);
|
||||||
}
|
}
|
||||||
@@ -371,36 +375,27 @@ public class PluginManager
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized boolean stopPlugin(Plugin plugin) throws PluginInstantiationException
|
public boolean stopPlugin(Plugin plugin) throws PluginInstantiationException
|
||||||
{
|
{
|
||||||
|
// plugins always stop in the EDT
|
||||||
|
assert SwingUtilities.isEventDispatchThread();
|
||||||
|
|
||||||
if (!activePlugins.remove(plugin))
|
if (!activePlugins.remove(plugin))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
unschedule(plugin);
|
unschedule(plugin);
|
||||||
eventBus.unregister(plugin);
|
eventBus.unregister(plugin);
|
||||||
|
|
||||||
// plugins always stop in the event thread
|
|
||||||
SwingUtilities.invokeAndWait(() ->
|
|
||||||
{
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
plugin.shutDown();
|
plugin.shutDown();
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
log.debug("Plugin {} is now stopped", plugin.getClass().getSimpleName());
|
log.debug("Plugin {} is now stopped", plugin.getClass().getSimpleName());
|
||||||
eventBus.post(new PluginChanged(plugin, false));
|
eventBus.post(new PluginChanged(plugin, false));
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (InterruptedException | InvocationTargetException ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new PluginInstantiationException(ex);
|
throw new PluginInstantiationException(ex);
|
||||||
}
|
}
|
||||||
@@ -555,6 +550,7 @@ public class PluginManager
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Topologically sort a graph. Uses Kahn's algorithm.
|
* Topologically sort a graph. Uses Kahn's algorithm.
|
||||||
|
*
|
||||||
* @param graph
|
* @param graph
|
||||||
* @param <T>
|
* @param <T>
|
||||||
* @return
|
* @return
|
||||||
|
|||||||
@@ -310,8 +310,6 @@ class PluginListPanel extends PluginPanel
|
|||||||
}
|
}
|
||||||
|
|
||||||
void startPlugin(Plugin plugin)
|
void startPlugin(Plugin plugin)
|
||||||
{
|
|
||||||
executorService.submit(() ->
|
|
||||||
{
|
{
|
||||||
pluginManager.setPluginEnabled(plugin, true);
|
pluginManager.setPluginEnabled(plugin, true);
|
||||||
|
|
||||||
@@ -323,12 +321,9 @@ class PluginListPanel extends PluginPanel
|
|||||||
{
|
{
|
||||||
log.warn("Error when starting plugin {}", plugin.getClass().getSimpleName(), ex);
|
log.warn("Error when starting plugin {}", plugin.getClass().getSimpleName(), ex);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void stopPlugin(Plugin plugin)
|
void stopPlugin(Plugin plugin)
|
||||||
{
|
|
||||||
executorService.submit(() ->
|
|
||||||
{
|
{
|
||||||
pluginManager.setPluginEnabled(plugin, false);
|
pluginManager.setPluginEnabled(plugin, false);
|
||||||
|
|
||||||
@@ -340,7 +335,6 @@ class PluginListPanel extends PluginPanel
|
|||||||
{
|
{
|
||||||
log.warn("Error when stopping plugin {}", plugin.getClass().getSimpleName(), ex);
|
log.warn("Error when stopping plugin {}", plugin.getClass().getSimpleName(), ex);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<String> getPinnedPluginNames()
|
private List<String> getPinnedPluginNames()
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import java.nio.FloatBuffer;
|
|||||||
import java.nio.IntBuffer;
|
import java.nio.IntBuffer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import jogamp.nativewindow.SurfaceScaleUtils;
|
import jogamp.nativewindow.SurfaceScaleUtils;
|
||||||
import jogamp.nativewindow.jawt.x11.X11JAWTWindow;
|
import jogamp.nativewindow.jawt.x11.X11JAWTWindow;
|
||||||
import jogamp.newt.awt.NewtFactoryAWT;
|
import jogamp.newt.awt.NewtFactoryAWT;
|
||||||
@@ -334,6 +335,8 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
{
|
{
|
||||||
log.error("Error starting GPU plugin", e);
|
log.error("Error starting GPU plugin", e);
|
||||||
|
|
||||||
|
SwingUtilities.invokeLater(() ->
|
||||||
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pluginManager.setPluginEnabled(this, false);
|
pluginManager.setPluginEnabled(this, false);
|
||||||
@@ -343,6 +346,7 @@ public class GpuPlugin extends Plugin implements DrawCallbacks
|
|||||||
{
|
{
|
||||||
log.error("error stopping plugin", ex);
|
log.error("error stopping plugin", ex);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
shutDown();
|
shutDown();
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user