Warning: session_start(): open(/var/lib/php/sessions/sess_qgr80d286hkui427obmsh32869, O_RDWR) failed: No space left on device (28) in /var/www/tb-usercake/models/config.php on line 51
Warning: session_start(): Failed to read session data: files (path: /var/lib/php/sessions) in /var/www/tb-usercake/models/config.php on line 51
abstract sclass DynDiscordHopper > DynPrintLogAndEnabled {
ifdef JDA40
!include #1026292 // Discord with JDA 4.0
endifdef
ifndef JDA40
!include #1023434 // Discord
endifndef
bool discordEnabled() { ret enabled; }
bool printToModule() { true; }
bool discordHopperMetaCmdsEnabled;
long preferredChannelID;
transient double minutesToKeepRecordedAnswers = 60.0;
L recordedAnswers = syncList();
sclass RecordedAnswer {
long timestamp;
long questionMsgID, answerMsgID, channelID;
S questionText, answerText;
toString { ret stdToString(this); }
}
switchable transient bool verboseEvents;
transient new L onDiscordStarted;
transient L> onDiscordEvent = syncList();
transient ListenerAdapter genericListener = new {
public void onGenericEvent(Event e) enter {
if (verboseEvents) print("Discord event: " + e);
pcallFAll(onDiscordEvent, e);
}
};
void onDiscordEvent(IVF1 e) {
onDiscordEvent.add(e);
}
enhanceFrame {
internalFramePopupMenuItem(f, "Start keep-alive module", rThread startKeepAliveModule);
minFrameSize(f, 300, 300);
}
// Note: Breaking change - moved start to thread
start-thread {
init();
startMe();
}
void startMe {
dm_vmBus_onMessage_q incomingDiscordMessage(voidfunc(Map map) {
if (!enabled) ret;
O module = map.get('module);
if (!dm_isMe(module)) ret;
S s = getString content(map);
long channelID = toLong(map.get('channelID));
if (channelID != 0 && preferredChannelID == 0)
setField(preferredChannelID := channelID);
cleanRecordedAnswers();
S answer = answer(s, map);
sendReply(map, answer);
});
if (!enabled) ret;
print("Starting Discord");
startDiscord();
print("Started Discord");
if (genericListener == null)
fail("genericListener is null");
discord.addEventListener(genericListener);
pcallFAll(onDiscordStarted);
}
void sendReply(Map map, S answer) {
if (empty(answer)) ret;
cleanRecordedAnswers();
new RecordedAnswer a;
if (minutesToKeepRecordedAnswers > 0) {
a.timestamp = now();
a.questionMsgID = getLong msgID(map);
a.channelID = getLong channelID(map);
a.questionText = getString content(map);
a.answerText = answer;
print("Recording answer : " + a);
recordedAnswers.add(a);
change();
}
dm_rcall reply(map.get('module), map, answer, (IVF1) msg -> {
a.answerMsgID = rcall_long getIdLong(msg);
change();
});
}
S answer(S s, Map map) {
if (discordHopperMetaCmdsEnabled && eq(s, "!bot count"))
ret lstr(dm_activeDiscordTokens());
if (eq(s, "!ip address"))
ret myPublicIP();
LS tokens = extractPossibleDiscordTokens(s);
for unnull (S token : tokens) {
if (getLong guildID(map) != 0)
ret "Send tokens only in private messages!!";
S answer = "That's a Discord token!";
if (contains(concatLists((LLS) vmBus_queryAll activeDiscordTokens()), token))
answer += " And I'm there already.";
else {
answer += " Jumping there!!";
dm_showNewModuleWithParams(dm_moduleLibID(), discordToken := token);
}
reply(map, answer);
}
null;
}
S atSelf() { ret discordAt(discordBotID); }
// sometimes mentions come in like this?
S atExclamSelf() { ret discordAtExclam(discordBotID); }
void onDiscordStarted(Runnable r) { onDiscordStarted.add(r); }
User getSelfUser() { ret discord.getSelfUser(); }
// OVERRIDE ME
void init {
dm_watchField discordToken(r { if (nempty(discordToken) && enabled) dm_reloadModule() });
dm_reloadOnFieldChange enabled();
}
void cleanRecordedAnswers {
RecordedAnswer a;
bool change;
synchronized(recordedAnswers) {
while ((a = first(recordedAnswers)) != null
&& elapsedMinutes_timestamp(a.timestamp) > minutesToKeepRecordedAnswers) {
print("Removing old answer: " + a);
recordedAnswers.remove(a);
}
set change;
}
if (change) change();
}
afterVisualize {
if (empty(discordToken))
containerAddFirst(buttons, jThreadedButton("Give me a token!", r {
temp enter(); dm_stringFieldDialog discordToken();
}));
addToContainer(buttons, jPopDownButton_noText(
"Export all my data...", rThread { dm_exportStructureToTextFileDialog(module()) },
"Import all my data...", rThread { dm_importStructureFromTextFileDialog(module()) }
));
}
bool warnOnDelete() { true; }
// API
S migrateToType(S moduleLibID) {
S moduleID = assertNotNull(dm_showNewModuleWithParams(moduleLibID, +discordToken));
print("Migrated to new module " + moduleID + ", disabling me");
setEnabled(false);
dm_reload(); // actually disable Discord
ret moduleID;
}
}