package com.github.ltsopensource.nio.idle;
import com.github.ltsopensource.core.commons.concurrent.ConcurrentHashSet;
import com.github.ltsopensource.core.support.SystemClock;
import com.github.ltsopensource.nio.channel.NioChannel;
import com.github.ltsopensource.nio.channel.NioChannelImpl;
import com.github.ltsopensource.nio.config.NioConfig;
import com.github.ltsopensource.nio.handler.Futures;
import com.github.ltsopensource.nio.handler.IoFutureListener;
import com.github.ltsopensource.remoting.Future;
/**
* @author Robert HG (254963746@qq.com) on 1/24/16.
*/
public class IdleDetector {
private final ConcurrentHashSet<NioChannel> channels = new ConcurrentHashSet<NioChannel>();
public void addChannel(NioChannel channel) {
channels.add(channel);
channel.getCloseFuture().addListener(new IoFutureListener() {
@Override
public void operationComplete(Future future) throws Exception {
removeChannel(((Futures.CloseFuture) future).channel());
}
});
}
public void removeChannel(NioChannel channel) {
channels.remove(channel);
}
private DetectorTask task = new DetectorTask();
public void start() {
new Thread(task).start();
}
public void stop() {
task.stop();
}
private class DetectorTask implements Runnable {
private volatile boolean stop = false;
private volatile Thread thread;
@Override
public void run() {
thread = Thread.currentThread();
while (!stop) {
long currentTime = SystemClock.now();
for (NioChannel channel : channels) {
if (channel.isConnected()) {
idleCheck0((NioChannelImpl) channel, currentTime);
}
}
try {
Thread.sleep(1000L);
} catch (InterruptedException ignored) {
}
}
}
public void stop() {
stop = true;
Thread thread = this.thread;
if (thread != null) {
thread.interrupt();
}
}
private void idleCheck0(NioChannelImpl channel, long currentTime) {
IdleInfo idle = channel.getIdleInfo();
long lastReadTime = idle.getLastReadTime();
long lastWriteTime = idle.getLastWriteTime();
long lastIoTime = Math.max(lastReadTime, lastWriteTime);
NioConfig config = channel.getConfig();
if (config.getIdleTimeBoth() > 0) {
notifyIdle(channel, IdleState.BOTH_IDLE, currentTime, config.getIdleTimeBoth() * 1000,
Math.max(lastIoTime, idle.getLastBothIdleTime()));
}
if (config.getIdleTimeRead() > 0) {
notifyIdle(channel, IdleState.READER_IDLE, currentTime, config.getIdleTimeRead() * 1000,
Math.max(lastIoTime, idle.getLastReadIdleTime()));
}
if (config.getIdleTimeWrite() > 0) {
notifyIdle(channel, IdleState.WRITER_IDLE, currentTime, config.getIdleTimeWrite() * 1000,
Math.max(lastIoTime, idle.getLastWriteIdleTime()));
}
notifyWriteTimeout(channel, currentTime);
}
private void notifyWriteTimeout(NioChannelImpl channel, long currentTime) {
// 将正在写的请求置为timeout
// TODO
}
private void notifyIdle(NioChannelImpl channel, IdleState state, long currentTime, long idleTime, long lastIoTime) {
if ((idleTime > 0) && (lastIoTime != 0) && (currentTime - lastIoTime >= idleTime)) {
channel.fireChannelIdle(state, currentTime);
}
}
}
}