package com.moshi.receptionist.service.impl;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import com.moshi.push.recepsrv.ServerShutdownListenner;
import com.moshi.push.recepsrv.conf.RecepsrvConfig;
import com.moshi.push.recepsrv.session.Session;
import com.moshi.push.recepsrv.session.SessionRepositoryEventListener;
import com.moshi.receptionist.common.message.MessageEvent;
import com.moshi.receptionist.common.router.RoutingTable;
import com.moshi.receptionist.redis.common.listener.MessageListener;
import com.moshi.receptionist.redis.sub.handler.PSubHandler;
import com.moshi.receptionist.router.event.SimpleMessageEvent;
import com.moshi.receptionist.service.MessageSubscribeService;
public class RedisMessageSubscribeService implements MessageSubscribeService ,
SessionRepositoryEventListener,
SubscribeCallBack,
EventListenerFailCallBack,
UnSubscribeCallBack,
ServerShutdownListenner{
private static final Logger log = LoggerFactory.getLogger(RedisMessageSubscribeService.class);
private PSubHandler subHandler;
private RoutingTable routingTable;
private ExecutorService subscribePool;
private ExecutorService eventListenerPool;
private ExecutorService pollMessagesPool;
private RecepsrvConfig serverConfig;
private String clientId;
private AtomicInteger subscribeNum = new AtomicInteger(0);
public RedisMessageSubscribeService(RecepsrvConfig config){
this.serverConfig=config;
clientId = serverConfig.getNodeName() ;
try {
if(clientId==null){
clientId = InetAddress.getLocalHost().getHostName();
}
} catch (UnknownHostException e) {
clientId="unKnowHost";
}
int subPoolSize = serverConfig.getSubscribeThreads();
int pollMsgSize = serverConfig.getPollMessageThreads();
if(subPoolSize<1){
subscribePool = Executors.newCachedThreadPool();
}else{
subscribePool = Executors.newFixedThreadPool(subPoolSize);
}
//----------------------------------------------------------------------------------------
if(pollMsgSize<1){
pollMessagesPool = Executors.newCachedThreadPool();
}else{
pollMessagesPool = Executors.newFixedThreadPool(pollMsgSize);
}
eventListenerPool = Executors.newSingleThreadExecutor();//单线程的接收redis 事件通知
}
public RedisMessageSubscribeService(RecepsrvConfig config,RoutingTable router){
this(config);
routingTable = router;
}
@Override
public void onUserSessionBuild(Session session) {
subscribe(session.getSessionName());
}
@Override
public void onSessionRemoved(Session session) {
unSubscribe(session.getSessionName());
}
@Override
public void registerMessageListener(MessageListener listener) {
subHandler.registerMessageListener(listener);
}
@Override
public void unRegisterMessageListener(MessageListener listener) {
subHandler.removeMessageListener(listener);
}
@Override
public void onMessageEvent(String channel, String message) {
MessageEvent event = new MessageEvent();
event.setContent(new SimpleMessageEvent(message));
event.setMessageId(RandomStringUtils.random(10));
event.setToTag(channel);
routingTable.routeMessage(event);
}
@Override
public void initialization() {
subHandler =PSubHandler.getInstance(new Jedis(serverConfig.getRedisHost(),serverConfig.getRedisPort()), clientId);
subHandler.registerMessageListener(this);
createEventListener();
}
@Override
public void subscribe(final String messageTags) {
pollMessagesPool.execute(new OpenMessageTask(messageTags, this));
subscribePool.execute(new SubscribeTask(clientId, messageTags,this));
}
@Override
public void unSubscribe(final String messageTags) {
subscribePool.execute(new UnSubscribeTask(clientId, messageTags, this));
}
@Override
public void onUnsubscribeFail(String clientId, String messageTag) {
unSubscribe(messageTag);
}
@Override
public void onSubscribeFail(String clientId, String messageTag) {
log.warn("subscribe fail, resub again :{}/{}.",clientId,messageTag);
subscribe(messageTag);
}
private void createEventListener(){
Runnable task = new EventListenerCreateTask(serverConfig.getRedisHost(), serverConfig.getRedisPort(), clientId, this,subHandler);
eventListenerPool.execute(task);
}
@Override
public void onPipleFail(String clientId) {
createEventListener();
}
@Override
public void onSubscribeSuccess(String clientId, String messageTag) {
int num = subscribeNum.incrementAndGet();
if(log.isDebugEnabled()){
log.debug("current subscribed users = {}.",num);
}
}
@Override
public void onUnSubscribeSuccess(String clientId, String messageTag) {
int num = subscribeNum.decrementAndGet();
if(log.isDebugEnabled()){
log.debug("current subscribed users = {}.",num);
}
}
@Override
public boolean isBusy(int currentNum, int limit) {
return currentNum-limit>subscribeNum.get();
}
@Override
public void onShotdown() {
this.eventListenerPool.shutdown();
this.pollMessagesPool.shutdown();
this.subscribePool.shutdown();
}
}