/* * Copyright (c) 2006-2011 Chris Smith, Shane Mc Cormack, Gregory Holmes * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.dmdirc.addons.lagdisplay; import com.dmdirc.FrameContainer; import com.dmdirc.Server; import com.dmdirc.ServerState; import com.dmdirc.actions.ActionManager; import com.dmdirc.actions.CoreActionType; import com.dmdirc.actions.interfaces.ActionType; import com.dmdirc.addons.ui_swing.SwingController; import com.dmdirc.config.ConfigManager; import com.dmdirc.config.IdentityManager; import com.dmdirc.config.prefs.PluginPreferencesCategory; import com.dmdirc.config.prefs.PreferencesCategory; import com.dmdirc.config.prefs.PreferencesDialogModel; import com.dmdirc.config.prefs.PreferencesSetting; import com.dmdirc.config.prefs.PreferencesType; import com.dmdirc.interfaces.ActionListener; import com.dmdirc.interfaces.ConfigChangeListener; import com.dmdirc.plugins.Plugin; import com.dmdirc.plugins.PluginManager; import com.dmdirc.ui.WindowManager; import com.dmdirc.util.RollingList; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; /** * Displays the current server's lag in the status bar. * @author chris */ public final class LagDisplayPlugin extends Plugin implements ActionListener, ConfigChangeListener { /** The panel we use in the status bar. */ private final LagDisplayPanel panel = new LagDisplayPanel(this); /** A cache of ping times. */ private final Map pings = new WeakHashMap(); /** Ping history. */ private final Map> history = new HashMap>(); /** Whether or not to show a graph in the info popup. */ private boolean showGraph = true; /** Whether or not to show labels on that graph. */ private boolean showLabels = true; /** The length of history to keep per-server. */ private int historySize = 100; /** Creates a new instance of LagDisplayPlugin. */ public LagDisplayPlugin() { super(); } /** {@inheritDoc} */ @Override public void onLoad() { ((SwingController) PluginManager.getPluginManager() .getPluginInfoByName("ui_swing").getPlugin()) .getSwingStatusBar().addComponent(panel); IdentityManager.getGlobalConfig().addChangeListener(getDomain(), this); readConfig(); ActionManager.addListener(this, CoreActionType.SERVER_GOTPING, CoreActionType.SERVER_NOPING, CoreActionType.CLIENT_FRAME_CHANGED, CoreActionType.SERVER_DISCONNECTED, CoreActionType.SERVER_PINGSENT, CoreActionType.SERVER_NUMERIC); } /** * Reads the plugin's global configuration settings. */ protected void readConfig() { final ConfigManager manager = IdentityManager.getGlobalConfig(); showGraph = manager.getOptionBool(getDomain(), "graph"); showLabels = manager.getOptionBool(getDomain(), "labels"); historySize = manager.getOptionInt(getDomain(), "history"); } /** * Retrieves the history of the specified server. If there is no history, * a new list is added to the history map and returned. * * @param server The server whose history is being requested * @return The history for the specified server */ protected RollingList getHistory(final Server server) { if (!history.containsKey(server)) { history.put(server, new RollingList(historySize)); } return history.get(server); } /** * Determines if the {@link ServerInfoDialog} should show a graph of the * ping time for the current server. * * @return True if a graph should be shown, false otherwise */ public boolean shouldShowGraph() { return showGraph; } /** * Determines if the {@link PingHistoryPanel} should show labels on selected * points. * * @return True if labels should be shown, false otherwise */ public boolean shouldShowLabels() { return showLabels; } /** {@inheritDoc} */ @Override public void onUnload() { ((SwingController) PluginManager.getPluginManager() .getPluginInfoByName("ui_swing").getPlugin()) .getSwingStatusBar().removeComponent(panel); IdentityManager.getConfigIdentity().removeListener(this); ActionManager.removeListener(this); } /** {@inheritDoc} */ @Override public void processEvent(final ActionType type, final StringBuffer format, final Object... arguments) { boolean useAlternate = false; for (Object obj : arguments) { if (obj instanceof FrameContainer && ((FrameContainer) obj).getConfigManager() != null) { useAlternate = ((FrameContainer) obj).getConfigManager() .getOptionBool(getDomain(), "usealternate"); break; } } if (!useAlternate && type.equals(CoreActionType.SERVER_GOTPING)) { final FrameContainer active = WindowManager.getActiveWindow(); final String value = formatTime(arguments[1]); getHistory(((Server) arguments[0])).add((Long) arguments[1]); pings.put(((Server) arguments[0]), value); if (((Server) arguments[0]).isChild(active) || arguments[0] == active) { panel.setText(value); } panel.refreshDialog(); } else if (!useAlternate && type.equals(CoreActionType.SERVER_NOPING)) { final FrameContainer active = WindowManager.getActiveWindow(); final String value = formatTime(arguments[1]) + "+"; pings.put(((Server) arguments[0]), value); if (((Server) arguments[0]).isChild(active) || arguments[0] == active) { panel.setText(value); } panel.refreshDialog(); } else if (type.equals(CoreActionType.SERVER_DISCONNECTED)) { final FrameContainer active = WindowManager.getActiveWindow(); if (((Server) arguments[0]).isChild(active) || arguments[0] == active) { panel.setText("Not connected"); pings.remove((Server) arguments[0]); } panel.refreshDialog(); } else if (type.equals(CoreActionType.CLIENT_FRAME_CHANGED)) { final FrameContainer source = (FrameContainer) arguments[0]; if (source == null || source.getServer() == null) { panel.setText("Unknown"); } else if (source.getServer().getState() != ServerState.CONNECTED) { panel.setText("Not connected"); } else { panel.setText(getTime(source.getServer())); } panel.refreshDialog(); } else if (useAlternate && type.equals(CoreActionType.SERVER_PINGSENT)) { ((Server) arguments[0]).getParser().sendRawMessage("LAGCHECK_" + new Date().getTime()); } else if (useAlternate && type.equals(CoreActionType.SERVER_NUMERIC) && ((Integer) arguments[1]).intValue() == 421 && ((String[]) arguments[2])[3].startsWith("LAGCHECK_")) { try { final long sent = Long.parseLong(((String[]) arguments[2])[3].substring(9)); final Long duration = Long.valueOf(new Date().getTime() - sent); final String value = formatTime(duration); final FrameContainer active = WindowManager.getActiveWindow(); pings.put((Server) arguments[0], value); getHistory(((Server) arguments[0])).add(duration); if (((Server) arguments[0]).isChild(active) || arguments[0] == active) { panel.setText(value); } } catch (NumberFormatException ex) { pings.remove((Server) arguments[0]); } if (format != null) { format.delete(0, format.length()); } panel.refreshDialog(); } } /** * Retrieves the ping time for the specified server. * * @param server The server whose ping time is being requested * @return A String representation of the current lag, or "Unknown" */ public String getTime(final Server server) { return pings.get(server) == null ? "Unknown" : pings.get(server); } /** * Formats the specified time so it's a nice size to display in the label. * @param object An uncast Long representing the time to be formatted * @return Formatted time string */ protected String formatTime(final Object object) { final Long time = (Long) object; if (time >= 10000) { return Math.round(time / 1000.0) + "s"; } else { return time + "ms"; } } /** {@inheritDoc} */ @Override public void showConfig(final PreferencesDialogModel manager) { final PreferencesCategory cat = new PluginPreferencesCategory( getPluginInfo(), "Lag display plugin", ""); cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN, getDomain(), "usealternate", "Alternate method", "Use an alternate method of determining " + "lag which bypasses bouncers or proxies that may reply?")); cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN, getDomain(), "graph", "Show graph", "Show a graph of ping times " + "for the current server in the information popup?")); cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN, getDomain(), "labels", "Show labels", "Show labels on selected " + "points on the ping graph?")); cat.addSetting(new PreferencesSetting(PreferencesType.INTEGER, getDomain(), "history", "Graph points", "Number of data points " + "to plot on the graph, if enabled.")); manager.getCategory("Plugins").addSubCategory(cat); } /** {@inheritDoc} */ @Override public void configChanged(final String domain, final String key) { readConfig(); } }