Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

282
LINES

< > BotCompany Repo | #1026298 // [LIVE] DynTalkBot2 for JDA 4.0 - DynServerAwareDiscordBot + input simplification, onUserJoin, name, authorizedUsers

JavaX fragment (include)

1  
set flag JDA40.
2  
3  
import net.dv8tion.jda.api.events.Event;
4  
import net.dv8tion.jda.api.events.user.update.*;
5  
6  
asclass DynTalkBot2<A extends DynTalkBot2.ByServer> extends DynServerAwareDiscordBot<A> {
7  
  switchable S myName = "Anonymous bot";
8  
  transient bool useAGIBlueForDropPunctuation = true;
9  
  transient bool preprocessAtSelfToMyName = true;
10  
  transient bool dropPunctuation = true;
11  
  transient bool ngbCommands = true;
12  
  L<Long> authorizedUsers = ll(547706854680297473); // stefan
13  
  
14  
  srecord ISaid(long channelID, long date, S text) {}
15  
  
16  
  void init {
17  
    super.init();
18  
    
19  
    onPostedInChannel.add((channel, msg) -> {
20  
      if (channel cast GuildChannel) {
21  
        Guild guild = channel.getGuild();
22  
        if (guild == null) ret;
23  
        ByServer bs = getByServer(guild);
24  
        long channelID = channel.getIdLong();
25  
        mapPut(bs.lastSaidInChannel, channelID, nu ISaid(+channelID, text := msg));
26  
        change();
27  
      }
28  
    });
29  
    
30  
    // We leave it as null to force subclasses to set this
31  
    // (avoids serializing bad instances)
32  
    // makeByServer = () -> (A) new ByServer;
33  
    
34  
    dm_vmBus_onMessage_q discordGuildJoin(voidfunc(Map map) {
35  
      ret unless map.get('module) == module();
36  
      print("Got join");
37  
      getByServer(getLong guildID(map), true)
38  
        .onUserJoin(getLong userID(map), map);
39  
    });
40  
    
41  
    onDiscordEvent(e -> {
42  
      //print("Generic Discord event: " + e);
43  
      if (e cast UserUpdateOnlineStatusEvent)
44  
        getByServer(e.getGuild()).onOnlineStatusChange(e);
45  
    });
46  
  }
47  
  
48  
  class ByServer extends DynServerAwareDiscordBot<DynTalkBot2.ByServer>.ByServer {
49  
    transient Lock lock;
50  
    L<Long> guildAuthorizedUsers = synchroList();
51  
    Map<Long, ISaid> lastSaidInChannel = synchroMap();
52  
    long preferredChannelInGuild;
53  
54  
    DynTalkBot2 m2() { ret DynTalkBot2.this; } // for debugging
55  
    
56  
    // overridable
57  
    void onUserJoin(long userID, O... _) {}
58  
    void onOnlineStatusChange(UserUpdateOnlineStatusEvent e) {}
59  
    
60  
    // to change name by server
61  
    S myName() { ret myName; }
62  
  
63  
    @Override S answer(S input, Map map) {
64  
      if (preferredChannelInGuild == 0) {
65  
        long channelID = longPar channelID(map);
66  
        if (channelID != 0) {
67  
          preferredChannelInGuild = channelID;
68  
          change();
69  
        }
70  
      }
71  
        
72  
      S answer = processLine(input, map);
73  
      try answer super.answer(input, map); // server-aware stuff
74  
      
75  
      ret answer;
76  
    }
77  
    
78  
    S dropMyPrefixOpt(S s) {
79  
      ret or(dropMyPrefixOrNull(s), s);
80  
    }
81  
    
82  
    S dropMyPrefixOrNull(S s) {
83  
      S sOld = s;
84  
      s = dropPrefixICTrim_orNull(myPrefix(), s);
85  
      if (s == null)
86  
        print("no got prefix: " + quote(myPrefix()) + " / " + quote(sOld));
87  
      ret s;
88  
    }
89  
  
90  
    S processLine(S s, O... _) {
91  
      s = preprocess(s, _);
92  
      ret processSimplifiedLine(s, _);
93  
    }
94  
    
95  
    S preprocess(S s, O... _) {
96  
      print("Preprocessing: " + quote(s));
97  
      //pcall { print("mother: " + DynTalkBot2.this); }
98  
      if (preprocessAtSelfToMyName && discordBotID != 0) {
99  
        //S a = dropPunctuation ? dropPunctuation3(atSelf()) : atSelf();
100  
        LS l = ll(atSelf(), atExclamSelf());
101  
        print("Replacing " + sfu(l));
102  
        s = replace_multi(s, l, " " + myName + " ");
103  
        print("Got " + quote(s));
104  
      }
105  
      if (dropPunctuation)
106  
        s = dropPunctuation3_withAGIBlue(useAGIBlueForDropPunctuation, s);
107  
      s = trim(simpleSpaces_noTok(s));
108  
      print("simplified >> " + quote(s));
109  
      ret s;
110  
    }
111  
    
112  
    S myPrefix() {
113  
      ret preprocessAtSelfToMyName ?
114  
        (endsWithLetterOrDigit(myName()) ? myName() + " " : myName()) :
115  
        (dropPunctuation ? replace(atSelf(), "@", "") /* @ is killed by preprocessing */ : atSelf()) + " ";
116  
    }
117  
    
118  
    synchronized Lock myLock() {
119  
      if (lock == null) lock = lock();
120  
      ret lock;
121  
    }
122  
  
123  
    // extend me
124  
    S processSimplifiedLine(S input, O... _) {
125  
      lock myLock();
126  
      new Matches m;
127  
      
128  
      input = dropMyPrefixOrNull(input);
129  
      if (input == null) null;
130  
      
131  
      if (ngbCommands) {
132  
        if (eqicOneOf(input, "support channel", "support server", "support"))
133  
          ret "Get support for me here: " + nextGenBotsDiscordInvite();
134  
          
135  
        if (eqicOneOf(input, "source", "sources", "source code"))
136  
          ret snippetLink(programID());
137  
      }
138  
  
139  
      if (swic_trim(input, "add master ", m)) {
140  
        try answer checkAuth(_);
141  
  
142  
        setAdd(authorizedUsers, parseFirstLong(m.rest()));
143  
        change();
144  
        
145  
        ret "Okidoki. Have " + n2(l(authorizedUsers), "master");
146  
      }
147  
      
148  
      if (eqic(input, "masters"))
149  
        ret linesLL("General: " + renderMasters(),
150  
          "For this guild: " + renderGuildMasters());
151  
      
152  
      if (eqic(input, "guild masters"))
153  
        ret renderGuildMasters();
154  
      
155  
      if (swic_trim(input, "delete master ", m)) {
156  
        try answer checkAuth(_);
157  
  
158  
        remove(authorizedUsers, parseFirstLong(m.rest()));
159  
        change();
160  
        
161  
        ret "Okidoki. Have " + n2(l(authorizedUsers), "master");
162  
      }
163  
      
164  
      if (swic_trim(input, "add guild master ", m)) {
165  
        try answer checkPerGuildAuth(_);
166  
  
167  
        setAdd(guildAuthorizedUsers, parseFirstLong(m.rest()));
168  
        change();
169  
        
170  
        ret "Okidoki. " + renderGuildMasters();
171  
      }
172  
      
173  
      if (swic_trim(input, "delete guild master ", m)) {
174  
        try answer checkPerGuildAuth(_);
175  
  
176  
        remove(guildAuthorizedUsers, parseFirstLong(m.rest()));
177  
        change();
178  
        
179  
        ret "Okidoki. " + renderGuildMasters();
180  
      }
181  
      
182  
      if (eqic(input, "guild count")) {
183  
        try answer checkAuth(_);
184  
        ret renderGuildCount();
185  
      }
186  
      
187  
      if (eqic(input, "guild names")) {
188  
        try answer checkAuth(_);
189  
        ret renderGuildNames();
190  
      }
191  
      
192  
      null;
193  
    }
194  
    
195  
    S renderGuildMasters() {
196  
      ret empty(guildAuthorizedUsers) ? "Only this guild's owner can control me."
197  
          : "I am controlled by this guild's owner and these people: " + joinWithComma(map discordAtPlusID(guildAuthorizedUsers));
198  
    }
199  
    
200  
    S renderGuildCount() {
201  
      ret "Total guilds joined: " + guildCount + ". Live guilds: " + liveGuildCount();
202  
    }
203  
    
204  
    S renderGuildNames() {
205  
      ret lines(map(discord.getGuilds(), g -> g.getName()));
206  
    }
207  
    
208  
    bool authed(O... _) {
209  
      ret contains(authorizedUsers, optPar userID(_));
210  
    }
211  
  
212  
    bool perGuildAuthed(O... _) {
213  
      long userID = longPar userID(_);
214  
      ret contains(guildAuthorizedUsers, userID)
215  
        || guildID != 0 && userID == getGuild().getOwnerIdLong();
216  
    }
217  
    
218  
    Guild getGuild() {
219  
      ret guildID == 0 ? null : discord.getGuildById(guildID);
220  
    }
221  
  
222  
    S checkAuth(O... _) {  
223  
      long userID = longPar userID(_);
224  
      bool result = authed(_);
225  
      print("Auth-checking user ID: " + userID + " => " + result);
226  
      if (!result) ret "You are not authorized";
227  
      null;
228  
    }
229  
    
230  
    S checkPerGuildAuth(O... _) {  
231  
      if (authed(_)) null;
232  
      long userID = longPar userID(_);
233  
      bool result = perGuildAuthed(_);
234  
      print("Guild-auth-checking user ID: " + userID + " => " + result);
235  
      if (!result) ret "You are not authorized";
236  
      null;
237  
    }
238  
    
239  
    S guildStructure() {
240  
      ret structure_nullingInstancesOfClass(_getClass(module()), this);
241  
    }
242  
    
243  
    // e.g. for help texts
244  
    S atSelfOrMyName() {
245  
      ret preprocessAtSelfToMyName ? myName() : atSelf();
246  
    }
247  
    
248  
    S atSelfOrMyName_space() {
249  
      ret preprocessAtSelfToMyName ? appendSpaceIfEndsWithLetter(myName) : atSelf();
250  
    }
251  
    
252  
    S guildMastersHelp() {
253  
      ret [[
254  
@me **masters** -- show who controls me
255  
@me **add guild master @user** -- allow @user to control me
256  
@me **delete guild master @user** -- @user can no longer control me
257  
]];
258  
    }
259  
  
260  
  } // end of class ByServer
261  
  
262  
  S serveGuildBackup(MessageChannel channel, Guild guild, S data) {
263  
    if (guild == null) ret "Do this in a guild";
264  
    if (containsDiscordToken(data)) ret "DISCORD TOKEN EXPOSED ALARM!! NOTIFY ADMINISTRATOR";
265  
    S baseName = urlencode(jda_selfUserName(discord))
266  
      + "-" + guild.getIdLong() + "-" + ymd_minus_hms();
267  
    S zipName = baseName + ".zip";
268  
    File zip = programFile("backups/" + zipName);
269  
    createZipFileWithSingleTextFile(zip, baseName + ".txt", data);
270  
    channel.sendMessage("Here's my latest brain contents for this guild.").addFile(zip).queue();
271  
    null;
272  
  }
273  
  
274  
  // use structure() on ByServer
275  
  S serveGuildBackup(MessageChannel channel, Guild guild, ByServer bs) {
276  
    ret serveGuildBackup(channel, guild, bs.guildStructure());
277  
  }
278  
  
279  
  S renderMasters() {
280  
    ret empty(authorizedUsers) ? "I have no masters." : "My masters are: " + joinWithComma(map discordAtPlusID(authorizedUsers));
281  
  }
282  
}

Author comment

Began life as a copy of #1025128

download  show line numbers  debug dex  old transpilations   

Travelled to 9 computer(s): bhatertpkbcr, mqqgnosmbjvj, onxytkatvevr, pyentgdyhuwx, pzhvpgtvlbxg, qsqiayxyrbia, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1026298
Snippet name: [LIVE] DynTalkBot2 for JDA 4.0 - DynServerAwareDiscordBot + input simplification, onUserJoin, name, authorizedUsers
Eternal ID of this version: #1026298/17
Text MD5: 1bc86b4c9b5693a46a57600fd9790f52
Author: stefan
Category: javax / discord
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2021-01-24 02:25:29
Source code size: 9042 bytes / 282 lines
Pitched / IR pitched: No / No
Views / Downloads: 339 / 1130
Version history: 16 change(s)
Referenced in: [show references]