This commit is contained in:
rubenlagus 2020-11-04 01:23:37 +00:00 committed by Ruben Bermudez
parent 93bd1e0efe
commit 2f56a05a22

View File

@ -11,9 +11,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
* Created by Daniil Nikanov aka JetCoder * Created by Daniil Nikanov aka JetCoder
*/ */
@SuppressWarnings("unused")
public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot
{ {
private static final long MANY_CHATS_SEND_INTERVAL = 33;
private static final long ONE_CHAT_SEND_INTERVAL = 1000; private static final long ONE_CHAT_SEND_INTERVAL = 1000;
private static final long CHAT_INACTIVE_INTERVAL = 1000 * 60 * 10; private static final long CHAT_INACTIVE_INTERVAL = 1000 * 60 * 10;
private final Timer mSendTimer = new Timer(true); private final Timer mSendTimer = new Timer(true);
@ -21,29 +21,85 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot
private final ArrayList<MessageQueue> mSendQueues = new ArrayList<>(); private final ArrayList<MessageQueue> mSendQueues = new ArrayList<>();
private final AtomicBoolean mSendRequested = new AtomicBoolean(false); private final AtomicBoolean mSendRequested = new AtomicBoolean(false);
private final class MessageSenderTask extends TimerTask
{
@Override
public void run()
{
//mSendRequested used for optimisation to not traverse all mMessagesMap 30 times per second all the time
if (!mSendRequested.getAndSet(false))
return;
long currentTime = System.currentTimeMillis();
mSendQueues.clear();
boolean processNext = false;
//First step - find all chats in which already allowed to send message (passed more than 1000 ms from previuos send)
Iterator<Map.Entry<Long,MessageQueue>> it = mMessagesMap.entrySet().iterator();
while (it.hasNext())
{
MessageQueue queue = it.next().getValue();
int state = queue.getCurrentState(currentTime); //Actual check here
if (state == MessageQueue.GET_MESSAGE)
{
mSendQueues.add(queue);
processNext = true;
}
else if (state == MessageQueue.WAIT)
{
processNext = true;
}
else if (state == MessageQueue.DELETE)
{
it.remove();
}
}
//If any of chats are in state WAIT or GET_MESSAGE, request another iteration
if (processNext)
mSendRequested.set(true);
//Second step - find oldest waiting queue and peek it's message
MessageQueue sendQueue = null;
long oldestPutTime = Long.MAX_VALUE;
for (MessageQueue queue : mSendQueues) {
long putTime = queue.getPutTime();
if (putTime < oldestPutTime) {
oldestPutTime = putTime;
sendQueue = queue;
}
}
if (sendQueue == null) //Possible if on first step wasn't found any chats in state GET_MESSAGE
return;
//Invoke the send callback. ChatId is passed for possible additional processing
sendMessageCallback(sendQueue.getChatId(), sendQueue.getMessage(currentTime));
}
}
private static class MessageQueue private static class MessageQueue
{ {
static final int EMPTY = 0; //Queue is empty public static final int EMPTY = 0; //Queue is empty
static final int WAIT = 1; //Queue has message(s) but not yet allowed to send public static final int WAIT = 1; //Queue has message(s) but not yet allowed to send
static final int DELETE = 2; //No one message of given queue was sent longer than CHAT_INACTIVE_INTERVAL, delete for optimisation public static final int DELETE = 2; //No one message of given queue was sent longer than CHAT_INACTIVE_INTERVAL, delete for optimisation
static final int GET_MESSAGE = 3; //Queue has message(s) and ready to send public static final int GET_MESSAGE = 3; //Queue has message(s) and ready to send
private final ConcurrentLinkedQueue<Object> mQueue = new ConcurrentLinkedQueue<>(); private final ConcurrentLinkedQueue<Object> mQueue = new ConcurrentLinkedQueue<>();
private final Long mChatId; private final Long mChatId;
private long mLastSendTime; //Time of last peek from queue private long mLastSendTime; //Time of last peek from queue
private volatile long mLastPutTime; //Time of last put into queue private volatile long mLastPutTime; //Time of last put into queue
MessageQueue(Long chatId) public MessageQueue(Long chatId)
{ {
mChatId = chatId; mChatId = chatId;
} }
synchronized void putMessage(Object msg) public synchronized void putMessage(Object msg)
{ {
mQueue.add(msg); mQueue.add(msg);
mLastPutTime = System.currentTimeMillis(); mLastPutTime = System.currentTimeMillis();
} }
synchronized int getCurrentState(long currentTime) public synchronized int getCurrentState(long currentTime)
{ {
//currentTime is passed as parameter for optimisation to do not recall currentTimeMillis() many times //currentTime is passed as parameter for optimisation to do not recall currentTimeMillis() many times
long interval = currentTime - mLastSendTime; long interval = currentTime - mLastSendTime;
@ -58,23 +114,29 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot
return WAIT; return WAIT;
} }
synchronized Object getMessage(long currentTime) public synchronized Object getMessage(long currentTime)
{ {
mLastSendTime = currentTime; mLastSendTime = currentTime;
return mQueue.poll(); return mQueue.poll();
} }
long getPutTime() public long getPutTime()
{ {
return mLastPutTime; return mLastPutTime;
} }
Long getChatId() public Long getChatId()
{ {
return mChatId; return mChatId;
} }
} }
//Constructor
protected TimedSendLongPollingBot()
{
mSendTimer.schedule(new MessageSenderTask(), MANY_CHATS_SEND_INTERVAL, MANY_CHATS_SEND_INTERVAL);
}
//Something like destructor //Something like destructor
public void finish() public void finish()
{ {
@ -149,5 +211,5 @@ public abstract class TimedSendLongPollingBot extends TelegramLongPollingBot
} }
} }
*/ */
abstract void sendMessageCallback(Long chatId, Object messageRequest); public abstract void sendMessageCallback(Long chatId, Object messageRequest);
} }