1 | import net.dv8tion.jda.core.events.Event; |
2 | import net.dv8tion.jda.core.events.user.update.*; |
3 | |
4 | asclass DynTalkBot2<A extends DynTalkBot2.ByServer> extends DynServerAwareDiscordBot<A> { |
5 | switchable S myName = "Anonymous bot"; |
6 | transient bool useAGIBlueForDropPunctuation = true; |
7 | transient bool preprocessAtSelfToMyName = true; |
8 | transient bool dropPunctuation = true; |
9 | transient bool ngbCommands = true; |
10 | //transient bool perGuildAuth; // implementing |
11 | L<Long> authorizedUsers = ll(547706854680297473); // stefan |
12 | |
13 | srecord ISaid(long channelID, long date, S text) {} |
14 | |
15 | void init { |
16 | super.init(); |
17 | |
18 | onPostedInChannel.add((channel, msg) -> { |
19 | if (channel cast Channel) { |
20 | Guild guild = channel.getGuild(); |
21 | if (guild == null) ret; |
22 | ByServer bs = getByServer(guild); |
23 | long channelID = channel.getIdLong(); |
24 | mapPut(bs.lastSaidInChannel, channelID, nu ISaid(+channelID, text := msg)); |
25 | change(); |
26 | } |
27 | }); |
28 | |
29 | // We leave it as null to force subclasses to set this |
30 | // (avoids serializing bad instances) |
31 | // makeByServer = () -> (A) new ByServer; |
32 | |
33 | dm_vmBus_onMessage_q discordGuildJoin(voidfunc(Map map) { |
34 | ret unless map.get('module) == module(); |
35 | print("Got join"); |
36 | getByServer(getLong guildID(map), true) |
37 | .onUserJoin(getLong userID(map), map); |
38 | }); |
39 | |
40 | onDiscordEvent(e -> { |
41 | //print("Generic Discord event: " + e); |
42 | if (e cast UserUpdateOnlineStatusEvent) |
43 | getByServer(e.getGuild()).onOnlineStatusChange(e); |
44 | }); |
45 | } |
46 | |
47 | class ByServer extends DynServerAwareDiscordBot.ByServer { |
48 | L<Long> guildAuthorizedUsers; |
49 | Map<Long, ISaid> lastSaidInChannel = synchroMap(); |
50 | |
51 | DynTalkBot2 m2() { ret DynTalkBot2.this; } // for debugging |
52 | |
53 | // overridable |
54 | void onUserJoin(long userID, O... _) {} |
55 | void onOnlineStatusChange(UserUpdateOnlineStatusEvent e) {} |
56 | |
57 | @Override S answer(S input, Map map) { |
58 | try answer super.answer(input, map); // server-aware stuff |
59 | S answer = processLine(input, map); |
60 | ret answer; |
61 | } |
62 | |
63 | S dropMyPrefixOrNull(S s) { |
64 | S sOld = s; |
65 | s = dropPrefixICTrim_orNull(myPrefix(), s); |
66 | if (s == null) |
67 | print("no got prefix: " + quote(myPrefix()) + " / " + quote(sOld)); |
68 | ret s; |
69 | } |
70 | |
71 | S processLine(S s, O... _) { |
72 | s = preprocess(s, _); |
73 | ret processSimplifiedLine(s, _); |
74 | } |
75 | |
76 | S preprocess(S s, O... _) { |
77 | print("Preprocessing: " + s); |
78 | //pcall { print("mother: " + DynTalkBot2.this); } |
79 | if (preprocessAtSelfToMyName && discordBotID != 0) |
80 | s = replace(s, atSelf(), " " + myName + " "); |
81 | if (dropPunctuation) |
82 | s = dropPunctuation3_withAGIBlue(useAGIBlueForDropPunctuation, s); |
83 | s = trim(simpleSpaces_noTok(s)); |
84 | print("simplified >> " + quote(s)); |
85 | ret s; |
86 | } |
87 | |
88 | S myPrefix() { |
89 | ret preprocessAtSelfToMyName ? |
90 | (endsWithLetterOrDigit(myName) ? myName + " " : myName) : |
91 | (dropPunctuation ? replace(atSelf(), "@", "") /* @ is killed by preprocessing */ : atSelf()) + " "; |
92 | } |
93 | |
94 | // extend me |
95 | S processSimplifiedLine(S input, O... _) { |
96 | new Matches m; |
97 | |
98 | input = dropMyPrefixOrNull(input); |
99 | if (input == null) null; |
100 | |
101 | if (ngbCommands) { |
102 | if (eqicOneOf(input, "support channel", "support server", "support")) |
103 | ret "Get support for me here: " + nextGenBotsDiscordInvite(); |
104 | |
105 | if (eqicOneOf(input, "source", "sources", "source code")) |
106 | ret snippetLink(programID()); |
107 | } |
108 | |
109 | if (swic_trim(input, "add master ", m)) { |
110 | try answer checkAuth(_); |
111 | |
112 | setAdd(authorizedUsers, parseFirstLong(m.rest())); |
113 | change(); |
114 | |
115 | ret "Okidoki. Have " + n2(l(authorizedUsers), "master"); |
116 | } |
117 | |
118 | if (eqic(input, "masters")) |
119 | ret empty(authorizedUsers) ? "I have no masters." : "My masters are: " + joinWithComma(map discordAtPlusID(authorizedUsers)); |
120 | |
121 | if (swic_trim(input, "delete master ", m)) { |
122 | try answer checkAuth(_); |
123 | |
124 | remove(authorizedUsers, parseFirstLong(m.rest())); |
125 | change(); |
126 | |
127 | ret "Okidoki. Have " + n2(l(authorizedUsers), "master"); |
128 | } |
129 | |
130 | if (eqic(input, "guild count")) { |
131 | try answer checkAuth(_); |
132 | ret renderGuildCount(); |
133 | } |
134 | |
135 | if (eqic(input, "guild names")) { |
136 | try answer checkAuth(_); |
137 | ret renderGuildNames(); |
138 | } |
139 | |
140 | null; |
141 | } |
142 | |
143 | S renderGuildCount() { |
144 | ret "Total guilds joined: " + guildCount + ". Live guilds: " + liveGuildCount(); |
145 | } |
146 | |
147 | S renderGuildNames() { |
148 | ret lines(map(discord.getGuilds(), g -> g.getName())); |
149 | } |
150 | |
151 | bool authed(O... _) { |
152 | ret contains(authorizedUsers, optPar userID(_)); |
153 | } |
154 | |
155 | S checkAuth(O... _) { |
156 | long userID = longPar userID(_); |
157 | bool result = authed(_); |
158 | print("Auth-checking user ID: " + userID + " => " + result); |
159 | if (!result) ret "You are not authorized"; |
160 | null; |
161 | } |
162 | |
163 | S guildStructure() { |
164 | ret structure_nullingInstancesOfClass(_getClass(module()), this); |
165 | } |
166 | } // end of class ByServer |
167 | |
168 | S serveGuildBackup(MessageChannel channel, Guild guild, S data) { |
169 | if (guild == null) ret "Do this in a guild"; |
170 | if (containsDiscordToken(data)) ret "DISCORD TOKEN EXPOSED ALARM!! NOTIFY ADMINISTRATOR"; |
171 | S baseName = urlencode(jda_selfUserName(discord)) |
172 | + "-" + guild.getIdLong() + "-" + ymd_minus_hms(); |
173 | S zipName = baseName + ".zip"; |
174 | File zip = programFile("backups/" + zipName); |
175 | createZipFileWithSingleTextFile(zip, baseName + ".txt", data); |
176 | channel.sendMessage("Here's my latest brain contents for this guild.").addFile(zip).queue(); |
177 | null; |
178 | } |
179 | |
180 | // use structure() on ByServer |
181 | S serveGuildBackup(MessageChannel channel, Guild guild, ByServer bs) { |
182 | ret serveGuildBackup(channel, guild, bs.guildStructure()); |
183 | } |
184 | |
185 | // e.g. for help texts |
186 | S atSelfOrMyName() { |
187 | ret preprocessAtSelfToMyName ? myName : atSelf(); |
188 | } |
189 | } |
Began life as a copy of #1025128
download show line numbers debug dex old transpilations
Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt
No comments. add comment
Snippet ID: | #1025820 |
Snippet name: | DynTalkBot2 backup before guild masters |
Eternal ID of this version: | #1025820/1 |
Text MD5: | 97b0ce68ef93a6e417c6de5ea58db1e2 |
Author: | stefan |
Category: | javax / agi.blue |
Type: | JavaX fragment (include) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2019-10-23 14:01:33 |
Source code size: | 6263 bytes / 189 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 181 / 205 |
Referenced in: | [show references] |