You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. * Copyright (c) 2006-2013 DMDirc Developers
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.addons.lagdisplay;
  23. import com.dmdirc.FrameContainer;
  24. import com.dmdirc.Server;
  25. import com.dmdirc.ServerState;
  26. import com.dmdirc.actions.ActionManager;
  27. import com.dmdirc.actions.CoreActionType;
  28. import com.dmdirc.interfaces.actions.ActionType;
  29. import com.dmdirc.addons.ui_swing.SelectionListener;
  30. import com.dmdirc.addons.ui_swing.SwingController;
  31. import com.dmdirc.addons.ui_swing.components.frames.TextFrame;
  32. import com.dmdirc.config.ConfigManager;
  33. import com.dmdirc.config.prefs.PluginPreferencesCategory;
  34. import com.dmdirc.config.prefs.PreferencesCategory;
  35. import com.dmdirc.config.prefs.PreferencesDialogModel;
  36. import com.dmdirc.config.prefs.PreferencesSetting;
  37. import com.dmdirc.config.prefs.PreferencesType;
  38. import com.dmdirc.interfaces.ActionListener;
  39. import com.dmdirc.interfaces.ConfigChangeListener;
  40. import com.dmdirc.plugins.BasePlugin;
  41. import com.dmdirc.plugins.PluginInfo;
  42. import com.dmdirc.util.collections.RollingList;
  43. import java.util.Date;
  44. import java.util.HashMap;
  45. import java.util.Map;
  46. import java.util.WeakHashMap;
  47. /**
  48. * Displays the current server's lag in the status bar.
  49. */
  50. public final class LagDisplayPlugin extends BasePlugin implements
  51. ActionListener, ConfigChangeListener, SelectionListener {
  52. /** The panel we use in the status bar. */
  53. private final LagDisplayPanel panel;
  54. /** A cache of ping times. */
  55. private final Map<Server, String> pings = new WeakHashMap<Server, String>();
  56. /** Ping history. */
  57. private final Map<Server, RollingList<Long>> history
  58. = new HashMap<Server, RollingList<Long>>();
  59. /** Parent Swing UI. */
  60. private final SwingController controller;
  61. /** Whether or not to show a graph in the info popup. */
  62. private boolean showGraph = true;
  63. /** Whether or not to show labels on that graph. */
  64. private boolean showLabels = true;
  65. /** The length of history to keep per-server. */
  66. private int historySize = 100;
  67. /** This plugin's plugin info. */
  68. private final PluginInfo pluginInfo;
  69. /** Global config. */
  70. private ConfigManager config;
  71. /**
  72. * Creates a new LagDisplayPlugin.
  73. *
  74. * @param controller The controller to add components to
  75. * @param pluginInfo This plugin's plugin info
  76. */
  77. public LagDisplayPlugin(final SwingController controller,
  78. final PluginInfo pluginInfo) {
  79. super();
  80. this.controller = controller;
  81. this.pluginInfo = pluginInfo;
  82. config = controller.getGlobalConfig();
  83. panel = new LagDisplayPanel(this, controller);
  84. }
  85. /**
  86. * Get our PluginInfo.
  87. * @return Our PluginInfo.
  88. */
  89. public PluginInfo getPluginInfo() {
  90. return pluginInfo;
  91. }
  92. /** {@inheritDoc} */
  93. @Override
  94. public void onLoad() {
  95. controller.getSwingStatusBar().addComponent(panel);
  96. controller.getMainFrame().addSelectionListener(this);
  97. config.addChangeListener(getDomain(), this);
  98. readConfig();
  99. ActionManager.getActionManager().registerListener(this,
  100. CoreActionType.SERVER_GOTPING, CoreActionType.SERVER_NOPING,
  101. CoreActionType.SERVER_DISCONNECTED,
  102. CoreActionType.SERVER_PINGSENT, CoreActionType.SERVER_NUMERIC);
  103. }
  104. /** {@inheritDoc} */
  105. @Override
  106. public void onUnload() {
  107. controller.getMainFrame().removeSelectionListener(this);
  108. controller.getSwingStatusBar().removeComponent(panel);
  109. config.removeListener(this);
  110. ActionManager.getActionManager().unregisterListener(this);
  111. }
  112. /** Reads the plugin's global configuration settings. */
  113. private void readConfig() {
  114. showGraph = config.getOptionBool(getDomain(), "graph");
  115. showLabels = config.getOptionBool(getDomain(), "labels");
  116. historySize = config.getOptionInt(getDomain(), "history");
  117. }
  118. /**
  119. * Retrieves the history of the specified server. If there is no history,
  120. * a new list is added to the history map and returned.
  121. *
  122. * @param server The server whose history is being requested
  123. * @return The history for the specified server
  124. */
  125. protected RollingList<Long> getHistory(final Server server) {
  126. if (!history.containsKey(server)) {
  127. history.put(server, new RollingList<Long>(historySize));
  128. }
  129. return history.get(server);
  130. }
  131. /**
  132. * Determines if the {@link ServerInfoDialog} should show a graph of the
  133. * ping time for the current server.
  134. *
  135. * @return True if a graph should be shown, false otherwise
  136. */
  137. public boolean shouldShowGraph() {
  138. return showGraph;
  139. }
  140. /**
  141. * Determines if the {@link PingHistoryPanel} should show labels on
  142. * selected points.
  143. *
  144. * @return True if labels should be shown, false otherwise
  145. */
  146. public boolean shouldShowLabels() {
  147. return showLabels;
  148. }
  149. /** {@inheritDoc} */
  150. @Override
  151. public void selectionChanged(final TextFrame window) {
  152. final FrameContainer source = window.getContainer();
  153. if (source == null || source.getServer() == null) {
  154. panel.getComponent().setText("Unknown");
  155. } else if (source.getServer().getState() != ServerState.CONNECTED) {
  156. panel.getComponent().setText("Not connected");
  157. } else {
  158. panel.getComponent().setText(getTime(source.getServer()));
  159. }
  160. panel.refreshDialog();
  161. }
  162. /** {@inheritDoc} */
  163. @Override
  164. public void processEvent(final ActionType type, final StringBuffer format,
  165. final Object... arguments) {
  166. boolean useAlternate = false;
  167. for (Object obj : arguments) {
  168. if (obj instanceof FrameContainer
  169. && ((FrameContainer) obj).getConfigManager() != null) {
  170. useAlternate = ((FrameContainer) obj).getConfigManager()
  171. .getOptionBool(getDomain(), "usealternate");
  172. break;
  173. }
  174. }
  175. final TextFrame activeFrame = controller.getMainFrame().getActiveFrame();
  176. final FrameContainer active = activeFrame == null ? null
  177. : activeFrame.getContainer();
  178. if (!useAlternate && type.equals(CoreActionType.SERVER_GOTPING)) {
  179. final String value = formatTime(arguments[1]);
  180. getHistory(((Server) arguments[0])).add((Long) arguments[1]);
  181. pings.put(((Server) arguments[0]), value);
  182. if (((Server) arguments[0]).isChild(active) || arguments[0] == active) {
  183. panel.getComponent().setText(value);
  184. }
  185. panel.refreshDialog();
  186. } else if (!useAlternate && type.equals(CoreActionType.SERVER_NOPING)) {
  187. final String value = formatTime(arguments[1]) + "+";
  188. pings.put(((Server) arguments[0]), value);
  189. if (((Server) arguments[0]).isChild(active) || arguments[0] == active) {
  190. panel.getComponent().setText(value);
  191. }
  192. panel.refreshDialog();
  193. } else if (type.equals(CoreActionType.SERVER_DISCONNECTED)) {
  194. if (((Server) arguments[0]).isChild(active) || arguments[0] == active) {
  195. panel.getComponent().setText("Not connected");
  196. pings.remove(arguments[0]);
  197. }
  198. panel.refreshDialog();
  199. } else if (useAlternate && type.equals(CoreActionType.SERVER_PINGSENT)) {
  200. ((Server) arguments[0]).getParser().sendRawMessage("LAGCHECK_" + new Date().getTime());
  201. } else if (useAlternate && type.equals(CoreActionType.SERVER_NUMERIC)
  202. && ((Integer) arguments[1]).intValue() == 421
  203. && ((String[]) arguments[2])[3].startsWith("LAGCHECK_")) {
  204. try {
  205. final long sent = Long.parseLong(((String[]) arguments[2])[3].substring(9));
  206. final Long duration = Long.valueOf(new Date().getTime() - sent);
  207. final String value = formatTime(duration);
  208. pings.put((Server) arguments[0], value);
  209. getHistory(((Server) arguments[0])).add(duration);
  210. if (((Server) arguments[0]).isChild(active) || arguments[0] == active) {
  211. panel.getComponent().setText(value);
  212. }
  213. } catch (NumberFormatException ex) {
  214. pings.remove(arguments[0]);
  215. }
  216. if (format != null) {
  217. format.delete(0, format.length());
  218. }
  219. panel.refreshDialog();
  220. }
  221. }
  222. /**
  223. * Retrieves the ping time for the specified server.
  224. *
  225. * @param server The server whose ping time is being requested
  226. * @return A String representation of the current lag, or "Unknown"
  227. */
  228. public String getTime(final Server server) {
  229. return pings.get(server) == null ? "Unknown" : pings.get(server);
  230. }
  231. /**
  232. * Formats the specified time so it's a nice size to display in the label.
  233. * @param object An uncast Long representing the time to be formatted
  234. * @return Formatted time string
  235. */
  236. protected String formatTime(final Object object) {
  237. final Long time = (Long) object;
  238. if (time >= 10000) {
  239. return Math.round(time / 1000.0) + "s";
  240. } else {
  241. return time + "ms";
  242. }
  243. }
  244. /** {@inheritDoc} */
  245. @Override
  246. public void showConfig(final PreferencesDialogModel manager) {
  247. final PreferencesCategory cat = new PluginPreferencesCategory(
  248. pluginInfo, "Lag display plugin", "");
  249. cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  250. getDomain(), "usealternate",
  251. "Alternate method", "Use an alternate method of determining "
  252. + "lag which bypasses bouncers or proxies that may reply?",
  253. manager.getConfigManager(), manager.getIdentity()));
  254. cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  255. getDomain(), "graph", "Show graph", "Show a graph of ping times " +
  256. "for the current server in the information popup?",
  257. manager.getConfigManager(), manager.getIdentity()));
  258. cat.addSetting(new PreferencesSetting(PreferencesType.BOOLEAN,
  259. getDomain(), "labels", "Show labels", "Show labels on selected " +
  260. "points on the ping graph?",
  261. manager.getConfigManager(), manager.getIdentity()));
  262. cat.addSetting(new PreferencesSetting(PreferencesType.INTEGER,
  263. getDomain(), "history", "Graph points", "Number of data points " +
  264. "to plot on the graph, if enabled.",
  265. manager.getConfigManager(), manager.getIdentity()));
  266. manager.getCategory("Plugins").addSubCategory(cat);
  267. }
  268. /** {@inheritDoc} */
  269. @Override
  270. public void configChanged(final String domain, final String key) {
  271. readConfig();
  272. }
  273. }