mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-22 19:24:53 +08:00
添加简单的群组活跃状态记录器,添加程序安全结束钩子
- ./data/tracker/<chatid>/<userid>/<unixdaystamp>.txt - 每行一个发言时的timestamp - 0/0/currentTime 用于记录tracker的在线状态
This commit is contained in:
parent
976d106de9
commit
66866572c0
@ -3,7 +3,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group 'cc.sukazyo'
|
group 'cc.sukazyo'
|
||||||
version '0.1.2'
|
version '0.2.0'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -2,7 +2,7 @@ package cc.sukazyo.cono.morny;
|
|||||||
|
|
||||||
import cc.sukazyo.cono.morny.bot.api.OnUpdate;
|
import cc.sukazyo.cono.morny.bot.api.OnUpdate;
|
||||||
import cc.sukazyo.cono.morny.bot.event.EventListeners;
|
import cc.sukazyo.cono.morny.bot.event.EventListeners;
|
||||||
import cc.sukazyo.cono.morny.data.MornyHello;
|
import cc.sukazyo.cono.morny.data.tracker.TrackerDataManager;
|
||||||
import com.pengrad.telegrambot.TelegramBot;
|
import com.pengrad.telegrambot.TelegramBot;
|
||||||
import com.pengrad.telegrambot.request.GetMe;
|
import com.pengrad.telegrambot.request.GetMe;
|
||||||
|
|
||||||
@ -18,6 +18,8 @@ public class MornyCoeur {
|
|||||||
logger.info(MornyHello.MORNY_PREVIEW_IMAGE_ASCII);
|
logger.info(MornyHello.MORNY_PREVIEW_IMAGE_ASCII);
|
||||||
logger.info("System Starting");
|
logger.info("System Starting");
|
||||||
|
|
||||||
|
configureSafeExit();
|
||||||
|
|
||||||
logger.info("args key:\n " + args[0]);
|
logger.info("args key:\n " + args[0]);
|
||||||
|
|
||||||
try { account = login(args[0]); }
|
try { account = login(args[0]); }
|
||||||
@ -25,6 +27,7 @@ public class MornyCoeur {
|
|||||||
|
|
||||||
logger.info("Bot login succeed.");
|
logger.info("Bot login succeed.");
|
||||||
|
|
||||||
|
TrackerDataManager.init();
|
||||||
EventListeners.registerAllListeners();
|
EventListeners.registerAllListeners();
|
||||||
account.setUpdatesListener(OnUpdate::onNormalUpdate);
|
account.setUpdatesListener(OnUpdate::onNormalUpdate);
|
||||||
|
|
||||||
@ -32,6 +35,15 @@ public class MornyCoeur {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void exitCleanup () {
|
||||||
|
TrackerDataManager.DAEMON.interrupt();
|
||||||
|
TrackerDataManager.trackingLock.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void configureSafeExit () {
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(MornyCoeur::exitCleanup));
|
||||||
|
}
|
||||||
|
|
||||||
public static TelegramBot login (String key) {
|
public static TelegramBot login (String key) {
|
||||||
TelegramBot account = new TelegramBot(key);
|
TelegramBot account = new TelegramBot(key);
|
||||||
logger.info("Trying to login...");
|
logger.info("Trying to login...");
|
||||||
|
@ -25,9 +25,13 @@ public class EventListenerManager {
|
|||||||
@Override
|
@Override
|
||||||
public void run () {
|
public void run () {
|
||||||
for (EventListener x : listeners) {
|
for (EventListener x : listeners) {
|
||||||
|
try {
|
||||||
if (exec.apply(x)) return;
|
if (exec.apply(x)) return;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error("Event Error!");
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
logger.info("event exited undone");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -5,9 +5,11 @@ import cc.sukazyo.cono.morny.bot.api.EventListenerManager;
|
|||||||
public class EventListeners {
|
public class EventListeners {
|
||||||
|
|
||||||
public static final OnCommandExecute COMMANDS_LISTENER = new OnCommandExecute();
|
public static final OnCommandExecute COMMANDS_LISTENER = new OnCommandExecute();
|
||||||
|
public static final OnActivityRecord ACTIVITY_RECORDER = new OnActivityRecord();
|
||||||
|
|
||||||
public static void registerAllListeners () {
|
public static void registerAllListeners () {
|
||||||
EventListenerManager.addListener(
|
EventListenerManager.addListener(
|
||||||
|
ACTIVITY_RECORDER,
|
||||||
COMMANDS_LISTENER
|
COMMANDS_LISTENER
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
package cc.sukazyo.cono.morny.bot.event;
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.bot.api.EventListener;
|
||||||
|
import cc.sukazyo.cono.morny.data.tracker.TrackerDataManager;
|
||||||
|
import com.pengrad.telegrambot.model.Chat;
|
||||||
|
import com.pengrad.telegrambot.model.Update;
|
||||||
|
|
||||||
|
public class OnActivityRecord extends EventListener {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onMessage (Update update) {
|
||||||
|
if (
|
||||||
|
update.message().chat().type() == Chat.Type.supergroup ||
|
||||||
|
update.message().chat().type() == Chat.Type.group
|
||||||
|
) {
|
||||||
|
TrackerDataManager.record(
|
||||||
|
update.message().chat().id(),
|
||||||
|
update.message().from().id(),
|
||||||
|
(long)update.message().date() * 1000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return super.onMessage(update);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,118 @@
|
|||||||
|
package cc.sukazyo.cono.morny.data.tracker;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.TreeSet;
|
||||||
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
|
import static cc.sukazyo.cono.morny.Logger.logger;
|
||||||
|
|
||||||
|
public class TrackerDataManager {
|
||||||
|
|
||||||
|
public static final ReentrantLock trackingLock = new ReentrantLock();
|
||||||
|
|
||||||
|
private static final ReentrantLock recordLock = new ReentrantLock();
|
||||||
|
private static HashMap<Long, HashMap<Long, TreeSet<Long>>> record = new HashMap<>();
|
||||||
|
|
||||||
|
public static final TrackerDaemon DAEMON = new TrackerDaemon();
|
||||||
|
public static class TrackerDaemon extends Thread {
|
||||||
|
|
||||||
|
public TrackerDaemon () { this.setName("TRACKER"); }
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run () {
|
||||||
|
trackingLock.lock();
|
||||||
|
long lastWaitTimestamp = System.currentTimeMillis();
|
||||||
|
boolean postProcess = false;
|
||||||
|
do {
|
||||||
|
long sleeping = lastWaitTimestamp - System.currentTimeMillis();
|
||||||
|
if (sleeping > 0) {
|
||||||
|
try { Thread.sleep(sleeping); } catch (InterruptedException e) { interrupt(); }
|
||||||
|
} else {
|
||||||
|
logger.warn("Tracker may be too busy to process data!!");
|
||||||
|
lastWaitTimestamp = System.currentTimeMillis();
|
||||||
|
}
|
||||||
|
if (interrupted()) {
|
||||||
|
postProcess = true;
|
||||||
|
logger.warn("last tracker write in this processor!");
|
||||||
|
}
|
||||||
|
lastWaitTimestamp += 10 * 60 * 1000;
|
||||||
|
if (record.size() != 0) {
|
||||||
|
logger.info("start writing tracker data.");
|
||||||
|
save(reset());
|
||||||
|
logger.info("done writing tracker data.");
|
||||||
|
}
|
||||||
|
else logger.info("nothing to do yet");
|
||||||
|
} while (!postProcess);
|
||||||
|
trackingLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void record (long chat, long user, long timestamp) {
|
||||||
|
recordLock.lock();
|
||||||
|
if (!record.containsKey(chat)) record.put(chat, new HashMap<>());
|
||||||
|
HashMap<Long, TreeSet<Long>> chatUsers = record.get(chat);
|
||||||
|
if (!chatUsers.containsKey(user)) chatUsers.put(user, new TreeSet<>());
|
||||||
|
TreeSet<Long> userRecords = chatUsers.get(user);
|
||||||
|
userRecords.add(timestamp);
|
||||||
|
recordLock.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void init () {
|
||||||
|
DAEMON.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static HashMap<Long, HashMap<Long, TreeSet<Long>>> reset () {
|
||||||
|
recordLock.lock();
|
||||||
|
HashMap<Long, HashMap<Long, TreeSet<Long>>> recordOld = record;
|
||||||
|
record = new HashMap<>();
|
||||||
|
recordLock.unlock();
|
||||||
|
return recordOld;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void save (HashMap<Long, HashMap<Long, TreeSet<Long>>> record) {
|
||||||
|
|
||||||
|
record.forEach((chat, chatUsers) -> chatUsers.forEach((user, userRecords) -> {
|
||||||
|
|
||||||
|
long dayCurrent = -1;
|
||||||
|
FileChannel channelCurrent = null;
|
||||||
|
|
||||||
|
for (long timestamp : userRecords) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
long day = timestamp / (24 * 60 * 60 * 1000);
|
||||||
|
if (dayCurrent != day) {
|
||||||
|
if (channelCurrent != null) channelCurrent.close();
|
||||||
|
channelCurrent = openFile(chat, user, day);
|
||||||
|
dayCurrent = day;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert channelCurrent != null;
|
||||||
|
channelCurrent.write(ByteBuffer.wrap(
|
||||||
|
String.format("%d\n", timestamp).getBytes(StandardCharsets.UTF_8)
|
||||||
|
));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.error(String.format("exception in write tracker data: %d/%d/%d", chat, user, timestamp));
|
||||||
|
e.printStackTrace(System.out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FileChannel openFile (long chat, long user, long day) throws IOException {
|
||||||
|
File data = new File(String.format("./data/tracker/%d/%d", chat, user));
|
||||||
|
if (!data.isDirectory()) if (!data.mkdirs()) throw new IOException("Cannot create file directory " + data.getPath());
|
||||||
|
File file = new File(data, String.valueOf(day));
|
||||||
|
if (!file.isFile()) if (!file.createNewFile()) throw new IOException("Cannot create file " + file.getPath());
|
||||||
|
return new FileOutputStream(file, true).getChannel();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user