1 /++ 2 Implementation of Admin plugin functionality that borders on debugging. 3 For internal use. 4 5 The [dialect.defs.IRCEvent|IRCEvent]-annotated handlers must be in the same module 6 as the [kameloso.plugins.admin.base.AdminPlugin|AdminPlugin], but these implementation 7 functions can be offloaded here to limit module size a bit. 8 9 See_Also: 10 [kameloso.plugins.admin.base] 11 12 Copyright: [JR](https://github.com/zorael) 13 License: [Boost Software License 1.0](https://www.boost.org/users/license.html) 14 15 Authors: 16 [JR](https://github.com/zorael) 17 +/ 18 module kameloso.plugins.admin.debugging; 19 20 version(WithAdminPlugin): 21 debug: 22 23 private: 24 25 import kameloso.plugins.admin.base : AdminPlugin; 26 27 import kameloso.messaging; 28 import dialect.defs; 29 import std.stdio : stdout; 30 import std.typecons : Flag, No, Yes; 31 32 package: 33 34 35 // onAnyEventImpl 36 /++ 37 Prints incoming events to the local terminal, in forms depending on 38 which flags have been set with bot commands. 39 40 If [kameloso.plugins.admin.base.AdminPlugin.printRaw|AdminPlugin.printRaw] is set by way of 41 invoking [kameloso.plugins.admin.base.onCommandPrintRaw|onCommandPrintRaw], prints all incoming server strings. 42 43 If [kameloso.plugins.admin.base.AdminPlugin.printBytes|AdminPlugin.printBytes] is set by way of 44 invoking [kameloso.plugins.admin.base.onCommandPrintBytes|onCommandPrintBytes], prints all incoming server strings byte by byte. 45 +/ 46 void onAnyEventImpl(AdminPlugin plugin, const ref IRCEvent event) 47 { 48 import std.stdio : write, writefln, writeln; 49 50 if (plugin.state.settings.headless) return; 51 52 if (plugin.adminSettings.printRaw) 53 { 54 if (event.tags.length) write('@', event.tags, ' '); 55 writeln(event.raw, '$'); 56 } 57 58 if (plugin.adminSettings.printBytes) 59 { 60 import std.string : representation; 61 62 foreach (immutable i, immutable c; event.content.representation) 63 { 64 import std.encoding : isValidCodeUnit; 65 import std.utf : replacementDchar; 66 67 immutable dc = isValidCodeUnit(c) ? dchar(c) : replacementDchar; 68 writefln("[%3d] %s : %03d", i, dc, c); 69 } 70 } 71 72 if (plugin.state.settings.flush) stdout.flush(); 73 } 74 75 76 // onCommandShowUserImpl 77 /++ 78 Prints the details of one or more specific, supplied users to the local terminal. 79 80 It basically prints the matching [dialect.defs.IRCUser|IRCUser]. 81 +/ 82 version(IncludeHeavyStuff) 83 void onCommandShowUserImpl(AdminPlugin plugin, const ref IRCEvent event) 84 { 85 import kameloso.printing : printObject; 86 import std.algorithm.iteration : splitter; 87 88 if (plugin.state.settings.headless) return; 89 90 foreach (immutable username; event.content.splitter(' ')) 91 { 92 if (const user = username in plugin.state.users) 93 { 94 printObject(*user); 95 } 96 else 97 { 98 import std.format : format; 99 100 enum pattern = "No such user: <4>%s<c>"; 101 immutable message = pattern.format(username); 102 privmsg(plugin.state, event.channel, event.sender.nickname, message); 103 } 104 } 105 } 106 107 108 // onCommandShowUsersImpl 109 /++ 110 Prints out the current `users` array of the [kameloso.plugins.admin.base.AdminPlugin|AdminPlugin]'s 111 [kameloso.plugins.common.core.IRCPluginState|IRCPluginState] to the local terminal. 112 +/ 113 version(IncludeHeavyStuff) 114 void onCommandShowUsersImpl(AdminPlugin plugin) 115 { 116 import kameloso.printing : printObject; 117 import std.stdio : writeln; 118 119 if (plugin.state.settings.headless) return; 120 121 foreach (immutable name, const user; plugin.state.users) 122 { 123 writeln(name); 124 printObject(user); 125 } 126 127 writeln(plugin.state.users.length, " users."); 128 if (plugin.state.settings.flush) stdout.flush(); 129 } 130 131 132 // onCommandSudoImpl 133 /++ 134 Sends supplied text to the server, verbatim. 135 136 You need basic knowledge of IRC server strings to use this. 137 +/ 138 void onCommandSudoImpl(AdminPlugin plugin, const ref IRCEvent event) 139 { 140 raw(plugin.state, event.content); 141 } 142 143 144 // onCommandPrintRawImpl 145 /++ 146 Toggles a flag to print all incoming events *raw*. 147 148 This is for debugging purposes. 149 +/ 150 void onCommandPrintRawImpl(AdminPlugin plugin, const ref IRCEvent event) 151 { 152 import std.conv : text; 153 import std.format : format; 154 155 if (plugin.state.settings.headless) return; 156 157 plugin.adminSettings.printRaw = !plugin.adminSettings.printRaw; 158 159 enum pattern = "Printing all: <b>%s<b>"; 160 immutable message = pattern.format(plugin.adminSettings.printRaw); 161 privmsg(plugin.state, event.channel, event.sender.nickname, message); 162 } 163 164 165 // onCommandPrintBytesImpl 166 /++ 167 Toggles a flag to print all incoming events *as individual bytes*. 168 169 This is for debugging purposes. 170 +/ 171 void onCommandPrintBytesImpl(AdminPlugin plugin, const ref IRCEvent event) 172 { 173 import std.conv : text; 174 import std.format : format; 175 176 if (plugin.state.settings.headless) return; 177 178 plugin.adminSettings.printBytes = !plugin.adminSettings.printBytes; 179 180 enum pattern = "Printing bytes: <b>%s<b>"; 181 immutable message = pattern.format(plugin.adminSettings.printBytes); 182 privmsg(plugin.state, event.channel, event.sender.nickname, message); 183 } 184 185 186 // onCommandStatusImpl 187 /++ 188 Dumps information about the current state of the bot to the local terminal. 189 190 This can be very spammy. 191 +/ 192 version(IncludeHeavyStuff) 193 void onCommandStatusImpl(AdminPlugin plugin) 194 { 195 import kameloso.common : logger; 196 import kameloso.printing : printObjects; 197 import std.stdio : writeln; 198 199 if (plugin.state.settings.headless) return; 200 201 logger.log("Current state:"); 202 printObjects!(Yes.all)(plugin.state.client, plugin.state.server); 203 writeln(); 204 205 logger.log("Channels:"); 206 foreach (immutable channelName, const channel; plugin.state.channels) 207 { 208 writeln(channelName); 209 printObjects(channel); 210 } 211 //writeln(); 212 213 /*logger.log("Users:"); 214 foreach (immutable nickname, const user; plugin.state.users) 215 { 216 writeln(nickname); 217 printObject(user); 218 }*/ 219 220 if (plugin.state.settings.flush) stdout.flush(); 221 } 222 223 224 // onCommandBusImpl 225 /++ 226 Sends an internal bus message to other plugins, much like how such can be 227 sent with the Pipeline plugin. 228 +/ 229 void onCommandBusImpl(AdminPlugin plugin, const string input) 230 { 231 import kameloso.common : logger; 232 import kameloso.thread : ThreadMessage, boxed; 233 import lu.string : contains, nom; 234 import std.concurrency : send; 235 import std.stdio : writeln; 236 237 if (!input.length) return; 238 239 if (!input.contains!(Yes.decode)(' ')) 240 { 241 if (!plugin.state.settings.headless) 242 { 243 logger.info("Sending bus message."); 244 writeln("Header: ", input); 245 writeln("Content: (empty)"); 246 } 247 248 plugin.state.mainThread.send(ThreadMessage.busMessage(input)); 249 } 250 else 251 { 252 string slice = input; // mutable 253 immutable header = slice.nom(' '); 254 255 if (!plugin.state.settings.headless) 256 { 257 logger.info("Sending bus message."); 258 writeln("Header: ", header); 259 writeln("Content: ", slice); 260 } 261 262 plugin.state.mainThread.send(ThreadMessage.busMessage(header, boxed(slice))); 263 } 264 265 if (!plugin.state.settings.headless && plugin.state.settings.flush) 266 { 267 stdout.flush(); 268 } 269 }