├── talkshutdown.sh ├── packagedev.sh ├── packageproduct.sh ├── src └── main │ ├── java │ └── com │ │ └── mogujie │ │ └── ares │ │ ├── data │ │ ├── IData.java │ │ ├── Counter.java │ │ ├── GroupCounterItem.java │ │ ├── Relationship.java │ │ ├── Audio.java │ │ ├── GroupRelation.java │ │ ├── GroupMessage.java │ │ ├── TransmitFile.java │ │ ├── Department.java │ │ ├── Group.java │ │ ├── Message.java │ │ └── User.java │ │ ├── extend │ │ ├── BaseAction.java │ │ ├── filter │ │ │ ├── IFilter.java │ │ │ ├── LoginFilter.java │ │ │ └── MessageContentFilter.java │ │ ├── action │ │ │ ├── ServerConfig.java │ │ │ ├── Monitor.java │ │ │ ├── StatisticsContent.java │ │ │ ├── Login.java │ │ │ ├── Dashboard.java │ │ │ ├── DelayUpdateMonitor.java │ │ │ ├── FileAction.java │ │ │ ├── DepartAction.java │ │ │ ├── UserAction.java │ │ │ ├── Friendship.java │ │ │ └── MessageCounter.java │ │ ├── dispatch │ │ │ └── DefaultRequestDispatcher.java │ │ ├── ActionContext.java │ │ ├── ActionHolder.java │ │ └── RequestParams.java │ │ ├── lib │ │ ├── net │ │ │ ├── Test.java │ │ │ ├── IDispatcher.java │ │ │ ├── IMHttpResponse.java │ │ │ ├── MoguHttpResponse.java │ │ │ ├── FileManager.java │ │ │ ├── Packet.java │ │ │ ├── BinaryMessageHandler.java │ │ │ ├── FrameBinaryDecoder.java │ │ │ ├── FrameBinaryEncoder.java │ │ │ └── DataBuffer.java │ │ ├── logger │ │ │ ├── NoneFilteredLoggerFilter.java │ │ │ ├── ConnectionKeepAliveFilter.java │ │ │ ├── LoggerFactory.java │ │ │ └── Logger.java │ │ └── storage │ │ │ ├── CachePool.java │ │ │ └── DBPool.java │ │ ├── timer │ │ ├── ConfigureReloadTask.java │ │ ├── WorkerInfoReloader.java │ │ └── Timer.java │ │ ├── model │ │ ├── ServerConfigModel.java │ │ ├── LoginModel.java │ │ ├── DepartModel.java │ │ ├── StatisticsModel.java │ │ └── AudioModel.java │ │ ├── util │ │ ├── MoguByteUtil.java │ │ ├── MoguArrayUtil.java │ │ ├── HttpUtil.java │ │ └── MoguUtil.java │ │ ├── manager │ │ ├── FileManager.java │ │ ├── ConfigureManager.java │ │ ├── CacheManager.java │ │ ├── DBManager.java │ │ ├── TimerManager.java │ │ └── ElegantStopManager.java │ │ ├── configure │ │ ├── SysConstants.java │ │ ├── BizConstants.java │ │ ├── Configure.java │ │ ├── Router.java │ │ └── PBRouter.java │ │ └── MainServer.java │ └── resources │ ├── system.properties │ ├── timer.xml │ ├── db-online.properties │ ├── db-dev.properties │ ├── cache-online.properties │ ├── cache-dev.properties │ └── logback.xml ├── run.sh ├── startup.sh ├── README.md └── pom.xml /talkshutdown.sh: -------------------------------------------------------------------------------- 1 | echo stop > /tmp/.mogutalk_stop.tmp 2 | -------------------------------------------------------------------------------- /packagedev.sh: -------------------------------------------------------------------------------- 1 | mvn clean package -Dmaven.test.skip=true 2 | mvn dependency:copy-dependencies 3 | -------------------------------------------------------------------------------- /packageproduct.sh: -------------------------------------------------------------------------------- 1 | mvn clean package -P product -Dmaven.test.skip=true 2 | mvn dependency:copy-dependencies 3 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/IData.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | public interface IData { 4 | 5 | } 6 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/BaseAction.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend; 2 | 3 | public abstract class BaseAction { 4 | } 5 | -------------------------------------------------------------------------------- /src/main/resources/system.properties: -------------------------------------------------------------------------------- 1 | mcrypt_salt=tt vs TT ? 2 | task_initialize_pool=3 3 | 4 | com.mogujie.ares.config.file.db=${config.file.db} 5 | com.mogujie.ares.config.file.cache=${config.file.cache} 6 | com.mogujie.ares.config.file.route=route.xml 7 | com.mogujie.ares.config.file.timer=timer.xml 8 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/filter/IFilter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.filter; 2 | 3 | /** 4 | * 5 | * @Description: 请求的过滤器 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2013-7-21 下午3:36:07 8 | * 9 | */ 10 | public interface IFilter { 11 | 12 | public void doFilter(); 13 | } 14 | -------------------------------------------------------------------------------- /src/main/resources/timer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.mogujie.ares.timer.ConfigureReloadTask 5 | 0 6 | rateTask 7 | 3 8 | 3 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/main/resources/db-online.properties: -------------------------------------------------------------------------------- 1 | instances=macim_master,macim_slave 2 | macim_master_url=jdbc:mysql://1.1.1.1/ttim 3 | macim_master_port=1 4 | macim_master_username=1 5 | macim_master_password=1 6 | macim_slave_url=jdbc:mysql://1.1.1.1/macim 7 | macim_master_port=1 8 | macim_slave_username=1 9 | macim_slave_password=1 10 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/Test.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | public class Test { 4 | 5 | public static void main(String[] args) { 6 | // TODO Auto-generated method stub 7 | String str = "2345678965435678908765467890"; 8 | MoguHttp.uploadAudioByteFile("http://122.225.68.125:8001/", str.getBytes()); 9 | } 10 | 11 | } 12 | -------------------------------------------------------------------------------- /src/main/resources/db-dev.properties: -------------------------------------------------------------------------------- 1 | instances=macim_master,macim_slave 2 | # macim master库 3 | macim_master_url=jdbc:mysql://1.1.1.1/ttim 4 | macim_master_port=1 5 | macim_master_username=1 6 | macim_master_password=1 7 | # macim slave库 8 | macim_slave_url=jdbc:mysql://1.1.1.1/ttim 9 | macim_master_port=1 10 | macim_slave_username=1 11 | macim_slave_password=1 12 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/filter/LoginFilter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.filter; 2 | 3 | /** 4 | * 5 | * @Description: 登陆请求的过滤处理 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2013-7-21 下午3:36:31 8 | * 9 | */ 10 | public class LoginFilter implements IFilter { 11 | 12 | @Override 13 | public void doFilter() { 14 | 15 | } 16 | 17 | 18 | } 19 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | java -server -Djava.ext.dirs=./ -Xmx2048M -Xms2048M -Xmn128M -XX:PermSize=64m -XX:MaxPermSize=128m -XX:+UseCompressedOops -XX:+UseParallelOldGC -verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC -XX:+PrintGCDetails -Xloggc:/tmp/mogutalk-gc.log -XX:+HeapDumpOnOutOfMemoryError -Djava.io.tmpdir=/tmp -XX:HeapDumpPath=/tmp/oom.heapdump -jar ./mogutalk-business-0.0.1-SNAPSHOT.jar $1 > mogutalk.log & 2 | echo $! > ./mogutalk.pid 3 | -------------------------------------------------------------------------------- /src/main/resources/cache-online.properties: -------------------------------------------------------------------------------- 1 | instances=counter,unread,group_counter,business 2 | counter_host=1.1.1.1 3 | counter_port=1 4 | counter_db=0 5 | #未读消息计数器的redis 6 | unread_host=1.1.1.1 7 | unread_port=1 8 | unread_db=1 9 | 10 | #群消息计数,未读消息和总计数都在这里 11 | group_counter_host=1.1.1.1 12 | group_counter_port=1 13 | group_counter_db=1 14 | 15 | #IM 业务 cache 16 | business_host=1.1.1.1 17 | business_port=1 18 | business_db=1 19 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/filter/MessageContentFilter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.filter; 2 | 3 | /** 4 | * 5 | * @Description: 消息内容相关请求的过滤处理 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2013-7-21 下午3:36:51 8 | * 9 | */ 10 | public class MessageContentFilter implements IFilter { 11 | 12 | @Override 13 | public void doFilter() { 14 | // TODO Auto-generated method stub 15 | 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/resources/cache-dev.properties: -------------------------------------------------------------------------------- 1 | instances=counter,unread,group_counter,business 2 | #消息计数器的redis 3 | counter_host=1.1.1.1 4 | counter_port=1 5 | counter_db=0 6 | #未读消息计数器的redis 7 | unread_host=1.1.1.1 8 | unread_port=1 9 | unread_db=1 10 | 11 | #群消息计数,未读消息和总计数都在这里 12 | group_counter_host=1.1.1.1 13 | group_counter_port=1 14 | group_counter_db=1 15 | 16 | #IM 业务 cache 17 | business_host=1.1.1.1 18 | business_port=1 19 | business_db=1 20 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/ServerConfig.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import com.mogujie.ares.extend.BaseAction; 4 | import com.mogujie.ares.lib.net.DataBuffer; 5 | import com.mogujie.ares.model.ServerConfigModel; 6 | 7 | /** 8 | * 9 | * @Description: 处理服务端配置的请求. 10 | * @author zuoye - zuoye[at]mogujie.com 11 | * @date 2013-11-5 12 | * 13 | */ 14 | public class ServerConfig extends BaseAction { 15 | } 16 | -------------------------------------------------------------------------------- /startup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | t=`date +%Y%m%d_%H%M%S` 4 | cp src/main/bin/* ./ 5 | ALLPROTS=($@) 6 | for port in ${ALLPROTS[@]} 7 | do 8 | file="./${port}" 9 | if [ -d "$file" ] ; then 10 | if [ ! -d "backup" ] ; then 11 | mkdir "backup" 12 | fi 13 | bak="backup/${port}_${t}" 14 | mv $file $bak 15 | fi 16 | mkdir $port 17 | cd $port 18 | cp ../target/mogutalk-business-0.0.1-SNAPSHOT.jar ./ 19 | cp ../run.sh ./ 20 | sh run.sh $port 21 | cd ../ 22 | done 23 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/IDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import org.jboss.netty.channel.ChannelHandlerContext; 4 | import org.jboss.netty.channel.MessageEvent; 5 | 6 | /** 7 | * 8 | * @ClassName: IDispatcher 9 | * @Description: 请求分发的接口 10 | * @author ziye - ziye(at)mogujie.com 11 | * @date 2013-7-20 下午5:55:47 12 | * 13 | */ 14 | public interface IDispatcher { 15 | 16 | public void dispatch(ChannelHandlerContext context, MessageEvent e); 17 | 18 | } 19 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/timer/ConfigureReloadTask.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.timer; 2 | 3 | import com.mogujie.ares.lib.logger.Logger; 4 | import com.mogujie.ares.lib.logger.LoggerFactory; 5 | 6 | /** 7 | * 8 | * @Description: 配置实时更新的类 9 | * @author shitou - shitou[at]mogujie.com 10 | * @date 2013-7-22 下午2:54:08 11 | * 12 | */ 13 | public class ConfigureReloadTask implements Runnable 14 | { 15 | private Logger logger = LoggerFactory.getLogger(ConfigureReloadTask.class); 16 | @Override 17 | public void run() 18 | { 19 | //重载所有的配置 20 | //ConfigureManager.getInstance().reloadAllConfigs(); 21 | logger.info("Hello World"); 22 | } 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/logger/NoneFilteredLoggerFilter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.logger; 2 | 3 | import ch.qos.logback.classic.spi.ILoggingEvent; 4 | import ch.qos.logback.core.filter.Filter; 5 | import ch.qos.logback.core.spi.FilterReply; 6 | 7 | /** 8 | * 9 | * @Description: 为过滤的一些通用日志的过滤器 10 | * @author ziye - ziye[at]mogujie.com 11 | * @date 2013-7-21 下午3:38:53 12 | * 13 | */ 14 | public class NoneFilteredLoggerFilter extends Filter { 15 | 16 | @Override 17 | public FilterReply decide(ILoggingEvent event) { 18 | 19 | if (event.getMessage().contains("[LoggerFilter:")) { 20 | return FilterReply.DENY; 21 | } else { 22 | return FilterReply.ACCEPT; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/model/ServerConfigModel.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.model; 2 | 3 | /* 4 | * 5 | * @Description: 服务配置相关操作 6 | * @author zuoye - zuoye[at]mogujie.com 7 | * @date 2013-11-5 8 | * 9 | */ 10 | public class ServerConfigModel { 11 | 12 | private static ServerConfigModel configModelInstance; 13 | 14 | public static ServerConfigModel getInstance() { 15 | if (configModelInstance == null) { 16 | configModelInstance = new ServerConfigModel(); 17 | } 18 | return configModelInstance; 19 | } 20 | 21 | private ServerConfigModel() { 22 | } 23 | 24 | public String getSensitivityWord() throws Exception { 25 | return ""; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/logger/ConnectionKeepAliveFilter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.logger; 2 | 3 | import ch.qos.logback.classic.spi.ILoggingEvent; 4 | import ch.qos.logback.core.filter.Filter; 5 | import ch.qos.logback.core.spi.FilterReply; 6 | 7 | /** 8 | * 9 | * @Description: heartbeat 之类和连接相关的日志过滤器 10 | * @author ziye - ziye[at]mogujie.com 11 | * @date 2013-7-21 下午3:37:45 12 | * 13 | */ 14 | public class ConnectionKeepAliveFilter extends Filter { 15 | 16 | @Override 17 | public FilterReply decide(ILoggingEvent event) { 18 | 19 | if (event.getMessage().contains("[LoggerFilter:Connection-Keep-alive]")) { 20 | return FilterReply.ACCEPT; 21 | } else { 22 | return FilterReply.DENY; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/Monitor.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import com.mogujie.ares.extend.BaseAction; 4 | import com.mogujie.ares.lib.logger.Logger; 5 | import com.mogujie.ares.lib.logger.LoggerFactory; 6 | import com.mogujie.ares.lib.net.DataBuffer; 7 | 8 | public class Monitor extends BaseAction { 9 | 10 | @SuppressWarnings("unused") 11 | private static final Logger logger = LoggerFactory.getLogger(Monitor.class); 12 | 13 | /** 14 | * 15 | * @Description: heartbeat 16 | * @param clientAddress 17 | * @return 18 | */ 19 | public DataBuffer heartbeat(String clientAddress, int version) { 20 | DataBuffer dataBuffer = new DataBuffer(0); 21 | return dataBuffer; // 不用返回 22 | } 23 | } -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/IMHttpResponse.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | /** 4 | * 5 | * @Description: http返回值 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2014-3-9 下午10:21:08 8 | * 9 | */ 10 | public class IMHttpResponse { 11 | private int statusCode; 12 | private String responseBody; 13 | 14 | public int getStatusCode() { 15 | return statusCode; 16 | } 17 | 18 | public void setStatusCode(int statusCode) { 19 | this.statusCode = statusCode; 20 | } 21 | 22 | public String getResponseBody() { 23 | return responseBody; 24 | } 25 | 26 | public void setResponseBody(String responseBody) { 27 | this.responseBody = responseBody; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "IMHttpResponse [statusCode=" + statusCode + ", responseBody=" 33 | + responseBody + "]"; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/MoguHttpResponse.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | /** 4 | * 5 | * @Description: http返回值 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2014-3-9 下午10:21:08 8 | * 9 | */ 10 | public class MoguHttpResponse { 11 | private int statusCode; 12 | private String responseBody; 13 | 14 | public int getStatusCode() { 15 | return statusCode; 16 | } 17 | 18 | public void setStatusCode(int statusCode) { 19 | this.statusCode = statusCode; 20 | } 21 | 22 | public String getResponseBody() { 23 | return responseBody; 24 | } 25 | 26 | public void setResponseBody(String responseBody) { 27 | this.responseBody = responseBody; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "IMHttpResponse [statusCode=" + statusCode + ", responseBody=" 33 | + responseBody + "]"; 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/util/MoguByteUtil.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.util; 2 | 3 | public class MoguByteUtil { 4 | 5 | private static MoguByteUtil instance = new MoguByteUtil(); 6 | 7 | public static MoguByteUtil getInstance() 8 | { 9 | if(instance == null) 10 | { 11 | synchronized(instance) { 12 | instance = new MoguByteUtil(); 13 | } 14 | } 15 | return instance; 16 | } 17 | 18 | public int convert2Int(byte[] bytes) { 19 | return (((int)bytes[0]) << 24) + (((int)bytes[1]) << 16) + (((int)bytes[2]) << 8) + bytes[3]; 20 | } 21 | 22 | public byte[] getBytes(int value) { 23 | byte[] bytes = new byte[4]; 24 | bytes[0] = (byte)(value >>> 24);//取最高8位放到0下标 25 | bytes[1] = (byte)(value >>> 16);//取次高8为放到1下标 26 | bytes[2] = (byte)(value >>> 8); //取次低8位放到2下标 27 | bytes[3] = (byte)(value ); //取最低8位放到3下标 28 | return bytes; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/logger/LoggerFactory.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.logger; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | import java.util.concurrent.ConcurrentMap; 5 | // ziye copy from mdl-common 6 | public class LoggerFactory { 7 | 8 | private static final ConcurrentMap loggers = new ConcurrentHashMap(); 9 | 10 | public static Logger getLogger(Class key) { 11 | Logger logger = loggers.get(key.getName()); 12 | if (logger == null) { 13 | loggers.putIfAbsent(key.getName(), new Logger(key)); 14 | logger = loggers.get(key.getName()); 15 | } 16 | return logger; 17 | } 18 | 19 | public static Logger getLogger(String key) { 20 | Logger logger = loggers.get(key); 21 | if (logger == null) { 22 | loggers.putIfAbsent(key, new Logger(key)); 23 | logger = loggers.get(key); 24 | } 25 | return logger; 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Counter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | import java.util.Map; 4 | 5 | /** 6 | * 7 | * @ClassName: Counter 8 | * @Description: 计数器描述类 9 | * @author shitou - shitou(at)mogujie.com 10 | * @date 2013-7-20 下午5:52:24 11 | * 12 | */ 13 | public class Counter 14 | { 15 | 16 | public int userId; 17 | 18 | public Map unreadCount; 19 | 20 | public Map msgCount; 21 | 22 | public void setUserId(int setUserId) 23 | { 24 | userId = setUserId; 25 | } 26 | 27 | public int getUserId() 28 | { 29 | return userId; 30 | } 31 | 32 | public void setUnreadCount(MapunreadMap) 33 | { 34 | unreadCount = unreadMap; 35 | } 36 | 37 | public Map getUnreadCount() 38 | { 39 | return unreadCount; 40 | } 41 | 42 | public void setMsgCount(MapsetMsgCount) 43 | { 44 | msgCount = setMsgCount; 45 | } 46 | 47 | public Map getMsgCount() 48 | { 49 | return msgCount; 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/util/MoguArrayUtil.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.util; 2 | 3 | import java.util.HashSet; 4 | import java.util.Set; 5 | 6 | public class MoguArrayUtil { 7 | 8 | private static MoguArrayUtil instance = new MoguArrayUtil(); 9 | 10 | public static MoguArrayUtil getInstance() 11 | { 12 | if(instance == null) 13 | { 14 | synchronized(instance) { 15 | instance = new MoguArrayUtil(); 16 | } 17 | } 18 | return instance; 19 | } 20 | 21 | 22 | public int[] arrayUnique(int[] intArray) { 23 | Set intSet = new HashSet(); 24 | int intVal; 25 | int length = intArray.length; 26 | for(int i = 0; i < length; i++) { 27 | intVal = intArray[i]; 28 | if(!intSet.contains(intVal)) { 29 | intSet.add(intVal); 30 | } 31 | } 32 | Integer[] uniqArray = new Integer[intSet.size()]; 33 | intSet.toArray(uniqArray); 34 | int[] ints = new int[uniqArray.length]; 35 | for(int i = 0; i < uniqArray.length; i++) { 36 | ints[i] = uniqArray[i]; 37 | } 38 | return ints; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/GroupCounterItem.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | public class GroupCounterItem { 4 | 5 | private int userId; 6 | 7 | private int groupId; 8 | 9 | private int groupTotalCount; // 群总消息数 10 | 11 | private int userUnreadCount; // 用户在该群中的未读消息数 12 | 13 | private int lastMessageId; 14 | 15 | public int getUserId() { 16 | return userId; 17 | } 18 | 19 | public void setUserId(int userId) { 20 | this.userId = userId; 21 | } 22 | 23 | public int getGroupId() { 24 | return groupId; 25 | } 26 | 27 | public void setGroupId(int groupId) { 28 | this.groupId = groupId; 29 | } 30 | 31 | public int getGroupTotalCount() { 32 | return groupTotalCount; 33 | } 34 | 35 | public void setGroupTotalCount(int groupTotalCount) { 36 | this.groupTotalCount = groupTotalCount; 37 | } 38 | 39 | public int getUserUnreadCount() { 40 | return userUnreadCount; 41 | } 42 | 43 | public void setUserUnreadCount(int userUnreadCount) { 44 | this.userUnreadCount = userUnreadCount; 45 | } 46 | 47 | public int getLastMessageId() { 48 | return lastMessageId; 49 | } 50 | 51 | public void setLastMessageId(int lastMessageId) { 52 | this.lastMessageId = lastMessageId; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Relationship.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | /** 4 | * 5 | * @ClassName: Relationship 6 | * @Description: 好友关系 7 | * @author ziye - ziye(at)mogujie.com 8 | * @date 2013-7-20 下午5:50:10 9 | * 10 | */ 11 | public class Relationship { 12 | 13 | private int relateId; 14 | 15 | private int userId; 16 | 17 | private int friendUserId; 18 | 19 | private int status; 20 | 21 | private int created; 22 | 23 | private int updated; 24 | 25 | public int getRelateId() { 26 | return relateId; 27 | } 28 | 29 | public void setRelateId(int relateId) { 30 | this.relateId = relateId; 31 | } 32 | 33 | public int getUserId() { 34 | return userId; 35 | } 36 | 37 | public void setUserId(int userId) { 38 | this.userId = userId; 39 | } 40 | 41 | public int getFriendUserId() { 42 | return friendUserId; 43 | } 44 | 45 | public void setFriendUserId(int friendUserId) { 46 | this.friendUserId = friendUserId; 47 | } 48 | 49 | public int getStatus() { 50 | return status; 51 | } 52 | 53 | public void setStatus(int status) { 54 | this.status = status; 55 | } 56 | 57 | public int getCreated() { 58 | return created; 59 | } 60 | 61 | public void setCreated(int created) { 62 | this.created = created; 63 | } 64 | 65 | public int getUpdated() { 66 | return updated; 67 | } 68 | 69 | public void setUpdated(int updated) { 70 | this.updated = updated; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Audio.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | public class Audio { 4 | 5 | private int id; 6 | 7 | private int userId; 8 | 9 | private int toUserId; 10 | 11 | private String path; 12 | 13 | private int fileSize; 14 | 15 | private int costTime; 16 | 17 | private int created; 18 | 19 | private byte[] data; 20 | 21 | public int getId() { 22 | return id; 23 | } 24 | 25 | public void setId(int id) { 26 | this.id = id; 27 | } 28 | 29 | public String getPath() { 30 | return path; 31 | } 32 | 33 | public void setPath(String path) { 34 | this.path = path; 35 | } 36 | 37 | public int getUserId() { 38 | return userId; 39 | } 40 | 41 | public void setUserId(int userId) { 42 | this.userId = userId; 43 | } 44 | 45 | public int getToUserId() { 46 | return toUserId; 47 | } 48 | 49 | public void setToUserId(int toUserId) { 50 | this.toUserId = toUserId; 51 | } 52 | 53 | public int getFileSize() { 54 | return fileSize; 55 | } 56 | 57 | public void setFileSize(int fileSize) { 58 | this.fileSize = fileSize; 59 | } 60 | 61 | public int getCostTime() { 62 | return costTime; 63 | } 64 | 65 | public void setCostTime(int costTime) { 66 | this.costTime = costTime; 67 | } 68 | 69 | public int getCreated() { 70 | return created; 71 | } 72 | 73 | public void setCreated(int created) { 74 | this.created = created; 75 | } 76 | 77 | public byte[] getData() { 78 | return data; 79 | } 80 | 81 | public void setData(byte[] data) { 82 | this.data = data; 83 | } 84 | 85 | 86 | } 87 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/StatisticsContent.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.sql.SQLException; 4 | 5 | import com.mogujie.ares.extend.BaseAction; 6 | import com.mogujie.ares.lib.logger.Logger; 7 | import com.mogujie.ares.lib.logger.LoggerFactory; 8 | import com.mogujie.ares.model.StatisticsModel; 9 | 10 | public class StatisticsContent extends BaseAction{ 11 | @SuppressWarnings("unused") 12 | private static final Logger logger = LoggerFactory.getLogger(StatisticsContent.class); 13 | 14 | //userId 15 | public void saveLog(int soure,int protocol,String ip,int userId,int actionType,String os,String userAgent,String flashVersion,String clientVersion,int version){ 16 | /* 17 | * C++ =>Java 18 | * source: web1. 19 | protocol: 2 20 | ip: 3707387924 21 | userId: 1000000 22 | os: Mac ox x 23 | userAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36 24 | flash: 9.0.1 flashplayer 版本号 25 | client: 3.14 as或客户端息的版本号. 26 | */ 27 | 28 | /* logger.info("saveLog soure=" + soure 29 | + ", protocol=" + protocol + ", ip=" + ip 30 | + ", userId=" + userId+", actionType=" + actionType+ ", os=" + os+ ", userAgent=" + userAgent+ ", flashVersion=" + flashVersion+ ", clientVersion=" + clientVersion); 31 | */ 32 | try { 33 | StatisticsModel.getInstance().saveLog(soure, protocol, ip,actionType, userId, os, userAgent, flashVersion, clientVersion); 34 | } catch (SQLException e) { 35 | e.printStackTrace(); 36 | } 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/FileManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import com.mogujie.ares.configure.BizConstants; 6 | import com.mogujie.ares.lib.logger.Logger; 7 | import com.mogujie.ares.lib.logger.LoggerFactory; 8 | import com.mogujie.ares.lib.net.MoguHttp; 9 | 10 | public class FileManager { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(FileManager.class); 13 | private static FileManager instance = new FileManager(); 14 | 15 | private String audioUploadUrl = BizConstants.URL_FILE_UPLOAD; // 文件上传路径 16 | 17 | private String audioDownloadUrl = BizConstants.URL_FILE_DOWNLOAD; // 文件下载路径 18 | 19 | public static FileManager getInstance() 20 | { 21 | if(instance == null) 22 | { 23 | instance = new FileManager(); 24 | } 25 | return instance; 26 | } 27 | 28 | /** 29 | * 30 | * @Description: 返回音频文件 31 | * @param bytes 32 | * @param userId 33 | * @return 34 | */ 35 | public String saveAudioBinary(byte[] bytes) { 36 | 37 | if(bytes == null || bytes.length == 0) { 38 | return ""; 39 | } 40 | 41 | String fileName = MoguHttp.uploadByteFile(this.audioUploadUrl, bytes); 42 | logger.info("保存语音文件成功:" + fileName); 43 | 44 | return fileName; 45 | } 46 | 47 | /** 48 | * 49 | * @Description: 从磁盘读取一个文件 50 | * @param fileName 51 | * @return 52 | */ 53 | public byte[] readAudioBinary(String fileName) { 54 | if(StringUtils.isEmpty(fileName)) { 55 | return null; 56 | } 57 | byte[] bytes = MoguHttp.downloadByteFile(this.audioDownloadUrl + fileName); 58 | 59 | return bytes; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/GroupRelation.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | /** 4 | * 5 | * @Description: 群-用户关系 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2014-1-5 下午4:17:37 8 | * 9 | */ 10 | public class GroupRelation { 11 | 12 | private int id; 13 | 14 | private int groupId; 15 | 16 | private int userId; 17 | 18 | private int title; 19 | 20 | private int groupType; 21 | 22 | private int status; 23 | 24 | private int created; 25 | 26 | private int updated; 27 | 28 | public int getId() { 29 | return id; 30 | } 31 | 32 | public void setId(int id) { 33 | this.id = id; 34 | } 35 | 36 | public int getGroupId() { 37 | return groupId; 38 | } 39 | 40 | public void setGroupId(int groupId) { 41 | this.groupId = groupId; 42 | } 43 | 44 | public int getUserId() { 45 | return userId; 46 | } 47 | 48 | public void setUserId(int userId) { 49 | this.userId = userId; 50 | } 51 | 52 | public int getTitle() { 53 | return title; 54 | } 55 | 56 | public void setTitle(int title) { 57 | this.title = title; 58 | } 59 | 60 | public int getGroupType() { 61 | return groupType; 62 | } 63 | 64 | public void setGroupType(int groupType) { 65 | this.groupType = groupType; 66 | } 67 | 68 | public int getStatus() { 69 | return status; 70 | } 71 | 72 | public void setStatus(int status) { 73 | this.status = status; 74 | } 75 | 76 | public int getCreated() { 77 | return created; 78 | } 79 | 80 | public void setCreated(int created) { 81 | this.created = created; 82 | } 83 | 84 | public int getUpdated() { 85 | return updated; 86 | } 87 | 88 | public void setUpdated(int updated) { 89 | this.updated = updated; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/GroupMessage.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | public class GroupMessage { 4 | 5 | 6 | // 消息id 7 | private int id; 8 | 9 | private int userId; 10 | 11 | private User userInfo; 12 | 13 | private int groupId; 14 | 15 | private Group groupInfo; 16 | 17 | private String content; 18 | 19 | private int status; 20 | 21 | private int updated; 22 | 23 | private int created; 24 | 25 | public int getId() { 26 | return id; 27 | } 28 | 29 | public void setId(int id) { 30 | this.id = id; 31 | } 32 | 33 | public int getUserId() { 34 | return userId; 35 | } 36 | 37 | public void setUserId(int userId) { 38 | this.userId = userId; 39 | } 40 | 41 | public User getUserInfo() { 42 | return userInfo; 43 | } 44 | 45 | public void setUserInfo(User userInfo) { 46 | this.userInfo = userInfo; 47 | } 48 | 49 | public int getGroupId() { 50 | return groupId; 51 | } 52 | 53 | public void setGroupId(int groupId) { 54 | this.groupId = groupId; 55 | } 56 | 57 | public Group getGroupInfo() { 58 | return groupInfo; 59 | } 60 | 61 | public void setGroupInfo(Group groupInfo) { 62 | this.groupInfo = groupInfo; 63 | } 64 | 65 | public String getContent() { 66 | return content; 67 | } 68 | 69 | public void setContent(String content) { 70 | this.content = content; 71 | } 72 | 73 | public int getStatus() { 74 | return status; 75 | } 76 | 77 | public void setStatus(int status) { 78 | this.status = status; 79 | } 80 | 81 | public int getUpdated() { 82 | return updated; 83 | } 84 | 85 | public void setUpdated(int updated) { 86 | this.updated = updated; 87 | } 88 | 89 | public int getCreated() { 90 | return created; 91 | } 92 | 93 | public void setCreated(int created) { 94 | this.created = created; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/FileManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import org.apache.commons.lang.StringUtils; 4 | 5 | import com.mogujie.ares.configure.BizConstants; 6 | import com.mogujie.ares.lib.logger.Logger; 7 | import com.mogujie.ares.lib.logger.LoggerFactory; 8 | import com.mogujie.ares.lib.net.MoguHttp; 9 | 10 | public class FileManager { 11 | 12 | private static final Logger logger = LoggerFactory.getLogger(FileManager.class); 13 | private static FileManager instance = new FileManager(); 14 | 15 | private String audioUploadUrl = BizConstants.URL_FILE_UPLOAD; // 文件上传路径 16 | 17 | private String audioDownloadUrl = BizConstants.URL_FILE_DOWNLOAD; // 文件下载路径 18 | 19 | public static FileManager getInstance() 20 | { 21 | if(instance == null) 22 | { 23 | instance = new FileManager(); 24 | } 25 | return instance; 26 | } 27 | 28 | /** 29 | * 30 | * @Description: 返回音频文件 31 | * @param bytes 32 | * @param userId 33 | * @return 34 | */ 35 | public String saveAudioBinary(byte[] bytes) { 36 | 37 | if(bytes == null || bytes.length == 0) { 38 | return ""; 39 | } 40 | 41 | String fileName = MoguHttp.uploadAudioByteFile(this.audioUploadUrl, bytes); 42 | if(StringUtils.isEmpty(fileName)) { 43 | logger.info("保存语音文件失败"); 44 | } else { 45 | logger.info("保存语音文件成功:" + fileName); 46 | } 47 | return fileName; 48 | } 49 | 50 | /** 51 | * 52 | * @Description: 从磁盘读取一个文件 53 | * @param fileName 54 | * @return 55 | */ 56 | public byte[] readAudioBinary(String fileName) { 57 | if(StringUtils.isEmpty(fileName)) { 58 | return null; 59 | } 60 | String strDownloadUrl = this.audioDownloadUrl + fileName; 61 | logger.info("下载文件:" + strDownloadUrl); 62 | byte[] bytes = MoguHttp.downloadByteFile(strDownloadUrl); 63 | 64 | return bytes; 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ###项目背景 2 | 随着蘑菇街由导购向电商转型,蘑菇街自己的IM也应运而生,IM起初只是用于商家和 3 | 买家之间沟通的工具。后面我们问自己,既然已经有了用于客服的IM,为什么不自己 4 | 做一个IM,用于公司内部的沟通工具,来替换RTX呢,然后就有了TT(TeamTalk) 5 | 的雏形,现在蘑菇街内部的IM工具都是TT来完成的。随着TT的逐渐完善,我们再次 6 | 决定把TT开源,来回馈开源社区,我们希望国内的中小企业都能用上免费开源的 7 | IM内部沟通工具。 8 | 9 | ###系统环境 10 | 服务端平台: Linux 11 | 客户端平台: Windows,Mac, iOS, Android 12 | 13 | ###子系统分类 14 | 各个子系统的详细说明请参考子系统的README文档 15 | 16 | -TTPhpServer 17 | TT的Web后台管理服务器 18 | 19 | -TTCppServer 20 | TT的服务器,包括登陆分配,长连接接入,消息路由,文件传输, 21 | 文件存储等功能的支持 22 | 23 | -TTJavaServer 24 | TT的服务器,只要是作为TT服务器操作MySQL和Redis的代理服务器 25 | 26 | -TTWinClient 27 | Window客户端 28 | 29 | -TTMacClient 30 | Mac系统客户端 31 | 32 | -TTIOSClient 33 | iOS客户端 34 | 35 | -TTAndroidClient 36 | Android客户端 37 | 38 | ###编译安装 39 | 详见各自子系统的INSTALL文件 40 | 41 | ###开发流程 42 | 43 | 开发者流程 44 | 45 | - 开发者是指现在TeamTalk的开发人员,或者以后我们信任的贡献者转化而成的开发人员。 46 | 47 | - 要成为开发者,需要在github上注册账号, 然后由管理者加入到相应项目的collaborators列表 48 | 49 | - 开发主要用到master和develop两个分支, 平时开发都在develop分支上,只有代码 50 | 达到一个milestone的stable状态,才把develop分支merge到master分支 51 | 52 | - 有时开发者可能想实现一个比较cool的feature,可以建立一个feature_x分支, 53 | 测试稳定后merge到master 54 | 55 | 贡献者流程 56 | 57 | - 贡献者是指非TeamTalk项目组成员,热爱开源且希望为开源项目贡献代码的开发人员 58 | 59 | - 贡献者可以在github上Fork一个子项目,然后在Fork的项目上提交代码, 60 | 再通过Pull Request把修改通知给项目开发者,由开发者code review后, 61 | 决定是否merge进入master分支, 具体可参考: [github协作流程](http://www.worldhello.net/gotgithub/04-work-with-others/010-fork-and-pull.html) 62 | 63 | ###版本迭代流程 64 | - 版本迭代周期暂定为3个月 65 | - 开发者和贡献者可以把想要实现的feature通过github的wiki功能提交上来 66 | - 开始迭代前讨论本期版本要实现哪些feature,然后把要在本次迭代实现的featue列表写入版本的TODO feature list列表 67 | - 制定大概的排期 68 | - 开发,内部测试 69 | - alpha版本发布,公测 70 | - 把develop分支代码merge到master分支,stable版本发布 71 | 72 | ###开源协议 73 | [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0.html) 74 | 75 | ###Remark 76 | ![](https://raw.githubusercontent.com/mogutt/TTiOSClient/develop/pic/we-need-you.png) 77 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/Packet.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | /** 4 | * 5 | * @Description: 发送和接收的数据包 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2013-7-21 下午4:14:31 8 | * 9 | */ 10 | public class Packet { 11 | 12 | private int length; // 数据包长度,包括包头 13 | 14 | private int version; // 版本号 15 | 16 | private int flag; // 标记: 分拆数据包,压缩 17 | 18 | private int serviceId; // 服务号, 后端这边固定1000 19 | 20 | private int commandId; // 命令号, 标识服务接口, 21 | 22 | private int error; // 服务器错误 23 | 24 | private int reserved; // 保留,可用于如序列号等 25 | 26 | private DataBuffer contentBuffer; // 业务数据部分 27 | 28 | public int getLength() { 29 | return length; 30 | } 31 | 32 | public void setLength(int length) { 33 | this.length = length; 34 | } 35 | 36 | public int getVersion() { 37 | return version; 38 | } 39 | 40 | public void setVersion(int version) { 41 | this.version = version; 42 | } 43 | 44 | public int getFlag() { 45 | return flag; 46 | } 47 | 48 | public void setFlag(int flag) { 49 | this.flag = flag; 50 | } 51 | 52 | public int getServiceId() { 53 | return serviceId; 54 | } 55 | 56 | public void setServiceId(int serviceId) { 57 | this.serviceId = serviceId; 58 | } 59 | 60 | public int getCommandId() { 61 | return commandId; 62 | } 63 | 64 | public void setCommandId(int commandId) { 65 | this.commandId = commandId; 66 | } 67 | 68 | public int getError() { 69 | return error; 70 | } 71 | 72 | public void setError(int error) { 73 | this.error = error; 74 | } 75 | 76 | public int getReserved() { 77 | return reserved; 78 | } 79 | 80 | public void setReserved(int reserved) { 81 | this.reserved = reserved; 82 | } 83 | 84 | public DataBuffer getContentBuffer() { 85 | return contentBuffer; 86 | } 87 | 88 | public void setContentBuffer(DataBuffer contentBuffer) { 89 | this.contentBuffer = contentBuffer; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/logger/Logger.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.logger; 2 | // ziye copy from mdl-common 3 | public class Logger { 4 | 5 | private final org.slf4j.Logger logger; 6 | 7 | public Logger(Class key) { 8 | this.logger = org.slf4j.LoggerFactory.getLogger(key); 9 | } 10 | 11 | public Logger(String key) { 12 | this.logger = org.slf4j.LoggerFactory.getLogger(key); 13 | } 14 | 15 | private String appendContextMessage(String msg) { 16 | return "" + msg; 17 | } 18 | 19 | public void debug(String msg) { 20 | try { 21 | logger.debug(appendContextMessage(msg)); 22 | } catch (Throwable t) { 23 | } 24 | } 25 | 26 | public void debug(String msg, Throwable e) { 27 | try { 28 | logger.debug(appendContextMessage(msg), e); 29 | } catch (Throwable t) { 30 | } 31 | } 32 | 33 | public void info(String format, Object[] argArray){ 34 | try { 35 | logger.info(format,argArray); 36 | } catch (Throwable t) { 37 | } 38 | } 39 | 40 | public void info(String msg) { 41 | try { 42 | logger.info(appendContextMessage(msg)); 43 | } catch (Throwable t) { 44 | } 45 | } 46 | 47 | public void info(String msg, Throwable e) { 48 | try { 49 | logger.info(appendContextMessage(msg), e); 50 | } catch (Throwable t) { 51 | } 52 | } 53 | 54 | public void warn(String msg, Throwable e) { 55 | try { 56 | logger.warn(appendContextMessage(msg), e); 57 | } catch (Throwable t) { 58 | } 59 | } 60 | 61 | public void warn(String msg) { 62 | try { 63 | logger.warn(appendContextMessage(msg)); 64 | } catch (Throwable t) { 65 | } 66 | } 67 | 68 | public void error(String msg) { 69 | try { 70 | logger.error(appendContextMessage(msg)); 71 | } catch (Throwable t) { 72 | } 73 | } 74 | 75 | public void error(String msg, Throwable e) { 76 | try { 77 | logger.error(appendContextMessage(msg), e); 78 | } catch (Throwable t) { 79 | } 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/TransmitFile.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | /** 4 | * 5 | * @Description: 群信息 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2014-1-5 下午4:17:55 8 | * 9 | */ 10 | public class TransmitFile { 11 | 12 | private int id; 13 | 14 | private int fromUserId; // 发送人 15 | 16 | private int toUserId; // 接收人 17 | 18 | private String taskId = ""; //任务编号 19 | 20 | private String filePath = ""; // 文件路径 21 | 22 | private int fileSize; //文件大小. 23 | 24 | private int status; // 状态,是否已经被接收 25 | 26 | private int created; // 创建时间 27 | 28 | private int updated; // 更新时间 29 | 30 | public int getId() { 31 | return id; 32 | } 33 | 34 | public void setId(int id) { 35 | this.id = id; 36 | } 37 | 38 | public int getFromUserId() { 39 | return fromUserId; 40 | } 41 | 42 | public void setFromUserId(int fromUserId) { 43 | this.fromUserId = fromUserId; 44 | } 45 | 46 | public int getToUserId() { 47 | return toUserId; 48 | } 49 | 50 | public void setToUserId(int toUserId) { 51 | this.toUserId = toUserId; 52 | } 53 | 54 | public String getFilePath() { 55 | return filePath; 56 | } 57 | 58 | public void setFilePath(String filePath) { 59 | this.filePath = filePath; 60 | } 61 | 62 | public int getCreated() { 63 | return created; 64 | } 65 | 66 | public void setCreated(int created) { 67 | this.created = created; 68 | } 69 | 70 | public int getUpdated() { 71 | return updated; 72 | } 73 | 74 | public void setUpdated(int updated) { 75 | this.updated = updated; 76 | } 77 | 78 | public int getStatus() { 79 | return status; 80 | } 81 | 82 | public void setStatus(int status) { 83 | this.status = status; 84 | } 85 | 86 | public int getFileSize() { 87 | return fileSize; 88 | } 89 | 90 | public void setFileSize(int fileSize) { 91 | this.fileSize = fileSize; 92 | } 93 | 94 | public String getTaskId() { 95 | return taskId; 96 | } 97 | 98 | public void setTaskId(String taskId) { 99 | this.taskId = taskId; 100 | } 101 | 102 | 103 | } 104 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/configure/SysConstants.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.configure; 2 | 3 | 4 | public class SysConstants { 5 | 6 | // 服务器的默认端口,可以通过启动时的args来修改 7 | public static final int SERVER_DEFAULT_PORT = 11000; 8 | 9 | // 默认消息头的长度 10 | public static final int PROTOCOL_HEADER_LENGTH = 16; 11 | 12 | //packet的当前版本号,最新版本 13 | public static final int PROTOCOL_CURRENT_VERSION = 2; 14 | 15 | public static final int PROTOCOL_PREVIOUS_VERSION=1; //上一版本的版本号 16 | 17 | // 定时任务启动状态 18 | public static final String TASK_ENABLE_RUN = "1"; 19 | 20 | // 定时任务停止状态 21 | public static final String TASK_DISENABLE_RUN = "0"; 22 | 23 | //停止应用的检查时间 24 | public static final long CHECK_STOP_GAP_TIME = 2000; 25 | 26 | //停止实例配置文件 27 | public static final String ELEGANT_STOP_FILE = "/tmp/.mogutalk_stop"; 28 | 29 | public static final String ELEGANT_SHUTDOWN_SHELL_SCRIPT = "mogutalkshutdown"; 30 | 31 | //停止实例值 32 | public static final String ELEGANT_STOP_CONTENT = "stop"; 33 | 34 | // --------------- redis pool --------------- 35 | 36 | // 从数据库连接池中取得连接时,对其的有效性进行检查 37 | public static final boolean TEST_ON_BORROW = true; 38 | 39 | // 最大连接数 40 | public static final int MAX_ACTIVE = 36; 41 | 42 | // 最大闲置的连接数 43 | public static final int MAX_IDLE = 20; 44 | 45 | // 最小..... 46 | public static final int MIN_IDLE = 5; 47 | 48 | // 请求最长等待时间/毫秒 49 | public static final int MAX_WAIT = 1000; 50 | 51 | // 闲置时测试 52 | public static final boolean TEST_WHILE_IDLE = true; 53 | 54 | // redis db的名字 55 | public static final String REDIS_INSTANCE_NAME_COUNTER = "counter"; // 总消息计数器 56 | 57 | public static final String REDIS_INSTANCE_NAME_SESSION = "session"; // mogujie session 58 | 59 | public static final String REDIS_INSTANCE_NAME_UNREAD = "unread"; // 未读消息计数 60 | 61 | public static final String REDIS_CINFO_PREFIX_KEY="user_c_"; //redis cinfo的前缀key. 62 | 63 | public static final String REDIS_CINFO_SUB_KEY="chatNew"; //redis cinfo 子key 64 | 65 | // --------------- db pool ----------------- 66 | 67 | public static final int DB_MIN_CONNECTIONS_PER_PARTITION = 10; 68 | 69 | public static final int DB_MAX_CONNECTIONS_PER_PARTITION = 18; 70 | 71 | public static final int DB_IDLE_CONNECTION_TEST_PERIOD = 60; 72 | 73 | public static final int DB_PARTITION_COUNT = 1; 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Department.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | public class Department { 4 | 5 | protected int departId; // 部门id 6 | 7 | // protected String departName; // 部门名 8 | 9 | protected String title; // 部门标题 10 | 11 | protected String description; // 部门描述 12 | 13 | protected int parentDepartId; // 父部门id(上级部门id) 14 | 15 | protected int leader; // 部门leader 16 | 17 | protected int status; // 部门状态 0:正常 1:删除 18 | 19 | private int created; // 创建时间 20 | 21 | private int updated; // 更新时间 22 | 23 | public int getDepartId() { 24 | return departId; 25 | } 26 | 27 | public void setDepartId(int departId) { 28 | this.departId = departId; 29 | } 30 | 31 | // public String getDepartName() { 32 | // return departName; 33 | // } 34 | // 35 | // public void setDepartName(String departName) { 36 | // this.departName = departName; 37 | // } 38 | 39 | public String getTitle() { 40 | return title; 41 | } 42 | 43 | public void setTitle(String title) { 44 | this.title = title; 45 | } 46 | 47 | public String getDescription() { 48 | return description; 49 | } 50 | 51 | public void setDescription(String description) { 52 | this.description = description; 53 | } 54 | 55 | public int getParentDepartId() { 56 | return parentDepartId; 57 | } 58 | 59 | public void setParentDepartId(int parentDepartId) { 60 | this.parentDepartId = parentDepartId; 61 | } 62 | 63 | public int getLeader() { 64 | return leader; 65 | } 66 | 67 | public void setLeader(int leader) { 68 | this.leader = leader; 69 | } 70 | 71 | public int getStatus() { 72 | return status; 73 | } 74 | 75 | public void setStatus(int status) { 76 | this.status = status; 77 | } 78 | 79 | public int getCreated() { 80 | return created; 81 | } 82 | 83 | public void setCreated(int created) { 84 | this.created = created; 85 | } 86 | 87 | public int getUpdated() { 88 | return updated; 89 | } 90 | 91 | public void setUpdated(int updated) { 92 | this.updated = updated; 93 | } 94 | 95 | public Department() { 96 | // TODO Auto-generated constructor stub 97 | } 98 | 99 | } 100 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/ConfigureManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import java.util.HashMap; 4 | import java.util.Properties; 5 | import java.util.concurrent.ConcurrentHashMap; 6 | 7 | import com.mogujie.ares.configure.Configure; 8 | import com.mogujie.ares.configure.Router; 9 | import com.mogujie.ares.lib.logger.Logger; 10 | import com.mogujie.ares.lib.logger.LoggerFactory; 11 | /** 12 | * 13 | * @Description: 配置管理类, 单例 14 | * @author shitou - shitou[at]mogujie.com 15 | * @date 2013-7-22 上午11:15:23 16 | * 17 | */ 18 | public class ConfigureManager 19 | { 20 | 21 | public static final Logger logger = LoggerFactory.getLogger(ConfigureManager.class); 22 | 23 | private static ConfigureManager _configureManagerInstance = null; 24 | 25 | public static ConfigureManager getInstance() 26 | { 27 | if(_configureManagerInstance == null) 28 | { 29 | _configureManagerInstance = new ConfigureManager(); 30 | } 31 | return _configureManagerInstance; 32 | } 33 | 34 | private Configure configure; 35 | 36 | private ConfigureManager() 37 | { 38 | configure = new Configure(); 39 | } 40 | 41 | /** 42 | * 初始化配置,只在启动时调用 43 | */ 44 | public void initial() throws Exception 45 | { 46 | reloadAllConfigs(); 47 | } 48 | 49 | /** 50 | * db的配置 51 | * @return 52 | */ 53 | public Properties getDBConfig() 54 | { 55 | return configure.getDBConfig(); 56 | } 57 | 58 | /** 59 | * cache(redis)配置 60 | * @return 61 | */ 62 | public Properties getCacheConfig() 63 | { 64 | return configure.getCacheConfig(); 65 | } 66 | 67 | /** 68 | * 阿瑞斯系统配置 69 | * @return 70 | */ 71 | public Properties getSystemConfig() 72 | { 73 | return configure.getSystemConfig(); 74 | } 75 | 76 | public Router getActionRouter() { 77 | return configure.getActionRouter(); 78 | } 79 | 80 | /** 81 | * 计划任务脚本配置 82 | * @return 83 | */ 84 | public ConcurrentHashMap> getTimerConfig() 85 | { 86 | return configure.getTimerConfig(); 87 | } 88 | 89 | /** 90 | * 装载数据 91 | * @throws Exception 92 | */ 93 | public void loadAllConfigs() throws Exception 94 | { 95 | configure.loadConfigs(); 96 | } 97 | 98 | /** 99 | * 重新装载数据 100 | * @throws Exception 101 | */ 102 | public void reloadAllConfigs() throws Exception { 103 | loadAllConfigs(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/timer/WorkerInfoReloader.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.timer; 2 | 3 | /** 4 | * 5 | * @Description: 配置实时更新的类 6 | * @author shitou - shitou[at]mogujie.com 7 | * @date 2013-7-22 下午2:54:08 8 | * 9 | */ 10 | //public class WorkerInfoReloader implements Runnable { 11 | // private Logger logger = 12 | // LoggerFactory.getLogger(WorkerInfoReloader.class); 13 | // @Override 14 | // public void run() 15 | // { 16 | // logger.info("reload worker info"); 17 | // //重载所有的配置 18 | // boolean isSuccess = InternalDataModel.getInstance().refreshUserList(); 19 | // if(!isSuccess) { 20 | // logger.error("reload worker info list fail"); 21 | // } 22 | // logger.info("reload worker info list success"); 23 | // } 24 | 25 | // public void recorectData() { 26 | // List groupList = new ArrayList(); 27 | // DBManager dbManager = DBManager.getInstance(); 28 | // Connection conn = dbManager.getConnection(DBPoolName.macim_slave); 29 | // PreparedStatement statement = null; 30 | // ResultSet rs = null; 31 | // CounterModel cm = CounterModel.getInstance(); 32 | // try { 33 | // String sql = "select * from IMGroupRelation where " + 34 | // "status = 1 and groupType = 2 order by updated desc, id desc"; 35 | // statement = conn.prepareStatement(sql); 36 | // rs = statement.executeQuery(); 37 | // GroupRelation gr = null; 38 | // while(rs.next()) { 39 | // gr = new GroupRelation(); 40 | // gr.setGroupId(rs.getInt("groupId")); 41 | // gr.setUserId(rs.getInt("userId")); 42 | // groupList.add(gr); 43 | // } 44 | // int size = groupList.size(); 45 | // logger.info("size: " + size); 46 | // for(int i = 0; i < size; i++) { 47 | // gr = groupList.get(i); 48 | // Map grcnt = cm.getUserGroupUnreadCount(gr.getUserId(), 49 | // new int[]{gr.getGroupId()}); 50 | // GroupMessage[] gm = 51 | // MessageModel.getInstance().getGroupMessages(gr.getGroupId(), 0, 1); 52 | // logger.info("crt: " + gm[0].getCreated() + ", grcnt: " + grcnt); 53 | // if(gr.getUserId() == 9822376 && grcnt.get(gr.getGroupId()) > 0 && 54 | // gm[0].getCreated() > 1400752800) { 55 | // // cm.clearUserGroupCounter(gr.getUserId(), gr.getGroupId()); 56 | // logger.info("清除消息: userId = " + gr.getUserId() 57 | // + " , groupId = " + gr.getGroupId() + ", cnt=" + 58 | // grcnt.get(gr.getGroupId())); 59 | // } 60 | // } 61 | // } catch (SQLException e) { 62 | // logger.error("", e); 63 | // } finally { 64 | // dbManager.release(DBPoolName.macim_slave, conn, statement, rs); 65 | // } 66 | // } 67 | // } 68 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/storage/CachePool.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.storage; 2 | 3 | import com.mogujie.ares.configure.SysConstants; 4 | 5 | import redis.clients.jedis.Jedis; 6 | import redis.clients.jedis.JedisPool; 7 | import redis.clients.jedis.JedisPoolConfig; 8 | 9 | /** 10 | * 11 | * @Description: 缓存的连接池 12 | * @author shitou - shitou[at]mogujie.com 13 | * @date 2013-7-21 下午4:15:34 14 | * 15 | */ 16 | public class CachePool { 17 | 18 | private JedisPool pool = null; 19 | 20 | private JedisPoolConfig poolConfig = null; 21 | 22 | private String host; // 缓存的服务器 23 | private int port; // 端口 24 | private int db; // 连接到第几个db 25 | 26 | public CachePool(String host, Integer port, Integer db) 27 | { 28 | this.host = host; 29 | this.port = port; 30 | this.db = db; 31 | } 32 | 33 | /** 34 | * @Description: 初始化配置 35 | */ 36 | public void initialConfig() 37 | { 38 | if(poolConfig == null) 39 | { 40 | poolConfig = new JedisPoolConfig(); 41 | poolConfig.setTestOnBorrow(SysConstants.TEST_ON_BORROW); // 从数据库连接池中取得连接时,对其的有效性进行检查 42 | poolConfig.setMaxActive(SysConstants.MAX_ACTIVE); // 最大连接数 43 | poolConfig.setMaxIdle(SysConstants.MAX_IDLE); // 最大闲置的连接数 44 | poolConfig.setMinIdle(SysConstants.MIN_IDLE); // 最少 45 | poolConfig.setMaxWait(SysConstants.MAX_WAIT); // 请求最长等待时间/毫秒 46 | poolConfig.setTestWhileIdle(SysConstants.TEST_WHILE_IDLE); // 闲置时测试 47 | } 48 | } 49 | 50 | /** 51 | * 52 | * @Description: 初始化 53 | */ 54 | public void launch() 55 | { 56 | if(pool == null) 57 | { 58 | initialConfig(); 59 | pool = new JedisPool(poolConfig, this.host, this.port); 60 | } 61 | } 62 | 63 | /** 64 | * 65 | * @Description: 销毁 66 | */ 67 | public void destory() 68 | { 69 | if(pool != null) 70 | { 71 | pool.destroy(); 72 | } 73 | } 74 | 75 | /** 76 | * 77 | * @Description: 获得连接 78 | * @return redis的连接 79 | */ 80 | public Jedis getResource() 81 | { 82 | Jedis jedisInstance = null; 83 | if(pool != null) 84 | { 85 | jedisInstance = pool.getResource(); 86 | if(db > 0) 87 | { 88 | jedisInstance.select(db); 89 | } 90 | } 91 | return jedisInstance; 92 | } 93 | 94 | /** 95 | * 96 | * @Description: 释放连接 97 | * @param jedisInstance 98 | */ 99 | public void returnResource(Jedis jedisInstance) 100 | { 101 | pool.returnResource(jedisInstance); 102 | } 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/dispatch/DefaultRequestDispatcher.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.dispatch; 2 | 3 | import org.jboss.netty.channel.ChannelHandlerContext; 4 | import org.jboss.netty.channel.MessageEvent; 5 | 6 | import com.mogujie.ares.extend.ActionContext; 7 | import com.mogujie.ares.extend.ActionHolder; 8 | import com.mogujie.ares.lib.logger.Logger; 9 | import com.mogujie.ares.lib.logger.LoggerFactory; 10 | import com.mogujie.ares.lib.net.DataBuffer; 11 | import com.mogujie.ares.lib.net.IDispatcher; 12 | import com.mogujie.ares.lib.net.Packet; 13 | 14 | /** 15 | * 16 | * @Description: 默认的消息分发器,所有从BinaryMessageHandler传来的消息 17 | * 由这个类根据消息头的type分发到相应的Action 18 | * @author ziye - ziye[at]mogujie.com 19 | * @date 2013-7-21 上午11:21:34 20 | * 21 | */ 22 | public class DefaultRequestDispatcher implements IDispatcher { 23 | 24 | private static final Logger logger = LoggerFactory 25 | .getLogger(DefaultRequestDispatcher.class); 26 | 27 | private ActionHolder actionHolder; 28 | 29 | public DefaultRequestDispatcher(ActionHolder actionHolder) { 30 | this.actionHolder = actionHolder; 31 | } 32 | 33 | public ActionHolder getActionHolder() { 34 | return actionHolder; 35 | } 36 | 37 | public void setActionHolder(ActionHolder actionHolder) { 38 | this.actionHolder = actionHolder; 39 | } 40 | 41 | /** 42 | * 43 | * @Description: 消息分发函数,所有请求都由这个函数来分发 44 | * @param @param requestType 45 | * @param @return 46 | * @return ActionContext 47 | * @throws 48 | */ 49 | @Override 50 | public void dispatch(ChannelHandlerContext context, MessageEvent e) { 51 | 52 | Packet packet = (Packet) e.getMessage(); 53 | int type = packet.getCommandId(); 54 | 55 | ActionContext actionContext = actionHolder.get(type); // 取得请求对应的Action 56 | if (actionContext == null) { // 这里是有可能会返回null的 57 | logger.error("找不到指定的Action, type: " + type); 58 | return; 59 | } 60 | 61 | try { 62 | Object res = actionContext.invoke(context, packet); 63 | if (res != null) { 64 | actionContext.sendResponse(context, packet, (DataBuffer) res); // 发送结果 65 | } 66 | } catch (Exception e1) { // 如果出错了,临死前返回一个数据包给客户端... 67 | logger.error("commandId: " + packet.getCommandId(), e1); 68 | // actionContext.sendResponse(context, packet, new DataBuffer(0)); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/model/LoginModel.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.model; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | import com.alibaba.druid.util.StringUtils; 9 | import com.mogujie.ares.lib.logger.Logger; 10 | import com.mogujie.ares.lib.logger.LoggerFactory; 11 | import com.mogujie.ares.manager.DBManager; 12 | import com.mogujie.ares.manager.DBManager.DBPoolName; 13 | import com.mogujie.ares.util.MoguUtil; 14 | 15 | /* 16 | * @Description: 登陆相关的所有操作 17 | * @author shuchen - shuchen[at]mogujie.com 18 | * @date 2014-08-04 下午3:20:01 19 | */ 20 | public class LoginModel { 21 | private static LoginModel instance = new LoginModel(); 22 | private static final Logger logger = LoggerFactory 23 | .getLogger(LoginModel.class); 24 | 25 | public static LoginModel getInstance() { 26 | if (instance == null) { 27 | instance = new LoginModel(); 28 | } 29 | return instance; 30 | } 31 | 32 | private LoginModel() { 33 | 34 | } 35 | 36 | /* 37 | * 38 | * @Description: 登陆的验证接口,直接DB拉取已加密密码验证 39 | * 40 | * @param mogujieSession 41 | * 42 | * @return 43 | * 44 | * @throws Exception 45 | */ 46 | public boolean auth(String uname, String pwd) throws Exception { 47 | boolean isAuthed = false; // model层不做参数为空判断,会在action层做掉 48 | DBManager dbManager = DBManager.getInstance(); 49 | Connection conn = dbManager.getConnection(DBPoolName.macim_slave); 50 | PreparedStatement statement = null; 51 | ResultSet rs = null; 52 | try { 53 | String sql = "select pwd from IMUsers where uname = " 54 | + MoguUtil.getArgsHolder(1); 55 | statement = conn.prepareStatement(sql); 56 | statement.setString(1, uname); 57 | rs = statement.executeQuery(); 58 | String passwd = ""; 59 | while (rs.next()) { 60 | passwd = rs.getString("pwd"); 61 | logger.info("login: " + uname); 62 | if (!StringUtils.isEmpty(passwd) && passwd.equals(pwd)) { 63 | isAuthed = true; 64 | } 65 | } 66 | } catch (SQLException e) { 67 | throw e; 68 | } finally { 69 | dbManager.release(DBPoolName.macim_slave, conn, statement, rs); 70 | } 71 | return isAuthed; 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/BinaryMessageHandler.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import org.jboss.netty.channel.ChannelHandlerContext; 4 | import org.jboss.netty.channel.ChannelStateEvent; 5 | import org.jboss.netty.channel.MessageEvent; 6 | import org.jboss.netty.channel.SimpleChannelHandler; 7 | 8 | import com.mogujie.ares.lib.logger.Logger; 9 | import com.mogujie.ares.lib.logger.LoggerFactory; 10 | import com.mogujie.ares.manager.NetworkManager; 11 | 12 | /** 13 | * 14 | * @Description: netty接收数据的handler,所有请求都在这里接收并转发到dispatcher 15 | * @author ziye - ziye[at]mogujie.com 16 | * @date 2013-7-21 下午3:39:34 17 | * 18 | */ 19 | public class BinaryMessageHandler extends SimpleChannelHandler { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(BinaryMessageHandler.class); 22 | 23 | private IDispatcher dispatcher; 24 | 25 | public BinaryMessageHandler(IDispatcher dispatcher) { 26 | this.dispatcher = dispatcher; 27 | } 28 | 29 | /** 30 | * 客户端建立连接 31 | * (non-Javadoc) 32 | * @see org.jboss.netty.channel.SimpleChannelHandler#channelConnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) 33 | */ 34 | public void channelConnected(ChannelHandlerContext context, ChannelStateEvent e) 35 | throws Exception { 36 | String clientAddr = context.getChannel().getRemoteAddress().toString(); 37 | logger.info("[LoggerFilter:Connection-Keep-alive] client " + clientAddr + " Connected"); 38 | NetworkManager.getInstance().addClient(context); // 添加到现有客户端的列表里 39 | super.channelConnected(context, e); 40 | } 41 | 42 | /** 43 | * 收到数据的事件 44 | */ 45 | @Override 46 | public void messageReceived(ChannelHandlerContext context, MessageEvent e) 47 | throws Exception { 48 | try{ 49 | dispatcher.dispatch(context, e); 50 | } catch(Exception exception) { 51 | logger.error("dispatch error. ", exception); 52 | } 53 | } 54 | 55 | /** 56 | * 客户端断开连接 57 | * (non-Javadoc) 58 | * @see org.jboss.netty.channel.SimpleChannelHandler#channelDisconnected(org.jboss.netty.channel.ChannelHandlerContext, org.jboss.netty.channel.ChannelStateEvent) 59 | */ 60 | public void channelDisconnected(ChannelHandlerContext context, 61 | ChannelStateEvent e) throws Exception { 62 | String clientAddr = context.getChannel().getRemoteAddress().toString(); 63 | logger.info("[LoggerFilter:Connection-Keep-alive] client " + clientAddr + " Disconnected"); 64 | NetworkManager.getInstance().removeClient(context); // 从现有客户端列表里移除该连接 65 | super.channelDisconnected(context, e); 66 | } 67 | 68 | 69 | } 70 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Group.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * 7 | * @Description: 群信息 8 | * @author ziye - ziye[at]mogujie.com 9 | * @date 2014-1-5 下午4:17:55 10 | * 11 | */ 12 | public class Group { 13 | 14 | private int groupId; // 群Id 15 | 16 | private String groupName = ""; // 群名 17 | 18 | private String avatar = ""; // 群头像 19 | 20 | private String adesc = ""; // 群描述 21 | 22 | private int createUserId; // 创建者Id 23 | 24 | private int groupType; // 群类型 1:固定群 2:临时群 25 | 26 | private int status; // 群状态 1:正常 0: 删除 27 | 28 | private int memberCnt; // 群成员个数 29 | 30 | private List userIdList; 31 | 32 | private int updated; // 群信息更新时间 33 | 34 | private int created; // 群创建时间 35 | 36 | public int getGroupId() { 37 | return groupId; 38 | } 39 | 40 | public void setGroupId(int groupId) { 41 | this.groupId = groupId; 42 | } 43 | 44 | public String getGroupName() { 45 | return groupName; 46 | } 47 | 48 | public void setGroupName(String groupName) { 49 | this.groupName = groupName; 50 | } 51 | 52 | public String getAvatar() { 53 | return avatar; 54 | } 55 | 56 | public void setAvatar(String avatar) { 57 | this.avatar = avatar; 58 | } 59 | 60 | public String getAdesc() { 61 | return adesc; 62 | } 63 | 64 | public void setAdesc(String adesc) { 65 | this.adesc = adesc; 66 | } 67 | 68 | public int getCreateUserId() { 69 | return createUserId; 70 | } 71 | 72 | public void setCreateUserId(int createUserId) { 73 | this.createUserId = createUserId; 74 | } 75 | 76 | public int getGroupType() { 77 | return groupType; 78 | } 79 | 80 | public void setGroupType(int groupType) { 81 | this.groupType = groupType; 82 | } 83 | 84 | public int getMemberCnt() { 85 | return memberCnt; 86 | } 87 | 88 | public void setMemberCnt(int memberCnt) { 89 | this.memberCnt = memberCnt; 90 | } 91 | 92 | public int getStatus() { 93 | return status; 94 | } 95 | 96 | public void setStatus(int status) { 97 | this.status = status; 98 | } 99 | 100 | public int getUpdated() { 101 | return updated; 102 | } 103 | 104 | public void setUpdated(int updated) { 105 | this.updated = updated; 106 | } 107 | 108 | public int getCreated() { 109 | return created; 110 | } 111 | 112 | public void setCreated(int created) { 113 | this.created = created; 114 | } 115 | 116 | public List getUserIdList() { 117 | return userIdList; 118 | } 119 | 120 | public void setUserIdList(List userIdList) { 121 | this.userIdList = userIdList; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/model/DepartModel.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.model; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | import java.util.HashMap; 8 | import java.util.Map; 9 | 10 | import com.mogujie.ares.data.Department; 11 | import com.mogujie.ares.lib.logger.Logger; 12 | import com.mogujie.ares.lib.logger.LoggerFactory; 13 | import com.mogujie.ares.manager.DBManager; 14 | import com.mogujie.ares.manager.DBManager.DBPoolName; 15 | 16 | /* 17 | * @Description: 部门相关的model 18 | * @author ziye 19 | * 20 | */ 21 | public class DepartModel { 22 | 23 | private static DepartModel instance = new DepartModel(); 24 | @SuppressWarnings("unused") 25 | private final Logger logger = LoggerFactory.getLogger(DepartModel.class); 26 | 27 | public static DepartModel getInstance() { 28 | if (instance == null) { 29 | instance = new DepartModel(); 30 | } 31 | return instance; 32 | } 33 | 34 | /* 35 | * @Description: 获取所有部门信息 36 | * 37 | * @return Map 部门的具体信息Map 38 | * 39 | * @throws SQLException 40 | */ 41 | public Map getDepartmentInfo() throws SQLException { 42 | Map departInfos = new HashMap(); 43 | DBManager dbManager = DBManager.getInstance(); 44 | Connection conn = dbManager.getConnection(DBPoolName.macim_slave); 45 | PreparedStatement statement = null; 46 | ResultSet rs = null; 47 | try { 48 | String sql = "select * from IMDepartment where status = 0"; 49 | statement = conn.prepareStatement(sql); 50 | rs = statement.executeQuery(); 51 | Department department = null; 52 | int departId = 0; 53 | while (rs.next()) { 54 | department = new Department(); 55 | departId = rs.getInt("id"); 56 | department.setDepartId(departId); 57 | department.setTitle(rs.getString("title")); 58 | department.setLeader(rs.getInt("leader")); 59 | department.setParentDepartId(rs.getInt("pid")); 60 | department.setStatus(rs.getInt("status")); 61 | department.setDescription(rs.getString("desc")); 62 | departInfos.put(departId, department); 63 | } 64 | } catch (SQLException e) { 65 | throw e; 66 | } finally { 67 | dbManager.release(DBPoolName.macim_slave, conn, statement, rs); 68 | } 69 | return departInfos; 70 | } 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/Message.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | /** 4 | * 5 | * @ClassName: Message 6 | * @Description: 消息类 7 | * @author ziye - ziye(at)mogujie.com 8 | * @date 2013-7-20 下午5:50:36 9 | * 10 | */ 11 | public class Message { 12 | 13 | // 消息id 14 | private int id; 15 | 16 | // 发送和接收的用户之间的关系Id,以relationship表中用户id小的在前的记录Id作为两个人的关系id 17 | private int relateId; 18 | 19 | private int fromUserId; 20 | 21 | private User fromUser; 22 | 23 | private int toUserId; 24 | 25 | private User toUser; 26 | 27 | private int type; 28 | 29 | private String content; 30 | 31 | private Audio audio; 32 | 33 | private int isDeleted; 34 | 35 | private int updated; 36 | 37 | private int created; 38 | 39 | public int getId() { 40 | return id; 41 | } 42 | 43 | public void setId(int id) { 44 | this.id = id; 45 | } 46 | 47 | public int getRelateId() { 48 | return relateId; 49 | } 50 | 51 | public void setRelateId(int relateId) { 52 | this.relateId = relateId; 53 | } 54 | 55 | public int getFromUserId() { 56 | return fromUserId; 57 | } 58 | 59 | public void setFromUserId(int fromUserId) { 60 | this.fromUserId = fromUserId; 61 | } 62 | 63 | public int getToUserId() { 64 | return toUserId; 65 | } 66 | 67 | public void setToUserId(int toUserId) { 68 | this.toUserId = toUserId; 69 | } 70 | 71 | public int getType() { 72 | return type; 73 | } 74 | 75 | public void setType(int type) { 76 | this.type = type; 77 | } 78 | 79 | public String getContent() { 80 | return content; 81 | } 82 | 83 | public void setContent(String content) { 84 | this.content = content; 85 | } 86 | 87 | public int getIsDeleted() { 88 | return isDeleted; 89 | } 90 | 91 | public void setIsDeleted(int isDeleted) { 92 | this.isDeleted = isDeleted; 93 | } 94 | 95 | public int getUpdated() { 96 | return updated; 97 | } 98 | 99 | public void setUpdated(int updated) { 100 | this.updated = updated; 101 | } 102 | 103 | public int getCreated() { 104 | return created; 105 | } 106 | 107 | public void setCreated(int created) { 108 | this.created = created; 109 | } 110 | 111 | public User getFromUser() { 112 | return fromUser; 113 | } 114 | 115 | public void setFromUser(User fromUser) { 116 | this.fromUser = fromUser; 117 | } 118 | 119 | public User getToUser() { 120 | return toUser; 121 | } 122 | 123 | public void setToUser(User toUser) { 124 | this.toUser = toUser; 125 | } 126 | 127 | public Audio getAudio() { 128 | return audio; 129 | } 130 | 131 | public void setAudio(Audio audio) { 132 | this.audio = audio; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/FrameBinaryDecoder.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import org.jboss.netty.buffer.ChannelBuffer; 4 | import org.jboss.netty.buffer.ChannelBuffers; 5 | import org.jboss.netty.channel.Channel; 6 | import org.jboss.netty.channel.ChannelHandlerContext; 7 | import org.jboss.netty.handler.codec.frame.FrameDecoder; 8 | 9 | import com.mogujie.ares.configure.SysConstants; 10 | import com.mogujie.ares.lib.logger.Logger; 11 | import com.mogujie.ares.lib.logger.LoggerFactory; 12 | 13 | /** 14 | * 15 | * @Description: 数据包解析器 16 | * @author ziye - ziye[at]mogujie.com 17 | * @date 2013-7-21 下午3:44:58 18 | * 19 | */ 20 | public class FrameBinaryDecoder extends FrameDecoder { 21 | 22 | private static final Logger logger = LoggerFactory 23 | .getLogger(FrameBinaryDecoder.class); 24 | 25 | /** 26 | * 解析数据包,主要负责解析数据包前8个字节统一格式的头部信息,生成Packet对象, 剩余的数据部分的解析在后面具体的action处理 27 | */ 28 | @Override 29 | protected Object decode(ChannelHandlerContext ctx, Channel channel, 30 | ChannelBuffer buffer) throws Exception { 31 | 32 | if (buffer.readableBytes() < SysConstants.PROTOCOL_HEADER_LENGTH) { 33 | return null; 34 | } 35 | 36 | buffer.markReaderIndex(); // 标记一下 37 | int length = buffer.readInt(); // 消息长度 38 | char version = buffer.readChar(); // 消息version, 1个字节 39 | char flag = buffer.readChar(); // 标记: 分拆数据包,压缩 40 | char serviceId = buffer.readChar(); // 服务号, 后端这边固定1000 41 | char commandId = buffer.readChar(); // 命令号 42 | char error = buffer.readChar(); // 服务器错误 43 | char reserved = buffer.readChar(); // 保留,可用户如序列号等 44 | int contentLength = length - SysConstants.PROTOCOL_HEADER_LENGTH; // 计算数据包中业务数据部分的长度(去除头部长度16) 45 | 46 | if (buffer.readableBytes() < contentLength) { 47 | logger.info("数据长度:" + contentLength); 48 | buffer.resetReaderIndex(); // 返回到上面标记的位置 49 | return null; 50 | } 51 | 52 | ChannelBuffer cBuffer = ChannelBuffers.buffer(contentLength); 53 | buffer.readBytes(cBuffer, contentLength); // 转移所有业务部分的数据到新的byte 54 | 55 | Packet packet = new Packet(); 56 | packet.setLength(contentLength); 57 | packet.setVersion(version); 58 | packet.setFlag(flag); 59 | packet.setServiceId(serviceId); 60 | packet.setCommandId(commandId); 61 | packet.setError(error); 62 | packet.setReserved(reserved); 63 | DataBuffer dataBuffer = new DataBuffer(cBuffer); // 数据部分 64 | packet.setContentBuffer(dataBuffer); 65 | 66 | // logger.info("decode packet serviceId : " + packet.getServiceId() 67 | // + " commandId: " + packet.getCommandId()); 68 | return packet; 69 | } 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/MainServer.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares; 2 | 3 | import com.mogujie.ares.configure.SysConstants; 4 | import com.mogujie.ares.extend.action.DelayUpdateMonitor; 5 | import com.mogujie.ares.lib.logger.Logger; 6 | import com.mogujie.ares.lib.logger.LoggerFactory; 7 | import com.mogujie.ares.manager.CacheManager; 8 | import com.mogujie.ares.manager.ConfigureManager; 9 | import com.mogujie.ares.manager.DBManager; 10 | import com.mogujie.ares.manager.ElegantStopManager; 11 | import com.mogujie.ares.manager.NetworkManager; 12 | import com.mogujie.ares.manager.TimerManager; 13 | 14 | /** 15 | * 初始化阿瑞斯项目main类 16 | * @author ziye 17 | * 18 | */ 19 | public class MainServer { 20 | 21 | private static final Logger logger = LoggerFactory.getLogger(MainServer.class); 22 | 23 | public MainServer() { 24 | 25 | } 26 | 27 | public void bootup(int port) { 28 | try { 29 | initLog(); 30 | initConfigure(); 31 | initBase(); // 基础部分的启动,包括各种连接池 32 | initTimers(); 33 | initNet(port); 34 | startStopChecker(port); 35 | } catch (Exception e) { 36 | logger.error("", e); 37 | ElegantStopManager.getInstance(port).shutdown(); 38 | } 39 | } 40 | 41 | /** 42 | * 日志初始化 43 | */ 44 | public void initLog() { 45 | // 这里好像没什么好做的... 46 | } 47 | 48 | /** 49 | * 配置相关的初始化 50 | * @throws Exception 51 | */ 52 | public void initConfigure() throws Exception { 53 | ConfigureManager.getInstance().loadAllConfigs(); 54 | } 55 | 56 | /** 57 | * 包括lib内的连接池等的初始化 58 | * @throws Exception 59 | */ 60 | public void initBase() throws Exception { 61 | DBManager dbManager = DBManager.getInstance(); 62 | CacheManager cacheManager = CacheManager.getInstance(); 63 | if(dbManager == null || cacheManager == null) { 64 | throw new Exception("初始化db和cache连接池出错!"); 65 | } 66 | } 67 | 68 | /** 69 | * 网络初始化 70 | * @throws Exception 71 | */ 72 | public void initNet(int port) throws Exception { 73 | NetworkManager networkManager = NetworkManager.getInstance(); 74 | networkManager.init(port); 75 | } 76 | 77 | /** 78 | * 定时脚本启动 79 | * @throws Exception 80 | */ 81 | public void initTimers() throws Exception { 82 | TimerManager.getInstance().lanuch(); 83 | DelayUpdateMonitor.getInstance().start(); 84 | } 85 | 86 | /** 87 | * 启动结束Check是否结束程序的线程 88 | */ 89 | public void startStopChecker(int port) { 90 | ElegantStopManager.getInstance(port).startCheckShutdownThread(); 91 | } 92 | 93 | public static void main( String[] args ) { 94 | int port = SysConstants.SERVER_DEFAULT_PORT; 95 | if(args.length >= 1) { 96 | port = Integer.parseInt(args[0]); 97 | } 98 | MainServer server = new MainServer(); 99 | server.bootup(port); 100 | } 101 | 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/Login.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import com.alibaba.druid.util.StringUtils; 4 | import com.mogujie.ares.data.User; 5 | import com.mogujie.ares.extend.BaseAction; 6 | import com.mogujie.ares.lib.logger.Logger; 7 | import com.mogujie.ares.lib.logger.LoggerFactory; 8 | import com.mogujie.ares.lib.net.DataBuffer; 9 | import com.mogujie.ares.model.LoginModel; 10 | import com.mogujie.ares.model.UserModel; 11 | import com.mogujie.ares.util.MoguUtil; 12 | 13 | /* 14 | * @Description: 用户登陆相关的请求 15 | * @author ziye - ziye[at]mogujie.com 16 | * @date 2013-7-21 下午1:28:17 17 | */ 18 | public class Login extends BaseAction { 19 | 20 | private static final Logger logger = LoggerFactory.getLogger(Login.class); 21 | 22 | /* 23 | * @Description: 用户登陆 24 | * 25 | * @param userId 用户Id 26 | * 27 | * @param token 登陆用户请求蘑菇街主站的http://www.mogujie.com/aresapi/login接口来获得 28 | * 29 | * @return 30 | */ 31 | public DataBuffer login(String uname, String pwd, DataBuffer attachment, 32 | int version) { 33 | logger.info("login: " + uname); 34 | int resultCode = 0; 35 | boolean isAuthed = false; 36 | User user = null; 37 | if (StringUtils.isEmpty(uname)) { 38 | resultCode = 1; 39 | } 40 | 41 | UserModel userModel = UserModel.getInstance(); 42 | try { 43 | isAuthed = LoginModel.getInstance().auth(uname, pwd); 44 | if (isAuthed) { 45 | user = userModel.getUserInfo(uname); 46 | } else { 47 | logger.info("login failed with error password!"); 48 | } 49 | } catch (Exception e) { 50 | logger.error("login failed with reason : ", e); 51 | isAuthed = false; 52 | } 53 | isAuthed = (isAuthed && (user != null)); // 用户要存在 54 | resultCode = (isAuthed ? 0 : 1); // 0: 成功,1: 失败 55 | DataBuffer buffer = new DataBuffer(); 56 | buffer.writeString(uname);// 用户名 57 | buffer.writeInt(resultCode); 58 | if (isAuthed) { 59 | buffer.writeInt(user.getUserId()); // 用户ID 60 | buffer.writeString(user.getUnick()); // 用户昵称 61 | buffer.writeString(user.getAvatar()); // 用户头像 62 | buffer.writeString(user.getTitle()); // 用户职称 63 | buffer.writeString(user.getPosition()); // 用户地址 64 | buffer.writeInt(user.getStatus()); // 用户在职等状态 65 | buffer.writeInt(user.getSex()); // 用户性别 66 | buffer.writeInt(user.getDepartId()); // 用户所在部门ID 67 | buffer.writeInt(user.getJobNumber()); // 用户工号 68 | buffer.writeString(user.getTelphone()); // 用户电话 69 | buffer.writeString(user.getMail()); // 用户邮箱 70 | logger.info("login success: " + uname + ", " + resultCode); 71 | } else { 72 | logger.info("login error: " + uname + ", " + resultCode); 73 | } 74 | 75 | return MoguUtil.writeAttachments(buffer, attachment); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/main/resources/logback.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | System.out 7 | 8 | %d{HH:mm:ss.SSS} [%p] [%c] - %m%n 9 | 10 | 11 | INFO 12 | 13 | 14 | 15 | true 16 | logs/mogutalk.log 17 | 18 | logs/%d{yyyyMMdd}/mogutalk.log 19 | 60 20 | 21 | 22 | %d{HH:mm:ss.SSS} [%p] [%c] - %m%n 23 | 24 | 25 | INFO 26 | 27 | 28 | 29 | true 30 | logs/mogutalk-error.log 31 | 32 | logs/%d{yyyyMMdd}/mogutalk-error.log 33 | 60 34 | 35 | 36 | %d{HH:mm:ss.SSS} [%p] [%c] - %m%n 37 | 38 | 39 | ERROR 40 | 41 | 42 | 43 | true 44 | logs/mogutalk-nonefiltered.log 45 | 46 | logs/%d{yyyyMMdd}/mogutalk-nonefiltered.log 47 | 60 48 | 49 | 50 | %d{HH:mm:ss.SSS} [%p] [%c] - %m%n 51 | 52 | 53 | 54 | 55 | 56 | true 57 | logs/mogutalk-connection.log 58 | 59 | logs/%d{yyyyMMdd}/mogutalk-connection.log 60 | 60 61 | 62 | 63 | %d{HH:mm:ss.SSS} [%p] [%c] - %m%n 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/model/StatisticsModel.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.model; 2 | 3 | import java.net.InetAddress; 4 | import java.net.UnknownHostException; 5 | import java.sql.Connection; 6 | import java.sql.PreparedStatement; 7 | import java.sql.SQLException; 8 | 9 | import com.mogujie.ares.manager.DBManager; 10 | import com.mogujie.ares.manager.DBManager.DBPoolName; 11 | 12 | /* 13 | * @Description: 统计模块处理. 14 | * @author zuoye@mogujie.com 15 | */ 16 | public class StatisticsModel { 17 | private static StatisticsModel instance = new StatisticsModel(); 18 | 19 | public static StatisticsModel getInstance() { 20 | if (instance == null) { 21 | instance = new StatisticsModel(); 22 | } 23 | return instance; 24 | } 25 | 26 | public void saveLog(int soure, int protocol, String ip, int type, 27 | int userId, String os, String userAgent, String flashVersion, 28 | String clientVersion) throws SQLException { 29 | DBManager dbManager = DBManager.getInstance(); 30 | Connection conn = dbManager.getConnection(DBPoolName.macim_master); 31 | PreparedStatement statement = null; 32 | try { 33 | String sql = " insert into IMLogging (source,protocol,ip,type,userId,os,userAgent,flash,client,created) values(?,?,?,?,?,?,?,?,?,?)"; 34 | statement = conn.prepareStatement(sql); 35 | int index = 1; 36 | statement.setObject(index++, soure); 37 | statement.setObject(index++, protocol); 38 | statement.setObject(index++, ip2long(ip)); 39 | statement.setObject(index++, type); 40 | statement.setObject(index++, userId); 41 | statement.setObject(index++, os); 42 | statement.setObject(index++, userAgent); 43 | statement.setObject(index++, flashVersion); 44 | statement.setObject(index++, clientVersion); 45 | statement.setObject(index++, System.currentTimeMillis() / 1000); 46 | statement.executeUpdate(); 47 | } catch (SQLException e) { 48 | throw e; 49 | } finally { 50 | dbManager.release(DBPoolName.macim_master, conn, statement, null); 51 | } 52 | } 53 | 54 | public long ip2long(String ip) { 55 | int ipNum = 0; 56 | try { 57 | ipNum = str2Ip(ip); 58 | } catch (UnknownHostException e) { 59 | e.printStackTrace(); 60 | } 61 | return int2long(ipNum); 62 | } 63 | 64 | public long int2long(int i) { 65 | long l = i & 0x7fffffffL; 66 | if (i < 0) { 67 | l |= 0x080000000L; 68 | } 69 | return l; 70 | } 71 | 72 | public int str2Ip(String ip) throws UnknownHostException { 73 | InetAddress address = InetAddress.getByName(ip);// 在给定主机名的情况下确定主机的 IP 址。 74 | byte[] bytes = address.getAddress();// 返回此 InetAddress 对象的原始 IP 地址 75 | int a, b, c, d; 76 | a = byte2int(bytes[0]); 77 | b = byte2int(bytes[1]); 78 | c = byte2int(bytes[2]); 79 | d = byte2int(bytes[3]); 80 | int result = (a << 24) | (b << 16) | (c << 8) | d; 81 | return result; 82 | } 83 | 84 | public int byte2int(byte b) { 85 | int l = b & 0x07f; 86 | if (b < 0) { 87 | l |= 0x80; 88 | } 89 | return l; 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/timer/Timer.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.timer; 2 | 3 | import java.util.Properties; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.ScheduledExecutorService; 6 | import java.util.concurrent.ScheduledFuture; 7 | import java.util.concurrent.TimeUnit; 8 | 9 | import com.mogujie.ares.manager.ConfigureManager; 10 | 11 | /** 12 | * 13 | * @Description: 定时器,实际上就是一个ScheduledExecutorService的封装类 14 | * @author shitou - shitou[at]mogujie.com 15 | * @date 2013-7-22 下午2:55:21 16 | * 17 | */ 18 | public class Timer 19 | { 20 | private Properties systemProperties; 21 | 22 | private ScheduledExecutorService schedulerService; // 线程池 23 | 24 | private boolean isLaunch = false; 25 | 26 | private static Timer timerInstance = new Timer(); 27 | 28 | public static Timer getInstance() 29 | { 30 | if(timerInstance == null) 31 | { 32 | timerInstance = new Timer(); 33 | } 34 | return timerInstance; 35 | } 36 | 37 | private Timer() 38 | { 39 | systemProperties = ConfigureManager.getInstance().getSystemConfig(); 40 | launch(); 41 | } 42 | 43 | // 初始化配置 44 | private void launch() 45 | { 46 | if( ! isLaunch && schedulerService == null) 47 | { 48 | schedulerService = Executors.newScheduledThreadPool( 49 | Integer.valueOf(systemProperties.getProperty("task_initialize_pool"))); 50 | } 51 | } 52 | 53 | /** 54 | * 55 | * @Description: 启动一个只运行一次的任务 56 | * @param task 57 | * @param delay 等待delay时间之后再执行 58 | * @param unit 59 | * @return 60 | */ 61 | public ScheduledFuture submitOneShotTask(Runnable task, long delay, TimeUnit unit) 62 | { 63 | ScheduledFuture scheduler = schedulerService.schedule(task, delay, unit); 64 | return scheduler; 65 | } 66 | 67 | /** 68 | * 69 | * @Description: 启动一个固定延迟周期执行的脚本, 70 | * 指上一次执行结束之后延迟period时间之后再执行 71 | * 如initialDelay = 1; delay = 3; unit = second; 执行时间固定需要2秒 72 | * 从time=0开始执行的时间应该是1, 6, 11, 16.... 73 | * @param task 74 | * @param initialDelay 75 | * @param period 76 | * @param unit 77 | * @return 78 | */ 79 | public ScheduledFuture submitFixedRateTask(Runnable task, long initialDelay, long period, TimeUnit unit) 80 | { 81 | ScheduledFuture scheduler = schedulerService.scheduleAtFixedRate(task, initialDelay, period, unit); 82 | return scheduler; 83 | } 84 | 85 | /** 86 | * 87 | * @Description: 启动一个固定周期执行的脚本,不管上一个任务执行多久, 88 | * 下一个任务都是在上一个开始执行的delay时间之后执行 89 | * 如initialDelay = 1; delay = 3; unit = second; 执行时间固定需要2秒 90 | * 从time=0开始执行的时间应该是1, 4, 7, 10.... 91 | * @param task 92 | * @param initialDelay 93 | * @param delay 94 | * @param unit 95 | * @return 96 | */ 97 | public ScheduledFuture submitFixedDelayTask(Runnable task, long initialDelay, long delay, TimeUnit unit) 98 | { 99 | ScheduledFuture scheduler = schedulerService.scheduleWithFixedDelay(task, initialDelay, delay, unit); 100 | return scheduler; 101 | } 102 | 103 | /** 104 | * @Description: 关闭所有任务 105 | */ 106 | public void shutDown() 107 | { 108 | if(schedulerService != null) 109 | { 110 | schedulerService.shutdown(); 111 | } 112 | } 113 | 114 | /** 115 | * @Description: 关闭所有任务 116 | */ 117 | public void shutDownNow() 118 | { 119 | if(schedulerService != null) 120 | { 121 | schedulerService.shutdownNow(); 122 | } 123 | } 124 | 125 | 126 | } -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/configure/BizConstants.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.configure; 2 | 3 | /** 4 | * 5 | * @Description: 业务相关的常量定义 6 | * @author ziye - ziye[at]mogujie.com 7 | * @date 2013-9-7 下午1:11:34 8 | * 9 | */ 10 | public class BizConstants { 11 | 12 | // 默认的serviceId 13 | public static final int DEFAULT_SERVICEID = 7; // 与C++端通信的ID 14 | 15 | // ---------------- 消息类型的常量定义 ------------------ 16 | 17 | public static final int COMMANDID_HEARTBEAT = 1; // 心跳包的commandId 18 | 19 | public static final int COMMANDID_STOP_RECEIVE = 100; // 停止的commandId 20 | 21 | public static final int COMMANDID_SEND_MESSAGE = 111; // 发送消息的commandId 22 | 23 | // ---------------- 用户角色定义 ---------------- 24 | 25 | public static final int ROLE_NORMAL_USER = 0; // normal user 26 | 27 | public static final int ROLE_SERVICE_USER = 1; // admin user 28 | 29 | // ---------------- 用户信息默认值 --------------- 30 | 31 | public static final String USER_INFO_DEFAULT_AVATAR = "/avatar/avatar_default.jpg"; // 默认用户头像 32 | 33 | public static final String GROUP_INFO_DEFAULT_AVATAR = "/avatar/group_avatar_default.jpg"; // 默认群组头像 34 | 35 | // URL 36 | public static final String URL_FILE_UPLOAD = "http://1.1.1.1:1/"; // 上传文件 37 | 38 | public static final String URL_FILE_DOWNLOAD = "http://1.1.1.1:1/"; // 下载文件 39 | 40 | // ---------------- 消息 ------------------- 41 | // 消息里图片的占位符 42 | public static final String MESSAGE_IMAGE_PREFIX = "image_prefix_&%@##@%*^$%{:{}}"; 43 | public static final String MESSAGE_IMAGE_SUFFIX = "image_suffix_*^&%#{:{}}"; 44 | public static final String Message_IMAGE_URL_REGEX = "(http://)?s\\d{1,2}"; 45 | public static final String MESSAGE_IMAGE_FULL_PLACEHOLDER_REGEX = "(&\\$#@~\\^@\\[\\{:)" 46 | + "((http[s]?://)?s\\d{1,2}\\.ttim\\.(org))(/pic/\\d{6}/[0-9a-z_]{30,40}\\d{1,10}x\\d{1,10}.*" 47 | + ":\\}\\]&\\$~@#@)"; // 图片占位符的正则表达式 48 | public static final String MESSAGE_IMAGE_PART_PLACEHOLDER_REGEX = "(&\\$#@~\\^@\\[\\{:)" 49 | + "(/pic/\\d{6}/[0-9a-z_]{30,40}\\d{1,10}x\\d{1,10}.*" 50 | + ":\\}\\]&\\$~@#@)"; // 图片占位符的正则表达式 51 | 52 | // ------------ IM消息的type ------------ 53 | public static final int MESSAGE_TYPE_IM = 1; // 普通用户+系统消息 54 | public static final int MESSAGE_TYPE_IM_AUDIO = 2; 55 | public static final int MESSAGE_TYPE_IM_GROUP = 17; 56 | public static final int MESSAGE_TYPE_IM_GROUP_AUDIO = 18; 57 | 58 | // 群组 59 | public static final String GROUP_TOTAL_MSG_COUNTER_REDIS_KEY_SUFFIX = "_group_msg"; // GROUP_TOTAL_MSG_COUNTER_REDIS_KEY_SUFFIX 60 | 61 | // {userId} + "_" + {groupId} + GROUP_USER_MSG_COUNTER_REDIS_KEY_SUFFIX 62 | public static final String GROUP_USER_MSG_COUNTER_REDIS_KEY_SUFFIX = "_user_group"; 63 | 64 | // hashtable里的两个subkey 65 | public static final String GROUP_COUNTER_SUBKEY_COUNTER = "count"; 66 | public static final String GROUP_COUNTER_SUBKEY_LASTID = "lastId"; 67 | 68 | public static final int GROUP_UNREAD_MAX_COUNTER = 150; // 用户一次读取未读群消息不能超过200 69 | 70 | public static final int GROUP_TYPE_FIXED = 1; 71 | 72 | public static final int GROUP_TYPE_TEMP = 2; 73 | 74 | public static final int UNREAD_MAX_COUNTER = 100; // 用户一次读取未读消息不能超过100 75 | 76 | // ------------- 服务号小T --------------- 77 | public static final int SYS_SERVER_USER_ID = 10000; 78 | public static final String SYS_SERVER_USER_NAME = "小T"; 79 | 80 | } 81 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/Dashboard.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.lang.management.ManagementFactory; 4 | 5 | import com.mogujie.ares.extend.BaseAction; 6 | import com.mogujie.ares.lib.net.DataBuffer; 7 | import com.sun.management.OperatingSystemMXBean; 8 | 9 | @SuppressWarnings("restriction") 10 | public class Dashboard extends BaseAction { 11 | 12 | private PerformanceMonitor cpuMonitor; 13 | 14 | public Dashboard() { 15 | // Create CPU monitoring class 16 | cpuMonitor = new PerformanceMonitor(); 17 | cpuMonitor.getCpuUsage(); // Set baseline 18 | } 19 | 20 | public DataBuffer getServerStatus(int version) { 21 | 22 | DataBuffer buffer = new DataBuffer(); 23 | 24 | // system info 25 | double cpu = roundToDecimals(cpuMonitor.getCpuUsage() * 100, 2); 26 | long freeMem = Runtime.getRuntime().freeMemory(); 27 | long maxMem = Runtime.getRuntime().maxMemory(); 28 | long totalMem = Runtime.getRuntime().totalMemory(); 29 | 30 | buffer.writeDouble(cpu); 31 | buffer.writeLong(freeMem); 32 | buffer.writeLong(maxMem); 33 | buffer.writeLong(totalMem); 34 | 35 | // threads list 36 | long totalThreadsCpuTime = 0; 37 | long[] threadIds = ManagementFactory.getThreadMXBean() 38 | .getAllThreadIds(); 39 | 40 | buffer.writeInt(threadIds.length); // 多少条线程. 41 | for (int i = 0; i < threadIds.length; i++) { 42 | long id = threadIds[i]; 43 | String name = ManagementFactory.getThreadMXBean().getThreadInfo(id) 44 | .getThreadName(); 45 | long cpuTime = 0; 46 | if (ManagementFactory.getThreadMXBean().isThreadCpuTimeSupported() 47 | && ManagementFactory.getThreadMXBean() 48 | .isThreadCpuTimeEnabled()) { 49 | cpuTime = ManagementFactory.getThreadMXBean().getThreadCpuTime( 50 | id); 51 | totalThreadsCpuTime += cpuTime; 52 | } 53 | buffer.writeLong(id); 54 | buffer.writeString(name); 55 | buffer.writeLong(cpuTime); 56 | } 57 | 58 | buffer.writeLong(totalThreadsCpuTime); 59 | 60 | return buffer; 61 | } 62 | 63 | private static double roundToDecimals(double d, int c) { 64 | int temp = (int) ((d * Math.pow(10, c))); 65 | return (double) (temp / Math.pow(10, c)); 66 | } 67 | 68 | private class PerformanceMonitor { 69 | private long lastSystemTime = 0; 70 | private long lastProcessCpuTime = 0; 71 | OperatingSystemMXBean osMxBean = (OperatingSystemMXBean) ManagementFactory 72 | .getOperatingSystemMXBean(); 73 | 74 | public synchronized double getCpuUsage() { 75 | if (lastSystemTime == 0) { 76 | baselineCounters(); 77 | return 0; 78 | } 79 | 80 | long systemTime = System.nanoTime(); 81 | long processCpuTime = osMxBean.getProcessCpuTime(); 82 | 83 | double cpuUsage = (double) (processCpuTime - lastProcessCpuTime) 84 | / (systemTime - lastSystemTime); 85 | 86 | lastSystemTime = systemTime; 87 | lastProcessCpuTime = processCpuTime; 88 | 89 | return cpuUsage / osMxBean.getAvailableProcessors(); 90 | } 91 | 92 | private void baselineCounters() { 93 | lastSystemTime = System.nanoTime(); 94 | lastProcessCpuTime = osMxBean.getProcessCpuTime(); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/ActionContext.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend; 2 | 3 | import java.lang.reflect.Method; 4 | 5 | import org.jboss.netty.channel.ChannelHandlerContext; 6 | 7 | import com.mogujie.ares.extend.filter.IFilter; 8 | import com.mogujie.ares.lib.net.DataBuffer; 9 | import com.mogujie.ares.lib.net.Packet; 10 | 11 | 12 | /** 13 | * 14 | * @Description: Action的描述类 15 | * @author ziye - ziye[at]mogujie.com 16 | * @date 2013-7-22 下午4:45:28 17 | * 18 | */ 19 | public class ActionContext { 20 | 21 | private BaseAction action; // Action对象Object 22 | 23 | private Method doMethod; // 处理业务的方法 24 | 25 | private RequestParams requestParams; // 请求参数控制器 26 | 27 | private int requestType; // 请求头的type 28 | 29 | private int defaultResponseType; // 默认响应的type 30 | 31 | private IFilter[] filters; // 过滤器们 32 | 33 | public BaseAction getAction() { 34 | return action; 35 | } 36 | 37 | public void setAction(BaseAction action) { 38 | this.action = action; 39 | } 40 | 41 | public Method getDoMethod() { 42 | return doMethod; 43 | } 44 | 45 | public void setDoMethod(Method doMethod) { 46 | this.doMethod = doMethod; 47 | } 48 | 49 | public RequestParams getRequestParams() { 50 | return requestParams; 51 | } 52 | 53 | public void setRequestParams(RequestParams requestParams) { 54 | this.requestParams = requestParams; 55 | } 56 | 57 | public int getRequestType() { 58 | return requestType; 59 | } 60 | 61 | public void setRequestType(int requestType) { 62 | this.requestType = requestType; 63 | } 64 | 65 | public int getDefaultResponseType() { 66 | return defaultResponseType; 67 | } 68 | 69 | public void setDefaultResponseType(int defaultResponseType) { 70 | this.defaultResponseType = defaultResponseType; 71 | } 72 | 73 | public IFilter[] getFilters() { 74 | return filters; 75 | } 76 | 77 | public void setFilters(IFilter[] filters) { 78 | this.filters = filters; 79 | } 80 | 81 | public Object invoke(ChannelHandlerContext context, Packet packet) throws Exception { 82 | // 解析请求的参数 83 | Object[] params = decode(packet.getContentBuffer(), context, this,packet.getVersion()); 84 | 85 | 86 | /* 87 | * 1.确定哪些处理器类是需要处理兼容版本的. 88 | * 2.需要兼容版本的多传一个请求过来的版本号. 89 | * 3.根据版本号.分别作相应的处理. 90 | 91 | 92 | if(action.isCompatibility()){ //需要考虑版本兼容性. 93 | Object[] newParams = new Object[params.length+1]; 94 | System.arraycopy(params, 0, newParams, 0, params.length); 95 | newParams[params.length]=packet.getVersion(); 96 | } 97 | */ 98 | 99 | return doMethod.invoke(action, params); // 调用 100 | } 101 | 102 | /** 103 | * 104 | * @Description: 数据包的解析,一个单纯的代理方法 105 | * @param dataBuffer 106 | * @param context 107 | * @return 108 | * @throws Exception 109 | */ 110 | public Object[] decode(DataBuffer dataBuffer, ChannelHandlerContext context, ActionContext actionContext,int version) throws Exception { 111 | return requestParams.decode(dataBuffer, context, actionContext,version); 112 | } 113 | 114 | // 发送消息 115 | public void sendResponse(ChannelHandlerContext context, Packet packet, DataBuffer responseBuffer) { 116 | Packet message = new Packet(); 117 | message.setVersion(packet.getVersion()); 118 | message.setFlag(packet.getFlag()); 119 | message.setServiceId(packet.getServiceId()); 120 | message.setCommandId(defaultResponseType); 121 | message.setError(packet.getError()); 122 | message.setReserved(packet.getReserved()); 123 | if(responseBuffer == null) { 124 | responseBuffer = new DataBuffer(0); 125 | } 126 | message.setContentBuffer(responseBuffer); 127 | 128 | context.getChannel().write(message); 129 | } 130 | } -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/data/User.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.data; 2 | 3 | /** 4 | * 5 | * @ClassName: User 6 | * @Description: 用户对象描述类 7 | * @author ziye - ziye(at)mogujie.com 8 | * @date 2013-7-20 下午5:49:23 9 | * 10 | */ 11 | public class User { 12 | 13 | protected int userId; // 用户id 14 | 15 | protected String uname; // 用户名 16 | 17 | protected String unick; // 用户昵称 18 | 19 | protected String avatar; // 用户头像 20 | 21 | protected String title; // 职务 22 | 23 | protected String position; // 地址,为什么不是address? 24 | 25 | protected int status; // 用户在职状态 0:正常(在职) 1:删除(离职) 可扩展 26 | 27 | protected int sex; // 性别 28 | 29 | protected int userType = 0; // 即identity,用户身份标识, 0-普通用户 1-管理员 30 | 31 | private int departId; // 部门id 32 | 33 | private int jobNumber; // 工号 34 | 35 | private String telphone; // 电话 36 | 37 | private String mail; // 邮箱 38 | 39 | private int created; // 创建时间 40 | 41 | private int updated; // 更新时间 42 | 43 | public int getUserId() { 44 | return userId; 45 | } 46 | 47 | public void setUserId(int userId) { 48 | this.userId = userId; 49 | } 50 | 51 | public String getUname() { 52 | return uname; 53 | } 54 | 55 | public void setUname(String uname) { 56 | this.uname = uname; 57 | } 58 | 59 | public String getAvatar() { 60 | return avatar; 61 | } 62 | 63 | public void setAvatar(String avatar) { 64 | this.avatar = avatar; 65 | } 66 | 67 | public int getDepartId() { 68 | return departId; 69 | } 70 | 71 | public void setDepartId(int departId) { 72 | this.departId = departId; 73 | } 74 | 75 | public String getUnick() { 76 | return unick; 77 | } 78 | 79 | public void setUnick(String unick) { 80 | this.unick = unick; 81 | } 82 | 83 | public String getTelphone() { 84 | return telphone; 85 | } 86 | 87 | public void setTelphone(String telphone) { 88 | this.telphone = telphone; 89 | } 90 | 91 | public int getCreated() { 92 | return created; 93 | } 94 | 95 | public void setCreated(int created) { 96 | this.created = created; 97 | } 98 | 99 | public int getUpdated() { 100 | return updated; 101 | } 102 | 103 | public void setUpdated(int updated) { 104 | this.updated = updated; 105 | } 106 | 107 | public int getSex() { 108 | return sex; 109 | } 110 | 111 | public void setSex(int sex) { 112 | this.sex = sex; 113 | } 114 | 115 | public String getTitle() { 116 | return title; 117 | } 118 | 119 | public void setTitle(String title) { 120 | this.title = title; 121 | } 122 | 123 | public String getPosition() { 124 | return position; 125 | } 126 | 127 | public void setPosition(String position) { 128 | this.position = position; 129 | } 130 | 131 | public int getStatus() { 132 | return status; 133 | } 134 | 135 | public void setStatus(int status) { 136 | this.status = status; 137 | } 138 | 139 | public int getUserType() { 140 | return userType; 141 | } 142 | 143 | public void setUserType(int user_type) { 144 | this.userType = user_type; 145 | } 146 | 147 | public int getJobNumber() { 148 | return jobNumber; 149 | } 150 | 151 | public void setJobNumber(int jobNumber) { 152 | this.jobNumber = jobNumber; 153 | } 154 | 155 | /** 156 | * @return the mail 157 | */ 158 | public String getMail() { 159 | return mail; 160 | } 161 | 162 | /** 163 | * @param mail 164 | * the mail to set 165 | */ 166 | public void setMail(String mail) { 167 | this.mail = mail; 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/ActionHolder.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend; 2 | 3 | import java.lang.reflect.Method; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | 9 | import com.mogujie.ares.configure.Router; 10 | import com.mogujie.ares.configure.Router.ActionDescricptor; 11 | import com.mogujie.ares.extend.filter.IFilter; 12 | 13 | /** 14 | * 15 | * @Description: 16 | * action的集合,在系统初始化的时候会把所有的action都初始化一遍, 17 | * 缓存在这里,每个Action用一个ActionItem描述 18 | * ps: 这个类只在系统初始化的时候有修改,而且是单线程的, 19 | * 后面多线程的都是读操作,不用做并发控制 20 | * @author ziye - ziye[at]mogujie.com 21 | * @date 2013-7-22 下午4:22:55 22 | * 23 | */ 24 | public class ActionHolder { 25 | 26 | /** 27 | * key: 请求头上的type 28 | * value: 具体action的描述ActionItem 29 | */ 30 | private Map actionMap = new HashMap(); 31 | 32 | private Map actionObjectMap = new HashMap(); 33 | 34 | public ActionHolder() { 35 | } 36 | 37 | /** 38 | * 39 | * @Description: 根据请求的type获得相应的ActionItem 40 | * @param type 41 | * @return 42 | */ 43 | public ActionContext get(int type) { 44 | return actionMap.get(type); 45 | } 46 | 47 | /** 48 | * 49 | * @Description: 把一个Router里的所有的Action加入到Action中 50 | * @param router 51 | * @throws Exception 52 | */ 53 | public void put(Router router) throws Exception { 54 | if(router == null) { return ; } 55 | Map actionDescMap = router.getActionMap(); 56 | if(actionDescMap == null || actionDescMap.isEmpty()) { return ; } 57 | 58 | Iterator> it = actionDescMap.entrySet().iterator(); 59 | ActionDescricptor actionDesc = null; 60 | while(it.hasNext()) { 61 | Entry entry = it.next(); 62 | actionDesc = entry.getValue(); 63 | put(actionDesc); 64 | } 65 | } 66 | 67 | /** 68 | * 69 | * @Description: 新增一个Action 70 | * @param actionDesc 71 | * @throws Exception 72 | */ 73 | @SuppressWarnings({"rawtypes"}) 74 | public void put(ActionDescricptor actionDesc) throws Exception { 75 | 76 | if(actionDesc == null) { 77 | return ; 78 | } 79 | 80 | try { 81 | ActionContext item = new ActionContext(); 82 | 83 | // action类 84 | String className = actionDesc.getActionClass(); 85 | BaseAction actionObject = actionObjectMap.get(className); 86 | if(actionObject == null) { 87 | Class actionClazz = Class.forName(className); 88 | actionObject = (BaseAction)actionClazz.newInstance(); 89 | actionObjectMap.put(className, actionObject); 90 | } 91 | item.setAction(actionObject); 92 | 93 | // 请求参数 94 | RequestParams requestParams = new RequestParams(); 95 | Map paramsdefine = actionDesc.getParams(); 96 | Class[] paramTypes = requestParams.addParams(paramsdefine); 97 | item.setRequestParams(requestParams); 98 | 99 | // 处理业务逻辑的方法 100 | Method method = actionObject.getClass().getMethod(actionDesc.getMethod(), paramTypes); 101 | item.setDoMethod(method); 102 | 103 | // 请求类型 104 | item.setRequestType(actionDesc.getRequestType()); 105 | item.setDefaultResponseType(actionDesc.getResponseType()); 106 | 107 | // 过滤器,暂时还没有 108 | String[] strFilters = actionDesc.getFilters(); 109 | String fname; 110 | IFilter filter; 111 | Class filterClazz; 112 | IFilter[] filters = new IFilter[strFilters.length]; 113 | for(int i = 0; i < strFilters.length; i++) { 114 | fname = strFilters[i]; 115 | filterClazz = Class.forName(fname); 116 | filter = (IFilter)filterClazz.newInstance(); 117 | filters[i] = filter; 118 | } 119 | item.setFilters(filters); 120 | 121 | actionMap.put(item.getRequestType(), item); 122 | } catch (Exception e) { 123 | throw e; 124 | } 125 | } 126 | 127 | } 128 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/FrameBinaryEncoder.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import org.jboss.netty.buffer.ChannelBuffer; 6 | import org.jboss.netty.buffer.ChannelBuffers; 7 | import org.jboss.netty.channel.ChannelHandlerContext; 8 | import org.jboss.netty.channel.Channels; 9 | import org.jboss.netty.channel.MessageEvent; 10 | import org.jboss.netty.channel.SimpleChannelDownstreamHandler; 11 | 12 | import com.mogujie.ares.configure.SysConstants; 13 | import com.mogujie.ares.lib.logger.Logger; 14 | import com.mogujie.ares.lib.logger.LoggerFactory; 15 | 16 | /** 17 | * 18 | * @Description: 数据编码器,把要发送的数据按照一定格式拼接成二进制的流 19 | * @author ziye - ziye[at]mogujie.com 20 | * @date 2013-7-21 下午4:02:07 21 | * 22 | */ 23 | public class FrameBinaryEncoder extends SimpleChannelDownstreamHandler { 24 | private static final Logger logger = LoggerFactory 25 | .getLogger(FrameBinaryEncoder.class); 26 | 27 | /** 28 | * @Description: 把要发送的数据编码成二进制数据并发送 29 | */ 30 | public void writeRequested(ChannelHandlerContext ctx, MessageEvent e) 31 | throws Exception { 32 | 33 | Packet request = (Packet) e.getMessage(); 34 | // encode 35 | DataBuffer contentBuffer = request.getContentBuffer(); 36 | ChannelBuffer dataBuffer = null; 37 | if (contentBuffer != null) { 38 | dataBuffer = contentBuffer.getOrignalBuffer(); 39 | } // 数据部分 40 | ChannelBuffer totalBuffer; 41 | ByteBuffer headBuffer = ByteBuffer 42 | .allocate(SysConstants.PROTOCOL_HEADER_LENGTH); 43 | if (dataBuffer != null) { 44 | int length = dataBuffer.readableBytes() 45 | + SysConstants.PROTOCOL_HEADER_LENGTH; // 总的包长 46 | headBuffer.putInt(length);// 消息长度 47 | char[] tc = Character.toChars(request.getVersion()); 48 | headBuffer.putChar(tc[0]);// 消息version, 1个字节 49 | tc = Character.toChars(request.getFlag()); 50 | headBuffer.putChar(tc[0]);// 标记: 分拆数据包,压缩 51 | tc = Character.toChars(request.getServiceId()); 52 | headBuffer.putChar(tc[0]); // 服务号, 后端这边固定1000 53 | tc = Character.toChars(request.getCommandId()); 54 | headBuffer.putChar(tc[0]); // 命令号 55 | tc = Character.toChars(request.getError()); 56 | headBuffer.putChar(tc[0]); // 服务器错误 57 | tc = Character.toChars(request.getReserved()); 58 | headBuffer.putChar(tc[0]); // 保留,可用于序列号等 59 | headBuffer.flip(); // 这里需要重置一下游标和长度 60 | 61 | totalBuffer = ChannelBuffers.dynamicBuffer(); 62 | totalBuffer.writeBytes(headBuffer); 63 | if (length > SysConstants.PROTOCOL_HEADER_LENGTH) { // 数据部分长度不为0才写入 64 | int dataLength = dataBuffer.readableBytes(); 65 | byte[] data = new byte[dataLength]; 66 | dataBuffer.readBytes(data); 67 | totalBuffer.writeBytes(data); 68 | } 69 | } else { 70 | int length = SysConstants.PROTOCOL_HEADER_LENGTH; // 总的包长 71 | headBuffer.putInt(length);// 消息长度 72 | headBuffer.put((byte) request.getVersion());// 消息version, 1个字节 73 | headBuffer.put((byte) request.getFlag());// 标记: 分拆数据包,压缩 74 | char[] tc = Character.toChars(request.getServiceId()); 75 | headBuffer.putChar(tc[0]); // 服务号, 后端这边固定1000 76 | tc = Character.toChars(request.getCommandId()); 77 | headBuffer.putChar(tc[0]); // 命令号 TODO 78 | tc = Character.toChars(request.getError()); 79 | headBuffer.putChar(tc[0]); // 服务器错误 80 | tc = Character.toChars(request.getReserved()); 81 | headBuffer.putChar(tc[0]); // 保留,可用户如序列号等 82 | headBuffer.flip(); // 这里需要重置一下游标和长度 83 | 84 | totalBuffer = ChannelBuffers.copiedBuffer(headBuffer); 85 | } 86 | // logger.info("encode serviceId : " + request.getServiceId() 87 | // + " commandId: " + request.getCommandId()); 88 | Channels.write(ctx, e.getFuture(), totalBuffer); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/util/HttpUtil.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.util; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Map.Entry; 9 | 10 | import org.apache.http.NameValuePair; 11 | import org.apache.http.client.config.RequestConfig; 12 | import org.apache.http.client.methods.CloseableHttpResponse; 13 | import org.apache.http.client.methods.HttpGet; 14 | import org.apache.http.client.methods.HttpPost; 15 | import org.apache.http.client.utils.URLEncodedUtils; 16 | import org.apache.http.entity.StringEntity; 17 | import org.apache.http.impl.client.CloseableHttpClient; 18 | import org.apache.http.impl.client.HttpClients; 19 | import org.apache.http.message.BasicNameValuePair; 20 | import org.apache.http.util.EntityUtils; 21 | 22 | import com.alibaba.druid.util.StringUtils; 23 | import com.mogujie.ares.lib.logger.Logger; 24 | import com.mogujie.ares.lib.logger.LoggerFactory; 25 | import com.mogujie.ares.lib.net.IMHttpResponse; 26 | 27 | public class HttpUtil { 28 | 29 | private static Logger logger = LoggerFactory.getLogger(HttpUtil.class); 30 | 31 | public static IMHttpResponse get(String url) { 32 | IMHttpResponse response = new IMHttpResponse(); 33 | response.setStatusCode(404); 34 | if(StringUtils.isEmpty(url)) { 35 | return response; 36 | } 37 | int statusCode = 404; 38 | CloseableHttpClient httpClient = null; 39 | HttpGet httpGet = null; 40 | try { 41 | httpClient = HttpClients.createDefault(); 42 | httpGet = new HttpGet(url);//HTTP Get请求(POST雷同) 43 | RequestConfig requestConfig = RequestConfig 44 | .custom() 45 | .setSocketTimeout(2000) 46 | .setConnectTimeout(2000) 47 | .build();//设置请求和传输超时时间 48 | httpGet.setConfig(requestConfig); 49 | CloseableHttpResponse hresp = httpClient.execute(httpGet);//执行请求 50 | String responseString = EntityUtils.toString(hresp.getEntity()); 51 | response.setStatusCode(hresp.getStatusLine().getStatusCode()); 52 | response.setResponseBody(responseString); 53 | return response; 54 | } catch (Exception e) { 55 | logger.error("error code: " + statusCode, e); 56 | } finally { 57 | if(httpGet != null) { 58 | httpGet.releaseConnection(); 59 | } 60 | } 61 | return response; 62 | } 63 | 64 | @SuppressWarnings("rawtypes") 65 | public static IMHttpResponse post(String url) { 66 | return post(url, new HashMap()); 67 | } 68 | 69 | @SuppressWarnings({ "rawtypes", "unchecked" }) 70 | public static IMHttpResponse post(String url, Map params) { 71 | IMHttpResponse response = new IMHttpResponse(); 72 | if(StringUtils.isEmpty(url)) { 73 | response.setStatusCode(404); 74 | return response; 75 | } 76 | 77 | CloseableHttpClient httpClient = null; 78 | HttpPost httpPost = null; 79 | try { 80 | httpPost = new HttpPost(url);//HTTP Get请求(POST雷同) 81 | List postData = new ArrayList(); 82 | Iterator piter = params.entrySet().iterator(); 83 | while(piter.hasNext()) { 84 | Entry entry = piter.next(); 85 | postData.add(new BasicNameValuePair(String.valueOf(entry.getKey()), String.valueOf(entry.getValue()))); 86 | } 87 | StringEntity entity = new StringEntity(URLEncodedUtils.format(postData, "UTF-8")); 88 | httpPost.setEntity(entity); 89 | RequestConfig requestConfig = RequestConfig 90 | .custom() 91 | .setSocketTimeout(2000) 92 | .setConnectTimeout(2000) 93 | .build();//设置请求和传输超时时间 94 | httpPost.setConfig(requestConfig); 95 | httpClient = HttpClients.createDefault(); 96 | CloseableHttpResponse hresp = httpClient.execute(httpPost);//执行请求 97 | String responseString = EntityUtils.toString(hresp.getEntity()); 98 | response.setStatusCode(hresp.getStatusLine().getStatusCode()); 99 | response.setResponseBody(responseString); 100 | return response; 101 | } catch(Exception e) { 102 | logger.error("url: " + url, e); 103 | } finally { 104 | if(httpPost != null) { 105 | httpPost.releaseConnection(); 106 | } 107 | } 108 | return response; 109 | } 110 | 111 | 112 | } 113 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/storage/DBPool.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.storage; 2 | 3 | import java.sql.Connection; 4 | import java.sql.ResultSet; 5 | import java.sql.SQLException; 6 | import java.sql.Statement; 7 | 8 | import com.alibaba.druid.pool.DruidDataSource; 9 | import com.mogujie.ares.lib.logger.Logger; 10 | import com.mogujie.ares.lib.logger.LoggerFactory; 11 | 12 | /** 13 | * 14 | * @Description: db连接池 15 | * @author shitou - shitou[at]mogujie.com 16 | * @date 2013-7-21 下午5:42:55 17 | * 18 | */ 19 | public class DBPool 20 | { 21 | 22 | private static final Logger logger = LoggerFactory.getLogger(DBPool.class); 23 | 24 | // private BoneCP dbConnectionPool = null; 25 | 26 | // private BoneCPConfig dbBoneCPConfig = null; 27 | 28 | private DruidDataSource druid; 29 | 30 | private String jdbcUrl; 31 | 32 | private String jdbcUsername; 33 | 34 | private String jdbcPassword; 35 | 36 | private String driverClass = "com.mysql.jdbc.Driver"; 37 | 38 | private int initConnectionCount = 5; 39 | 40 | private int maxActiveConnection = 18; 41 | 42 | 43 | public DBPool(String jdbcUrl, String username, String password) 44 | { 45 | this.jdbcUrl = jdbcUrl; 46 | this.jdbcUsername = username; 47 | this.jdbcPassword = password; 48 | } 49 | 50 | /** 51 | * 初始化 52 | */ 53 | // public void initial() 54 | // { 55 | // //load configure 56 | //// if(dbBoneCPConfig == null) 57 | //// { 58 | //// dbBoneCPConfig = new BoneCPConfig(); 59 | //// dbBoneCPConfig.setJdbcUrl(this.jdbcUrl); 60 | //// dbBoneCPConfig.setUsername(this.jdbcUsername); 61 | //// dbBoneCPConfig.setPassword(this.jdbcPassword); 62 | //// dbBoneCPConfig.setMinConnectionsPerPartition(Constants.DB_MIN_CONNECTIONS_PER_PARTITION); 63 | //// dbBoneCPConfig.setMaxConnectionsPerPartition(Constants.DB_MAX_CONNECTIONS_PER_PARTITION); 64 | //// dbBoneCPConfig.setIdleConnectionTestPeriod(Constants.DB_IDLE_CONNECTION_TEST_PERIOD, TimeUnit.SECONDS); 65 | //// dbBoneCPConfig.setPartitionCount(Constants.DB_PARTITION_COUNT); 66 | //// } 67 | // } 68 | 69 | /** 70 | * 启动 71 | * @throws SQLException 72 | */ 73 | public void launchDBPool() throws SQLException 74 | { 75 | if(druid == null) 76 | { 77 | // initial(); 78 | try { 79 | // dbConnectionPool = new BoneCP(dbBoneCPConfig); 80 | druid = new DruidDataSource(); 81 | druid.setDriverClassName(driverClass); 82 | druid.setUsername(jdbcUsername); 83 | druid.setPassword(jdbcPassword); 84 | druid.setUrl(jdbcUrl); 85 | druid.setMinIdle(maxActiveConnection); 86 | druid.setInitialSize(initConnectionCount); 87 | druid.setMaxActive(maxActiveConnection); 88 | druid.setFilters("stat"); 89 | druid.setTestWhileIdle(true); 90 | druid.setTestOnBorrow(false); 91 | druid.setTestOnReturn(false); 92 | druid.setMaxWait(60000); 93 | druid.setPoolPreparedStatements(false); 94 | druid.setValidationQuery("SELECT 'x'"); 95 | 96 | druid.init(); 97 | } catch (SQLException e) { 98 | logger.error("", e); 99 | throw e; 100 | } 101 | } 102 | } 103 | 104 | /** 105 | * 关闭 106 | */ 107 | public void shutDownDBPool() 108 | { 109 | if(druid != null) 110 | { 111 | //dbConnectionPool.shutdown(); 112 | druid.close(); 113 | } 114 | } 115 | 116 | /** 117 | * 从Pool中获取一个链接 118 | */ 119 | public Connection getConnection() 120 | { 121 | Connection connection = null; 122 | try { 123 | // connection = dbConnectionPool.getConnection(); 124 | connection = druid.getConnection(); 125 | } catch (SQLException e) { 126 | logger.error("", e); 127 | } 128 | return connection; 129 | } 130 | 131 | /** 132 | * 快捷关闭 133 | * @param connection 134 | * @paramlogger.error("", e); 135 | */ 136 | public void shortCutClose(Connection connection, Statement stat, ResultSet rs) 137 | { 138 | try { 139 | if(rs != null && !rs.isClosed()) { 140 | rs.close(); 141 | } 142 | if(stat != null && !stat.isClosed()) { 143 | stat.close(); 144 | } 145 | if(connection != null && !connection.isClosed()) { 146 | connection.close(); 147 | } 148 | } catch (SQLException e) { 149 | logger.error("", e); 150 | } 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/CacheManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import java.util.Iterator; 4 | import java.util.Map; 5 | import java.util.Map.Entry; 6 | import java.util.Properties; 7 | import java.util.concurrent.ConcurrentHashMap; 8 | 9 | import com.mogujie.ares.lib.storage.CachePool; 10 | 11 | import redis.clients.jedis.Jedis; 12 | 13 | /** 14 | * 15 | * @Description: 缓存连接相关的管理类,针对不同业务会有多个连接池,单例 16 | * @author shitou - shitou[at]mogujie.com 17 | * @date 2013-7-21 下午5:45:18 18 | * 19 | */ 20 | public class CacheManager 21 | { 22 | private ConcurrentHashMap cachePool = new ConcurrentHashMap(); // 多个池子 23 | 24 | private static CacheManager cacheManagerInstance = new CacheManager(); 25 | 26 | private Properties cacheProperties; 27 | 28 | private boolean isLanuch = false; 29 | 30 | public static CacheManager getInstance() 31 | { 32 | if(cacheManagerInstance == null) 33 | { 34 | cacheManagerInstance = new CacheManager(); 35 | } 36 | return cacheManagerInstance; 37 | } 38 | 39 | private CacheManager() 40 | { 41 | this.cacheProperties = ConfigureManager.getInstance().getCacheConfig(); 42 | launch(); 43 | } 44 | 45 | /** 46 | * @Description: 初始化 47 | */ 48 | private void launch() 49 | { 50 | if( ! isLanuch) 51 | { 52 | //shutDown(); 53 | 54 | String needLaunchPoolInstance = cacheProperties.getProperty("instances"); 55 | String[] needLaunchPools = needLaunchPoolInstance.split(","); 56 | for(String instance : needLaunchPools) 57 | { 58 | //获取配置 59 | String redisHost = cacheProperties.getProperty(instance + "_host"); 60 | Integer redisPort = Integer.valueOf(cacheProperties.getProperty(instance + "_port")); 61 | Integer redisDB = Integer.valueOf(cacheProperties.getProperty(instance + "_db")); 62 | 63 | //实例化,启动,并塞入Hashmap中 64 | CachePool cachePoolInstance = new CachePool(redisHost, redisPort, redisDB); 65 | cachePoolInstance.launch(); 66 | cachePool.put(instance, cachePoolInstance); 67 | } 68 | isLanuch = true; 69 | } 70 | } 71 | 72 | /** 73 | * @Description: 关闭所有连接池 74 | */ 75 | public void shutDown() 76 | { 77 | if(this.cachePool.size() > 0) 78 | { 79 | Iterator> iterator = this.cachePool.entrySet().iterator(); 80 | while(iterator.hasNext()) 81 | { 82 | Map.Entry hashEntry = iterator.next(); 83 | CachePool poolInstance = hashEntry.getValue(); 84 | poolInstance.destory(); 85 | 86 | cachePool.remove(hashEntry.getKey()); 87 | } 88 | 89 | cachePool.clear(); 90 | } 91 | } 92 | 93 | /** 94 | * @Description: 从指定的链接池中获取一个链接 95 | * @param poolName 连接池的名字 96 | * @return 97 | */ 98 | public Jedis getResource(CachePoolName poolName) { 99 | String strName = poolName.toString(); 100 | 101 | return getJedisResource(strName); 102 | } 103 | 104 | /** 105 | * @Description: 释放一个链接 106 | * @param poolName 连接所在的连接池 107 | * @param jedis 连接 108 | */ 109 | public void returnResource(CachePoolName poolName, Jedis jedis) { 110 | if(jedis == null) { 111 | return ; 112 | } 113 | 114 | String strName = poolName.toString(); 115 | returnJedisResource(strName, jedis); 116 | } 117 | 118 | /** 119 | * 120 | * @Description: 具体释放连接操作 121 | * @param poolName 122 | * @param jedisInstance 123 | */ 124 | private void returnJedisResource(String poolName, Jedis jedisInstance) { 125 | CachePool pool = cachePool.get(poolName); 126 | if(pool != null) { 127 | pool.returnResource(jedisInstance); 128 | } 129 | } 130 | 131 | /** 132 | * 133 | * @Description: 具体获取连接操作 134 | * @param instanceName 135 | * @return 136 | */ 137 | private Jedis getJedisResource(String instanceName) { 138 | Jedis jedisResource = null; 139 | CachePool pool = cachePool.get(instanceName); 140 | if(pool != null) { 141 | jedisResource = pool.getResource(); 142 | } 143 | return jedisResource; 144 | } 145 | 146 | /** 147 | * 148 | * @Description: 连接池的名字 149 | * @author ziye - ziye[at]mogujie.com 150 | * @date 2013-7-21 下午6:37:06 151 | * 152 | */ 153 | public enum CachePoolName { 154 | counter, // 所有计数器 155 | unread, // 未读计数器 156 | // cinfo, //用户信息(消息通知用的). 157 | // cinfo_push, // 推送cinfo 158 | group_counter 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/util/MoguUtil.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.util; 2 | 3 | import java.security.MessageDigest; 4 | import java.security.NoSuchAlgorithmException; 5 | import java.util.HashMap; 6 | import java.util.HashSet; 7 | import java.util.Map; 8 | import java.util.Set; 9 | 10 | import com.mogujie.ares.data.User; 11 | import com.mogujie.ares.lib.net.DataBuffer; 12 | 13 | /* 14 | * 蘑菇街IM工具类 15 | */ 16 | public final class MoguUtil { 17 | 18 | /* 19 | * 判断是否是管理员 20 | */ 21 | public boolean isAdmin(User user) { 22 | return (user == null) ? false : isAdmin(user.getUserType()); 23 | } 24 | 25 | /* 26 | * 判断是否是管理员 27 | */ 28 | public boolean isAdmin(int type) { 29 | return (type == 1) ? true : false; 30 | } 31 | 32 | /* 33 | * 对int数组去重 34 | * 35 | * @param array 需要去重的数组 36 | */ 37 | public static int[] distinct(int[] array) { 38 | Set intSet = new HashSet(); 39 | int intVal; 40 | int length = array.length; 41 | for (int i = 0; i < length; i++) { 42 | intVal = array[i]; 43 | if (!intSet.contains(intVal)) { 44 | intSet.add(intVal); 45 | } 46 | } 47 | Integer[] uniqArray = new Integer[intSet.size()]; 48 | intSet.toArray(uniqArray); 49 | int[] ints = new int[uniqArray.length]; 50 | for (int i = 0; i < uniqArray.length; i++) { 51 | ints[i] = uniqArray[i]; 52 | } 53 | return ints; 54 | } 55 | 56 | /* 57 | * 对int数组去重并返回map对象 58 | * 59 | * @param array 需要去重的数组 60 | */ 61 | public static Map distinctToMap(int[] array) { 62 | Set intSet = new HashSet(); 63 | int intVal; 64 | int length = array.length; 65 | for (int i = 0; i < length; i++) { 66 | intVal = array[i]; 67 | if (!intSet.contains(intVal)) { 68 | intSet.add(intVal); 69 | } 70 | } 71 | Integer[] uniqArray = new Integer[intSet.size()]; 72 | intSet.toArray(uniqArray); 73 | Map mapIds = new HashMap(); 74 | for (int i = 0; i < uniqArray.length; i++) { 75 | mapIds.put(uniqArray[i], uniqArray[i]); 76 | } 77 | return mapIds; 78 | } 79 | 80 | /* 81 | * 获得DB中参数?占位符 82 | * 83 | * @parma number 参数个数 84 | */ 85 | public static String getArgsHolder(int number) { 86 | return getArgsHolder("?", ",", number); 87 | } 88 | 89 | /* 90 | * 获得DB中参数?占位符 91 | * 92 | * @param hoder 占位的字符 93 | * 94 | * @param split 分隔的字符 95 | * 96 | * @parma number 参数个数 97 | */ 98 | public static String getArgsHolder(String hoder, String split, int number) { 99 | StringBuffer buffer = new StringBuffer(""); 100 | if (number <= 0) { 101 | return buffer.toString(); 102 | } 103 | 104 | for (int i = 0; i < number; i++) { 105 | buffer.append(split + hoder); 106 | } 107 | return buffer.toString().substring(1); 108 | 109 | } 110 | 111 | /** 112 | * 113 | * @Description: md5加密 114 | * @param str 115 | * @return 116 | * @throws NoSuchAlgorithmException 117 | */ 118 | public static String md5(String str) throws NoSuchAlgorithmException { 119 | 120 | MessageDigest tool = MessageDigest.getInstance("MD5"); 121 | tool.update(str.getBytes()); 122 | byte[] bytes = tool.digest(); 123 | StringBuffer sb = new StringBuffer(); 124 | for (int i = 0; i < bytes.length; i++) { // 字节数组转换成十六进制字符串,形成最终的密文 125 | int v = bytes[i] & 0xff; 126 | if (v < 16) { 127 | sb.append(0); 128 | } 129 | sb.append(Integer.toHexString(v)); 130 | } 131 | 132 | return sb.toString(); 133 | } 134 | 135 | /* 136 | * 将请求附带的信息写回 137 | */ 138 | public static DataBuffer writeAttachments(DataBuffer buffer, 139 | DataBuffer attachment) { 140 | if (null != buffer && null != attachment) { 141 | buffer.writeInt(attachment.readableBytes()); 142 | if (attachment.readableBytes() > 0) { 143 | buffer.writeDataBuffer(attachment); 144 | } 145 | } 146 | 147 | return buffer; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/configure/Configure.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.configure; 2 | 3 | import java.io.IOException; 4 | import java.io.InputStream; 5 | import java.util.HashMap; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.Properties; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | import org.dom4j.DocumentException; 12 | import org.dom4j.Node; 13 | import org.dom4j.io.SAXReader; 14 | 15 | import com.mogujie.ares.lib.logger.Logger; 16 | import com.mogujie.ares.lib.logger.LoggerFactory; 17 | 18 | /** 19 | * 配置,单利 20 | * @author stone 21 | * 22 | */ 23 | public class Configure 24 | { 25 | public static final Logger logger = LoggerFactory.getLogger(Configure.class); 26 | 27 | public Properties systemConfig; 28 | 29 | public Properties dbConfig; 30 | 31 | public Properties cacheConfig; 32 | 33 | public ConcurrentHashMap> timerConfig; 34 | 35 | public Router actionRouter; 36 | 37 | public Configure() 38 | { 39 | systemConfig = new Properties(); 40 | dbConfig = new Properties(); 41 | cacheConfig = new Properties(); 42 | timerConfig = new ConcurrentHashMap>(); 43 | actionRouter = Router.getInstance(); 44 | } 45 | 46 | public Properties getSystemConfig() 47 | { 48 | return systemConfig; 49 | } 50 | 51 | public Properties getDBConfig() 52 | { 53 | return dbConfig; 54 | } 55 | 56 | public Properties getCacheConfig() 57 | { 58 | return cacheConfig; 59 | } 60 | 61 | public Router getActionRouter() { 62 | return actionRouter; 63 | } 64 | 65 | public ConcurrentHashMap> getTimerConfig() 66 | { 67 | return timerConfig; 68 | } 69 | 70 | /** 71 | * 载入所有配置 72 | * @throws Exception 73 | */ 74 | public void loadConfigs() throws Exception { 75 | loadSystemConfig(); // 系统配置 76 | loadDBConfig(); 77 | loadCacheConfig(); 78 | loadActionConfig(); // action相关的路由配置 79 | loadTimerConfig(); // 计划任务脚本配置 80 | } 81 | 82 | public void loadSystemConfig() 83 | { 84 | propertyConfigLoader("system.properties", systemConfig); 85 | } 86 | 87 | public void loadDBConfig() 88 | { 89 | propertyConfigLoader(systemConfig.getProperty("com.mogujie.ares.config.file.db"), dbConfig); 90 | } 91 | 92 | public void loadCacheConfig() 93 | { 94 | propertyConfigLoader(systemConfig.getProperty("com.mogujie.ares.config.file.cache"), cacheConfig); 95 | } 96 | 97 | public void loadActionConfig() throws Exception { 98 | actionRouter.load(systemConfig.getProperty("com.mogujie.ares.config.file.route")); 99 | } 100 | 101 | public void loadTimerConfig() 102 | { 103 | taskXMLConfigLoader(systemConfig.getProperty("com.mogujie.ares.config.file.timer"), timerConfig); 104 | } 105 | 106 | public void propertyConfigLoader(String configFilePath, Properties config) 107 | { 108 | if(configFilePath.length() == 0) 109 | { 110 | return ; 111 | } 112 | 113 | InputStream configFileStream = Configure.class.getClassLoader() 114 | .getResourceAsStream(configFilePath); 115 | try { 116 | config.load(configFileStream); 117 | } catch (IOException e) { 118 | logger.error("", e); 119 | } 120 | } 121 | 122 | /** 123 | * 载入xml格式的计划任务脚本的配置 124 | * 125 | * @param configFilePath 126 | * @param config 127 | */ 128 | @SuppressWarnings({"unchecked"}) 129 | public void taskXMLConfigLoader(String configFilePath, Map> config) 130 | { 131 | if(configFilePath.length() == 0) 132 | { 133 | return ; 134 | } 135 | // String configFileFullPath = System.getProperty("user.dir") + 136 | // "/src/main/resources/" + configFilePath; 137 | // if( ! new File(configFileFullPath).exists()) 138 | // { 139 | // return ; 140 | // } 141 | 142 | InputStream is = this.getClass().getResourceAsStream("/" + configFilePath); 143 | if(is == null) { 144 | return; 145 | } 146 | SAXReader reader = new SAXReader(); 147 | try { 148 | org.dom4j.Document configDocument = reader.read(is); 149 | List nodes = configDocument.selectNodes("//tasks/task"); 150 | for(Node node : nodes) 151 | { 152 | Node enable = node.selectSingleNode("enable"); 153 | Node name = node.selectSingleNode("name"); 154 | Node initdelay = node.selectSingleNode("initdelay"); 155 | Node periodordelay = node.selectSingleNode("periodordelay"); 156 | Node taskType = node.selectSingleNode("taskType"); 157 | 158 | HashMap theTaskConfig = new HashMap(); 159 | theTaskConfig.put("enable", enable.getText()); 160 | theTaskConfig.put("initdelay", initdelay.getText()); 161 | theTaskConfig.put("periodordelay", periodordelay.getText()); 162 | theTaskConfig.put("taskType", taskType.getText()); 163 | 164 | config.put(name.getText(), theTaskConfig); 165 | } 166 | } catch (DocumentException e) { 167 | logger.error("", e); 168 | } 169 | } 170 | 171 | 172 | } 173 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/DBManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import java.sql.Connection; 4 | import java.sql.ResultSet; 5 | import java.sql.SQLException; 6 | import java.sql.Statement; 7 | import java.util.Iterator; 8 | import java.util.Properties; 9 | import java.util.concurrent.ConcurrentHashMap; 10 | 11 | import com.mogujie.ares.lib.logger.Logger; 12 | import com.mogujie.ares.lib.logger.LoggerFactory; 13 | import com.mogujie.ares.lib.storage.DBPool; 14 | 15 | /** 16 | * 17 | * @Description: db连接池管理类,单例 18 | * @author shitou - shitou[at]mogujie.com 19 | * @date 2013-7-21 下午7:04:05 20 | * 21 | */ 22 | public class DBManager { 23 | private static final Logger logger = LoggerFactory 24 | .getLogger(DBManager.class); 25 | 26 | // 连接池集合 27 | private ConcurrentHashMap dbPoolMap = new ConcurrentHashMap(); 28 | 29 | // db配置 30 | private Properties dbProperties; 31 | 32 | // 是否已加载 33 | private boolean isLaunch = false; 34 | 35 | // 单例 36 | private static DBManager dbManagerInstance = getInstance(); 37 | 38 | public static DBManager getInstance() { 39 | if (dbManagerInstance == null) { 40 | try { 41 | dbManagerInstance = new DBManager(); 42 | } catch (SQLException e) { 43 | logger.error("", e); 44 | } 45 | } 46 | return dbManagerInstance; 47 | } 48 | 49 | private DBManager() throws SQLException { 50 | dbProperties = ConfigureManager.getInstance().getDBConfig(); 51 | launch(); 52 | } 53 | 54 | /** 55 | * 56 | * @throws SQLException 57 | * @Description: 初始化加载 58 | */ 59 | private void launch() throws SQLException { 60 | if (!isLaunch) { 61 | // shutDown(); 62 | 63 | String shutDownInstances = dbProperties.getProperty("instances"); 64 | String[] instances = shutDownInstances.split(","); 65 | for (String instanceName : instances) { 66 | if (instanceName.length() == 0) { 67 | continue; 68 | } 69 | String jdbcUrl = dbProperties 70 | .getProperty(instanceName + "_url"); 71 | String jdbcUsername = dbProperties.getProperty(instanceName 72 | + "_username"); 73 | String jdbcPassword = dbProperties.getProperty(instanceName 74 | + "_password"); 75 | DBPool newDBPool = new DBPool(jdbcUrl, jdbcUsername, 76 | jdbcPassword); 77 | newDBPool.launchDBPool(); 78 | 79 | dbPoolMap.put(instanceName, newDBPool); 80 | } 81 | isLaunch = true; 82 | } 83 | 84 | } 85 | 86 | /** 87 | * 88 | * @Description: 关闭所有连接池 89 | */ 90 | public void shutDown() { 91 | if (dbPoolMap.size() > 0) { 92 | Iterator iterator = dbPoolMap.keySet().iterator(); 93 | while (iterator.hasNext()) { 94 | DBPool pool = dbPoolMap.remove(iterator.next()); 95 | if (pool != null) { 96 | pool.shutDownDBPool(); 97 | } 98 | } 99 | dbPoolMap.clear(); 100 | } 101 | } 102 | 103 | /** 104 | * 105 | * @Description: 获得DB连接 106 | * @return 指定的链接池中的一个连接 107 | */ 108 | public Connection getConnection(DBPoolName name) { 109 | Connection connection = null; 110 | DBPool dbPool = dbPoolMap.get(name.toString()); 111 | if (dbPool != null) { 112 | connection = dbPool.getConnection(); 113 | } 114 | return connection; 115 | } 116 | 117 | /** 118 | * 119 | * @Description: 释放连接 120 | * @param poolName 121 | * 连接所在的连接池 122 | * @param connection 123 | * 连接 124 | */ 125 | public void closeConnection(DBPoolName poolName, Connection connection) { 126 | DBPool pool = dbPoolMap.get(poolName.toString()); 127 | if (pool != null) { 128 | pool.shortCutClose(connection, null, null); 129 | } 130 | } 131 | 132 | /** 133 | * 134 | * @Description: 集中释放各种资源 135 | * @param poolName 136 | * 连接所在的连接池的名字 137 | * @param connection 138 | * 连接 139 | * @param statement 140 | * @param resultSet 141 | */ 142 | public void release(DBPoolName poolName, Connection connection, 143 | Statement statement, ResultSet resultSet) { 144 | DBPool pool = dbPoolMap.get(poolName.toString()); 145 | if (pool != null) { 146 | pool.shortCutClose(connection, statement, resultSet); 147 | } 148 | } 149 | 150 | /** 151 | * 152 | * @Description: 连接池的名字,定义一个枚举,以免传错 153 | * @author ziye - ziye[at]mogujie.com 154 | * @date 2013-7-22 上午11:45:27 155 | * 156 | */ 157 | public enum DBPoolName { 158 | macim_master, macim_slave 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/RequestParams.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend; 2 | 3 | import java.util.Iterator; 4 | import java.util.LinkedHashMap; 5 | import java.util.Map; 6 | 7 | import org.jboss.netty.channel.ChannelHandlerContext; 8 | 9 | import com.mogujie.ares.lib.net.DataBuffer; 10 | 11 | /** 12 | * 13 | * @Description: 请求参数的描述和控制类,负责将请求数据包中的二进制数据解析成具体的变量 14 | * @author ziye - ziye[at]mogujie.com 15 | * @date 2013-7-21 上午11:41:37 16 | * 17 | */ 18 | @SuppressWarnings({"rawtypes"}) 19 | public class RequestParams { 20 | 21 | // 原生的描述参数的数据,参数名 => 参数类型,详细请见配置route.xml 22 | private Map metaData = new LinkedHashMap(); 23 | 24 | // 参数名和java类型的对应 25 | private Map paramsType = new LinkedHashMap(); 26 | 27 | /** 28 | * 29 | * @Description: 添加单个参数 30 | * @param name 参数名称 31 | * @param typeName 参数类型名称 32 | * @param typeClazz 参数的java类型 33 | */ 34 | public void add(String name, String typeName, Class typeClazz) { 35 | metaData.put(name, typeName); 36 | paramsType.put(name, typeClazz); 37 | } 38 | 39 | public Map getParamsType() { 40 | return paramsType; 41 | } 42 | 43 | public void setParamsType(Map paramsType) { 44 | this.paramsType = paramsType; 45 | } 46 | 47 | public Map getMetaData() { 48 | return metaData; 49 | } 50 | 51 | public void setMetaData(Map metaData) { 52 | this.metaData = metaData; 53 | } 54 | 55 | /** 56 | * @Description: 将请求数据包中的二进制数据解析成具体的变量 57 | * @param dataBuffer 58 | * @param actionContext 59 | * @return 60 | * @throws Exception 61 | * NOTE: 最后一个参数 version不需要客户端手动传的.处理参数的时候,自动从请求的报头里取的. 62 | */ 63 | public Object[] decode(DataBuffer dataBuffer, ChannelHandlerContext context, ActionContext actionContext,int version) throws Exception { 64 | Object[] values = null; 65 | 66 | if(metaData == null || metaData.size() <= 0) { 67 | values = new Object[0]; 68 | return values; 69 | } 70 | 71 | values = new Object[metaData.size()]; 72 | Iterator it = metaData.keySet().iterator(); 73 | String type; 74 | String name; 75 | int i = 0; 76 | while(it.hasNext() && i!=metaData.size()-1) { 77 | name = it.next(); 78 | type = metaData.get(name); 79 | Object value = null; 80 | if(name.startsWith("${") && name.endsWith("}")) { // 系统数据 81 | // 这里特判 82 | if(name.equals("${channel.remoteAddress}")) { // 客户端的地址信息 83 | value = context.getChannel().getRemoteAddress().toString(); 84 | } else if(name.equals("${action.requestType}")) { 85 | value = actionContext.getRequestType(); 86 | } 87 | // TO BE CONTINUED.... 88 | } else { 89 | if("int".equals(type)) { 90 | value = dataBuffer.readInt(); 91 | } else if("char".equals(type)) { 92 | value = dataBuffer.readChar(); 93 | } else if("byte".equals(type)) { 94 | value = dataBuffer.readByte(); 95 | } else if("String".equals(type)) { 96 | value = dataBuffer.readString(); 97 | } else if("int-array".equals(type)) { // int数组 98 | value = dataBuffer.readIntArray(); 99 | } else if("byte-array".equals(type)) { // byte数组 100 | value = dataBuffer.readByteArray(); 101 | } else if("string-array".equals(type)) { // String数组 102 | value = dataBuffer.readStringArray(); 103 | } else if("DataBuffer".equals(type)) { // 直接传DataBuffer,业务方自己解析,太霸道了 104 | value = dataBuffer.readDataBuffer(); 105 | }else { 106 | throw new Exception("不支持的类型"); 107 | } 108 | } 109 | values[i++] = value; 110 | } 111 | values[i++] = version; 112 | return values; 113 | } 114 | 115 | /** 116 | * @throws Exception 当传入的参数类型不支持时返回这个错误,比如Map什么的神类型 117 | * @Description: 添加一个方法的参数,要按照从左到右的顺序添加,不然会有问题 118 | * @param @param paramsMap 参数配置的map,参数名 => 类型名称 119 | * @return Class[] 直接返回参数类型对应的java类型数组,顺序与传入时(配置)一致 120 | * @throws 121 | */ 122 | public Class[] addParams(Map paramsMap) throws Exception { 123 | Class[] paramTypes = new Class[paramsMap.size()]; 124 | Iterator it = paramsMap.keySet().iterator(); 125 | int j = 0; 126 | Class typeClazz = null; 127 | while(it.hasNext()) { 128 | String name = it.next(); 129 | String typeName = paramsMap.get(name); 130 | if("int".equals(typeName)) { 131 | typeClazz = int.class; 132 | } else if("String".equals(typeName)) { 133 | typeClazz = String.class; 134 | } else if("byte".equals(typeName)) { // byte,和int分开是因为数据包中int占4个字节,byte只占一个字节 135 | typeClazz = byte.class; 136 | } else if("int-array".equals(typeName)) { // int数组 137 | typeClazz = int[].class; 138 | } else if("byte-array".equals(typeName)) { // byte数组 139 | typeClazz = byte[].class; 140 | } else if("string-array".equals(typeName)) { // string数组 141 | typeClazz = String[].class; 142 | } else if("DataBuffer".equals(typeName)) { // 鬼畜的dataBuffer 143 | typeClazz = DataBuffer.class; 144 | } else { 145 | throw new Exception(typeName + "是神马!"); 146 | } 147 | paramTypes[j++] = typeClazz; 148 | add(name, typeName, typeClazz); 149 | } 150 | 151 | return paramTypes; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/DelayUpdateMonitor.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.util.Map; 4 | import java.util.concurrent.ConcurrentHashMap; 5 | 6 | import com.mogujie.ares.lib.logger.Logger; 7 | import com.mogujie.ares.lib.logger.LoggerFactory; 8 | import com.mogujie.ares.model.GroupModel; 9 | import com.mogujie.ares.model.RelationshipModel; 10 | 11 | public class DelayUpdateMonitor { 12 | public static final int DEFAULT_PACKET_SEND_MONTOR_INTERVAL = 30 * 1000; 13 | 14 | private Monitor mMonitor; 15 | private ConcurrentHashMap mGroupForUpdateMap = new ConcurrentHashMap(); 16 | private ConcurrentHashMap mPersonalForUpdateMap = new ConcurrentHashMap(); 17 | private volatile boolean mNeedStop; 18 | private volatile boolean mStarted = false; 19 | private static final Logger logger = LoggerFactory 20 | .getLogger(MessageContent.class); 21 | private static DelayUpdateMonitor instance; 22 | 23 | public static DelayUpdateMonitor getInstance() { 24 | if (null == instance) { 25 | instance = new DelayUpdateMonitor(); 26 | } 27 | return instance; 28 | } 29 | 30 | private DelayUpdateMonitor() { 31 | mMonitor = new Monitor("TT-Delay-Update-Monitor", 32 | DEFAULT_PACKET_SEND_MONTOR_INTERVAL); 33 | } 34 | 35 | public synchronized void start() { 36 | if (mStarted) 37 | return; 38 | mNeedStop = false; 39 | mMonitor.start(); 40 | mStarted = true; 41 | } 42 | 43 | public synchronized void stop() { 44 | if (mNeedStop) { 45 | return; 46 | } 47 | mNeedStop = true; 48 | mStarted = false; 49 | } 50 | 51 | public void AddPersonalUpdate(int uA, int uB, int time) { 52 | int small = uA < uB ? uA : uB; 53 | int big = uA + uB - small; 54 | String sKey = small + ":" + big; 55 | logger.info("user " + uA + " and " + uB + "wants to update to :" + time); 56 | synchronized(mPersonalForUpdateMap) { 57 | if (mPersonalForUpdateMap.containsKey(sKey)) { 58 | mPersonalForUpdateMap.remove(sKey); 59 | } 60 | mPersonalForUpdateMap.put(sKey, time); 61 | } 62 | } 63 | 64 | public void AddGroupUpdate(int groupId, int time) { 65 | logger.info("Group " + groupId + "wants to update to :" + time); 66 | synchronized(mGroupForUpdateMap) { 67 | if (mGroupForUpdateMap.containsKey(groupId)) { 68 | mGroupForUpdateMap.remove(groupId); 69 | } 70 | mGroupForUpdateMap.put(groupId, time); 71 | } 72 | } 73 | 74 | private class Monitor extends Thread { 75 | 76 | private int mInterval; 77 | public Monitor(String name, int interval) { 78 | setName(name); 79 | mInterval = interval; 80 | } 81 | 82 | @Override 83 | public void run() { 84 | super.run(); 85 | try { 86 | while (!mNeedStop) { 87 | ConcurrentHashMap oldGroupMap = new ConcurrentHashMap(); 88 | synchronized(mGroupForUpdateMap) { 89 | ConcurrentHashMap tmpMap; 90 | tmpMap = mGroupForUpdateMap; 91 | mGroupForUpdateMap = oldGroupMap; 92 | oldGroupMap = tmpMap; 93 | } 94 | GroupModel groupModel = GroupModel.getInstance(); 95 | for(Map.Entry e: oldGroupMap.entrySet() ){ 96 | int groupId = e.getKey(); 97 | int time = e.getValue(); 98 | groupModel.updateGroupTime(groupId, time); 99 | logger.info("Group " + groupId + " update to :" + time); 100 | } 101 | 102 | ConcurrentHashMap oldPersonalMap = new ConcurrentHashMap(); 103 | synchronized(mPersonalForUpdateMap) { 104 | ConcurrentHashMap tmpMap; 105 | tmpMap = mPersonalForUpdateMap; 106 | mPersonalForUpdateMap = oldPersonalMap; 107 | oldPersonalMap = tmpMap; 108 | } 109 | 110 | RelationshipModel relationModel = RelationshipModel.getInstance(); 111 | for(Map.Entry e: oldPersonalMap.entrySet() ){ 112 | String[] resultString = e.getKey().split(":"); 113 | int uA = Integer.parseInt(resultString[0]); 114 | int uB = Integer.parseInt(resultString[1]); 115 | int time = e.getValue(); 116 | relationModel.updateRelationShip(uA, uB, time); 117 | logger.info("user " + uA + " and " + uB + " update to :" + time); 118 | } 119 | 120 | sleep(mInterval); 121 | } 122 | } catch (Exception e) { 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/FileAction.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.util.List; 4 | 5 | import com.mogujie.ares.data.TransmitFile; 6 | import com.mogujie.ares.extend.BaseAction; 7 | import com.mogujie.ares.lib.logger.Logger; 8 | import com.mogujie.ares.lib.logger.LoggerFactory; 9 | import com.mogujie.ares.lib.net.DataBuffer; 10 | import com.mogujie.ares.model.FileModel; 11 | import com.mogujie.ares.util.MoguUtil; 12 | 13 | /** 14 | * 15 | * @Description: 用户相关的类 16 | * @author ziye - ziye[at]mogujie.com 17 | * @date 2013-8-12 下午4:55:45 18 | * 19 | */ 20 | public class FileAction extends BaseAction { 21 | 22 | private static final Logger logger = LoggerFactory 23 | .getLogger(FileAction.class); 24 | 25 | /* 26 | * 27 | * @Description: 存储离线文件的信息 28 | * 29 | * @param fromUserId 30 | * 31 | * @param userIds 32 | * 33 | * @return 34 | */ 35 | public DataBuffer addFileRecord(int commandId, int requestId, 36 | int fromUserId, int toUserId, String taskId, String filePath, int fileSize, 37 | int version) { 38 | logger.info("add file recored : " + "fromUserId=" + fromUserId 39 | + ", toUserId=" + toUserId + ", taskId = " + taskId + ", filePath=" + filePath); 40 | DataBuffer buffer; 41 | if (fromUserId <= 0 || toUserId <= 0 || filePath == null 42 | || "".equals(filePath)) { 43 | buffer = new DataBuffer(); 44 | buffer.writeInt(requestId); // request uuid 45 | buffer.writeInt(1); // result 46 | buffer.writeInt(commandId); // source commandId 47 | buffer.writeInt(fromUserId); // fromUserId 48 | buffer.writeInt(toUserId); // toUserId 49 | return buffer; 50 | } 51 | 52 | buffer = new DataBuffer(); 53 | buffer.writeInt(requestId); // request uuid 54 | boolean isSuccess = false; 55 | isSuccess = FileModel.getInstance().saveFileRecord(fromUserId, 56 | toUserId, taskId, filePath, fileSize); 57 | int result = isSuccess ? 0 : 2; 58 | buffer.writeInt(result); // result 59 | buffer.writeChar((char) commandId); // source commandId 60 | buffer.writeInt(fromUserId); // fromUserId 61 | buffer.writeInt(toUserId); // toUserId 62 | return buffer; 63 | } 64 | 65 | /* 66 | * 67 | * @Description: 删除离线文件的信息 68 | * 69 | * @param fromUserId 70 | * 71 | * @param userIds 72 | * 73 | * @return 74 | */ 75 | public DataBuffer removeFileRecord(int commandId, int requestId, 76 | int fromUserId, int toUserId, String taskId, int version) { 77 | logger.info("remove file recored : " + "taskId=" + taskId); 78 | DataBuffer buffer; 79 | if (null == taskId || taskId.isEmpty()) { 80 | buffer = new DataBuffer(); 81 | buffer.writeInt(requestId); // request uuid 82 | buffer.writeInt(1); // result 83 | buffer.writeChar((char) commandId); 84 | buffer.writeInt(fromUserId); // fromUserId 85 | buffer.writeInt(toUserId); // toUserId 86 | return buffer; 87 | } 88 | 89 | buffer = new DataBuffer(); 90 | buffer.writeInt(requestId); // request uuid 91 | TransmitFile file = FileModel.getInstance().getFileRecord(taskId); 92 | boolean isSuccess = false; 93 | int now = (int) (System.currentTimeMillis() / 1000); 94 | if (file != null && file.getStatus() == 1 95 | && file.getCreated() > now - 7 * 86400) { 96 | isSuccess = FileModel.getInstance().deleteFileRecord(taskId); 97 | } 98 | int result = isSuccess ? 0 : 2; 99 | buffer.writeInt(result); // result 100 | buffer.writeChar((char) commandId); 101 | buffer.writeInt(fromUserId); // fromUserId 102 | buffer.writeInt(toUserId); // toUserId 103 | return buffer; 104 | } 105 | 106 | /* 107 | * 108 | * @Description: 存储或删除立宪文件的信息 109 | * 110 | * @param fromUserId 111 | * 112 | * @param userIds 113 | * 114 | * @return 115 | */ 116 | public DataBuffer getFileRecord(int requestUserId, DataBuffer attachment, int version) { 117 | logger.info("-->> getFileRecord ->> get file recored : " 118 | + requestUserId); 119 | DataBuffer buffer; 120 | if (requestUserId <= 0) { 121 | buffer = new DataBuffer(); 122 | buffer.writeInt(requestUserId); // request uuid 123 | buffer.writeInt(0); // file count 124 | return MoguUtil.writeAttachments(buffer, attachment); 125 | } 126 | 127 | buffer = new DataBuffer(); 128 | List fileList = FileModel.getInstance().getUserFiles( 129 | requestUserId); // 这里不会返回null 130 | int size = fileList.size(); 131 | buffer.writeInt(requestUserId); // request userId 132 | buffer.writeInt(size); 133 | TransmitFile file = null; 134 | for (int i = 0; i < size; i++) { 135 | file = fileList.get(i); 136 | buffer.writeInt(file.getFromUserId()); 137 | buffer.writeString(file.getTaskId()); 138 | buffer.writeString(file.getFilePath()); 139 | buffer.writeInt(file.getFileSize()); 140 | } 141 | return MoguUtil.writeAttachments(buffer, attachment); 142 | } 143 | 144 | } 145 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/DepartAction.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.sql.SQLException; 4 | import java.util.Iterator; 5 | import java.util.Map; 6 | 7 | import com.mogujie.ares.data.Department; 8 | import com.mogujie.ares.extend.BaseAction; 9 | import com.mogujie.ares.lib.logger.Logger; 10 | import com.mogujie.ares.lib.logger.LoggerFactory; 11 | import com.mogujie.ares.lib.net.DataBuffer; 12 | import com.mogujie.ares.model.DepartModel; 13 | import com.mogujie.ares.util.MoguUtil; 14 | 15 | public class DepartAction extends BaseAction { 16 | private static final Logger logger = LoggerFactory 17 | .getLogger(DepartAction.class); 18 | 19 | /* 20 | * 21 | * @Description: 获取所有部门信息 22 | * 23 | * @param fromUserId 24 | * 25 | * @return 26 | */ 27 | public DataBuffer getDepartmentInfo(int fromUserId, DataBuffer attachment, 28 | int version) { 29 | logger.info("get all department info by user : " + fromUserId); 30 | DataBuffer buffer; 31 | if (fromUserId <= 0) { 32 | buffer = new DataBuffer(); 33 | buffer.writeInt(fromUserId); 34 | buffer.writeInt(0); 35 | buffer.writeInt(attachment.readableBytes()); 36 | if (attachment.readableBytes() > 0) { 37 | buffer.writeDataBuffer(attachment); 38 | } 39 | return buffer; 40 | } 41 | 42 | try { 43 | Map departments = DepartModel.getInstance() 44 | .getDepartmentInfo(); 45 | buffer = new DataBuffer(); 46 | buffer.writeInt(fromUserId); // 发请求的用户 47 | buffer.writeInt(departments.size()); // 查询到的部门个数 48 | Department department; 49 | Iterator it = departments.keySet().iterator(); 50 | while (it.hasNext()) { 51 | department = departments.get(it.next()); 52 | buffer.writeInt(department.getDepartId()); // 部门id 53 | buffer.writeString(department.getTitle()); // 部门标题 54 | buffer.writeString(department.getDescription()); // 部门描述 55 | buffer.writeInt(department.getParentDepartId()); // 上级部门ID 56 | buffer.writeInt(department.getLeader()); // 部门leader 57 | buffer.writeInt(department.getStatus()); // 部门状态 58 | } 59 | } catch (SQLException e) { 60 | logger.error("get all department info error with reason : ", e); 61 | buffer = new DataBuffer(); 62 | buffer.writeInt(fromUserId); 63 | buffer.writeInt(0); 64 | } 65 | 66 | return MoguUtil.writeAttachments(buffer, attachment); 67 | } 68 | 69 | // /** 70 | // * 71 | // * @Description: 获取组织架构信息(部门信息+员工) 72 | // * @param fromUserId 73 | // * @param departIds 74 | // * @return 75 | // */ 76 | // public DataBuffer getOrganizationalChart(int fromUserId, 77 | // DataBuffer attachment, int version) { 78 | // logger.info("get organizational chart by user : " + fromUserId); 79 | // DataBuffer buffer; 80 | // if (fromUserId <= 0) { 81 | // buffer = new DataBuffer(); 82 | // buffer.writeInt(fromUserId); 83 | // buffer.writeInt(0); 84 | // buffer.writeInt(attachment.readableBytes()); 85 | // if (attachment.readableBytes() > 0) { 86 | // buffer.writeDataBuffer(attachment); 87 | // } 88 | // return buffer; 89 | // } 90 | // 91 | // try { 92 | // Map departments = DepartModel.getInstance() 93 | // .getDepartmentInfo(); 94 | // buffer = new DataBuffer(); 95 | // buffer.writeInt(fromUserId); // 发请求的用户 96 | // buffer.writeInt(departments.size()); // 查询到详细信息的用户数 97 | // Department department; 98 | // Iterator it = departments.keySet().iterator(); 99 | // Set setUsers = null; 100 | // while (it.hasNext()) { 101 | // department = departments.get(it.next()); 102 | // buffer.writeInt(department.getDepartId()); // 部门id 103 | // buffer.writeString(department.getTitle()); // 部门标题 104 | // buffer.writeString(department.getDescription()); // 部门描述 105 | // buffer.writeInt(department.getParentDepartId()); // 上级部门ID 106 | // buffer.writeString(department.getLeader()); // 部门leader 107 | // buffer.writeInt(department.getStatus()); // 部门状态 108 | // 109 | // setUsers = UserModel.getInstance().getUserInfoByDepartId( 110 | // department.getDepartId()); 111 | // buffer.writeInt(setUsers.size()); // 部门人员数 112 | // Iterator itr = setUsers.iterator(); 113 | // User user = null; 114 | // while (itr.hasNext()) { 115 | // user = itr.next(); 116 | // buffer.writeInt(user.getUserId()); 117 | // buffer.writeInt(user.getSex()); 118 | // buffer.writeString(user.getUname()); 119 | // buffer.writeString(user.getUnick()); 120 | // buffer.writeString(user.getAvatar()); 121 | // buffer.writeString(user.getTitle()); 122 | // buffer.writeInt(user.getJobNumber()); 123 | // buffer.writeString(user.getMail()); 124 | // buffer.writeString(user.getTelphone()); 125 | // } 126 | // } 127 | // } catch (SQLException e) { 128 | // logger.error("get organizational chart error with reason : ", e); 129 | // buffer = new DataBuffer(); 130 | // buffer.writeInt(fromUserId); 131 | // buffer.writeInt(0); 132 | // } 133 | // 134 | // return MoguUtil.writeAttachments(buffer, attachment); 135 | // } 136 | } 137 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/lib/net/DataBuffer.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.lib.net; 2 | 3 | import java.util.List; 4 | 5 | import org.jboss.netty.buffer.ChannelBuffer; 6 | import org.jboss.netty.buffer.ChannelBuffers; 7 | 8 | /** 9 | * 10 | * @Description: 数据缓冲区对象,直接封装了netty的ChannelBuffer 11 | * @author ziye - ziye[at]mogujie.com 12 | * @date 2013-7-21 下午3:40:52 13 | * 14 | */ 15 | public class DataBuffer { 16 | 17 | protected ChannelBuffer buffer; 18 | 19 | public DataBuffer() { 20 | buffer = ChannelBuffers.dynamicBuffer(); 21 | } 22 | 23 | public DataBuffer(ChannelBuffer binaryBuffer) { 24 | buffer = binaryBuffer; 25 | } 26 | 27 | public DataBuffer(int length) { 28 | buffer = ChannelBuffers.buffer(length); 29 | } 30 | 31 | public byte[] array() { 32 | return buffer.array(); 33 | } 34 | 35 | public void setOrignalBuffer(ChannelBuffer buffer) { 36 | this.buffer = buffer; 37 | } 38 | 39 | public ChannelBuffer getOrignalBuffer() { 40 | return buffer; 41 | } 42 | 43 | public void writeByte(int value) { 44 | buffer.writeByte(value); 45 | } 46 | 47 | public byte readByte() { 48 | return buffer.readByte(); 49 | } 50 | 51 | public void writeBytes(byte[] bytes) { 52 | buffer.writeBytes(bytes); 53 | } 54 | 55 | public byte[] readBytes(int length) { 56 | byte[] bytes = new byte[length]; 57 | buffer.readBytes(bytes); 58 | return bytes; 59 | } 60 | 61 | public int readInt() { 62 | if(buffer.readable()){ 63 | return buffer.readInt(); 64 | }else{ 65 | return 0; 66 | } 67 | } 68 | 69 | public void writeInt(int value) { 70 | buffer.writeInt(value); 71 | } 72 | 73 | public char readChar() { 74 | return buffer.readChar(); 75 | } 76 | 77 | public void writeChar(char c) { 78 | buffer.writeChar(c); 79 | } 80 | 81 | public long readLong() { 82 | return buffer.readLong(); 83 | } 84 | 85 | public void writeLong(long value) { 86 | buffer.writeLong(value); 87 | } 88 | 89 | public double readDouble(){ 90 | return buffer.readDouble(); 91 | } 92 | 93 | public void writeDouble(double value){ 94 | buffer.writeDouble(value); 95 | } 96 | 97 | /** 98 | * 读取一个字符串 99 | * @return 100 | * 格式:前导length表示字符串的byte数 101 | * length(4字节)string(length字节) 102 | */ 103 | public String readString() { 104 | int length = readInt(); 105 | byte[] bytes = readBytes(length); 106 | 107 | return new String(bytes); 108 | } 109 | 110 | /** 111 | * 写入一个字符串 112 | * @param str 113 | * 数据格式见方法readString() 114 | */ 115 | public void writeString(String str) { 116 | byte[] bytes = str.getBytes(); 117 | writeInt(bytes.length); 118 | writeBytes(bytes); 119 | } 120 | 121 | /** 122 | * 读取int数组 123 | * @return 124 | * 格式:前导count表示数组中有多少个元素 125 | * count(4字节)int1(4字节)...intCount(4字节) 126 | */ 127 | public int[] readIntArray() { 128 | int count = readInt(); 129 | int[] intArray = new int[count]; 130 | for(int i = 0; i < count; i++) { 131 | intArray[i] = readInt(); 132 | } 133 | return intArray; 134 | } 135 | 136 | /** 137 | * 写入int数组 138 | * @param intArray 格式见readIntArray() 139 | */ 140 | public void writeIntArray(int[] intArray) { 141 | int count = intArray.length; 142 | writeInt(count); 143 | for(int i = 0; i < count; i++) { 144 | writeInt(intArray[i]); 145 | } 146 | } 147 | 148 | /** 149 | * 150 | * @Description: 写入一个int的list,list转数组太蛋疼了 151 | * @param intList 152 | */ 153 | public void writeIntList(List intList) { 154 | if(intList == null || intList.isEmpty()) { 155 | writeInt(0); 156 | return ; 157 | } 158 | int count = intList.size(); 159 | writeInt(count); 160 | for(int i = 0; i < count; i++) { 161 | writeInt(intList.get(i)); 162 | } 163 | } 164 | 165 | /** 166 | * 读取byte数组 167 | * @return 168 | * 格式:前导count表示数组中有多少个元素 169 | * count(4字节)byte1(4字节)...byteCount(4字节) 170 | */ 171 | public byte[] readByteArray() { 172 | int length = readInt(); // 获取长度 173 | byte[] bytes = new byte[length]; 174 | buffer.readBytes(bytes); 175 | return bytes; 176 | } 177 | 178 | /** 179 | * 写入byte数组 180 | * @param byteArray 格式见readByteArray() 181 | */ 182 | public void writeByteArray(byte[] byteArray) { 183 | int length = byteArray.length; 184 | writeInt(length); 185 | buffer.writeBytes(byteArray); 186 | } 187 | /** 188 | * 读取String数组 189 | * @return 190 | * 格式:前导count表示数组中有多少个元素 191 | * count(4字节)string1(4字节)...stringsCount(4字节) 192 | */ 193 | public String[] readStringArray() { 194 | int count = readInt(); // 获取长度 195 | String[] strArray = new String[count]; 196 | for(int i = 0; i < count; i++) { 197 | strArray[i] = readString(); 198 | } 199 | return strArray; 200 | } 201 | 202 | /** 203 | * 写入String数组 204 | * @param byteArray 格式见readStringArray() 205 | */ 206 | public void writeStringArray(String[] strArray) { 207 | int count = strArray.length; 208 | writeInt(count); 209 | for(int i = 0; i < count; i++) { 210 | writeString(strArray[i]); 211 | } 212 | } 213 | 214 | /** 215 | * 获取有效(可读取)的byte数 216 | * @return 217 | */ 218 | public int readableBytes() { 219 | return buffer.readableBytes(); 220 | } 221 | 222 | public DataBuffer readDataBuffer() { 223 | if(buffer == null || buffer.readableBytes() == 0) { 224 | return new DataBuffer(0); 225 | } 226 | int length = readInt(); 227 | DataBuffer dataBuffer = new DataBuffer(0); 228 | dataBuffer.setOrignalBuffer(buffer.readBytes(length)); 229 | return dataBuffer; 230 | } 231 | 232 | public void writeDataBuffer(DataBuffer inputBuffer) { 233 | if(inputBuffer == null || inputBuffer.readableBytes() == 0) { 234 | return ; 235 | } 236 | buffer.writeBytes(inputBuffer.buffer); 237 | } 238 | } 239 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/configure/Router.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.configure; 2 | 3 | import java.io.InputStream; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.LinkedHashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.dom4j.DocumentException; 11 | import org.dom4j.Node; 12 | import org.dom4j.io.SAXReader; 13 | 14 | /** 15 | * 16 | * @ClassName: Router 17 | * @Description: Action的路由配置信息类 18 | * @author ziye - ziye(at)mogujie.com 19 | * @date 2013-7-20 下午5:36:56 20 | */ 21 | public class Router { 22 | 23 | public static Router instance; 24 | 25 | // 路由的配置信息 26 | private Map actionMap = new HashMap(); 27 | 28 | public static Router getInstance() { 29 | if(instance == null) { 30 | instance = new Router(); 31 | } 32 | 33 | return instance; 34 | } 35 | 36 | private Router() { 37 | 38 | } 39 | 40 | public Map getActionMap() { 41 | return actionMap; 42 | } 43 | 44 | public void setActionMap(Map actionMap) { 45 | this.actionMap = actionMap; 46 | } 47 | 48 | /** 49 | * 50 | * @Title: getActionByRequestType 51 | * @Description: 根据头的type类型获得具体的action 52 | * @param @param type 53 | * @param @return 54 | * @return ActionItem 55 | * @throws 56 | */ 57 | public ActionDescricptor getActionByRequestType(int type) { 58 | return actionMap.get(type); 59 | } 60 | 61 | /** 62 | * 63 | * @Title: load 64 | * @Description: 装在配置,配置文件格式如下: 65 | * 66 | * 67 | * 68 | * com.mogujie.ares.extend.action.Monitor 69 | * heartbeat 70 | * 1 71 | * 1 72 | * 73 | * ${channel.remoteAddress} 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * @param @param file 82 | * @param @throws Exception 83 | * @return void 84 | * @throws 85 | */ 86 | @SuppressWarnings({"unchecked"}) 87 | public void load(String file) throws Exception { 88 | if(file == null || file.length() == 0) { 89 | throw new Exception("Route file is not specified!"); 90 | } 91 | 92 | InputStream is = Router.class.getClassLoader().getResourceAsStream(file); 93 | if(is == null) { 94 | throw new Exception("Route file is not found! " + file); 95 | } 96 | SAXReader reader = new SAXReader(); 97 | try { 98 | org.dom4j.Document configDocument = reader.read(is); 99 | List nodes = configDocument.selectNodes("//route/requests/request"); 100 | Node node; 101 | ActionDescricptor item; 102 | for(int i = 0; i < nodes.size(); i++) 103 | { 104 | item = new ActionDescricptor(); 105 | 106 | node = nodes.get(i); 107 | Node actionClassNode = node.selectSingleNode("action-class"); 108 | item.setActionClass(actionClassNode.getStringValue()); 109 | Node methodNode = node.selectSingleNode("method"); 110 | item.setMethod(methodNode.getStringValue()); 111 | Node requestTypeNode = node.selectSingleNode("request-type"); 112 | item.setRequestType(Integer.parseInt(requestTypeNode.getStringValue())); 113 | Node responseTypeNode = node.selectSingleNode("response-type"); 114 | item.setResponseType(Integer.parseInt(responseTypeNode.getStringValue())); 115 | 116 | // params 117 | Node paramsNode = node.selectSingleNode("params"); 118 | List paramNodes = paramsNode.selectNodes("*"); // 取得所有的子节点 119 | Map params = new LinkedHashMap(); 120 | Node param; 121 | for(int j = 0; j < paramNodes.size(); j++) { 122 | param = paramNodes.get(j); 123 | params.put(param.getStringValue(), param.getName()); 124 | } 125 | item.setParams(params); 126 | 127 | // filters 128 | Node filter; 129 | Node filtersNode = node.selectSingleNode("filters"); 130 | List filterNodes = filtersNode.selectNodes("*"); 131 | List filters = new ArrayList(); 132 | for(int j = 0; j < filterNodes.size(); j++) { 133 | filter = filterNodes.get(j); 134 | filters.add(filter.getStringValue()); 135 | } 136 | String[] str = new String[filters.size()]; 137 | filters.toArray(str); 138 | item.setFilters(str); 139 | 140 | actionMap.put(item.getRequestType(), item); 141 | } 142 | } catch (DocumentException e) { 143 | throw e; 144 | } 145 | } 146 | 147 | /** 148 | * 149 | * @ClassName: ActionItem 150 | * @Description: 单个Action的描述类 151 | * @author ziye - ziye(at)mogujie.com 152 | * @date 2013-7-20 下午5:42:09 153 | * 154 | */ 155 | public class ActionDescricptor{ 156 | 157 | // 类名 158 | private String actionClass; 159 | 160 | // 处理请求的方法名 161 | private String method; 162 | 163 | // 请求头的type,这种type的请求才处理 164 | private int requestType; 165 | 166 | // 响应的type 167 | private int responseType; 168 | 169 | // 请求的参数 170 | private Map params; 171 | 172 | // filter过滤 173 | private String[] filters; 174 | 175 | public ActionDescricptor() { 176 | } 177 | 178 | public String getActionClass() { 179 | return actionClass; 180 | } 181 | 182 | public void setActionClass(String actionClass) { 183 | this.actionClass = actionClass; 184 | } 185 | 186 | public String getMethod() { 187 | return method; 188 | } 189 | 190 | public void setMethod(String method) { 191 | this.method = method; 192 | } 193 | 194 | public int getRequestType() { 195 | return requestType; 196 | } 197 | 198 | public void setRequestType(int requestType) { 199 | this.requestType = requestType; 200 | } 201 | 202 | public Map getParams() { 203 | return params; 204 | } 205 | 206 | public void setParams(Map params) { 207 | this.params = params; 208 | } 209 | 210 | public String[] getFilters() { 211 | return filters; 212 | } 213 | 214 | public void setFilters(String[] filters) { 215 | this.filters = filters; 216 | } 217 | 218 | public int getResponseType() { 219 | return responseType; 220 | } 221 | 222 | public void setResponseType(int responseType) { 223 | this.responseType = responseType; 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/configure/PBRouter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.configure; 2 | 3 | import java.io.InputStream; 4 | import java.util.ArrayList; 5 | import java.util.HashMap; 6 | import java.util.LinkedHashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.dom4j.DocumentException; 11 | import org.dom4j.Node; 12 | import org.dom4j.io.SAXReader; 13 | 14 | /** 15 | * 16 | * @ClassName: Router 17 | * @Description: Action的路由配置信息类 18 | * @author ziye - ziye(at)mogujie.com 19 | * @date 2013-7-20 下午5:36:56 20 | */ 21 | public class PBRouter { 22 | 23 | public static PBRouter instance; 24 | 25 | // 路由的配置信息 26 | private Map actionMap = new HashMap(); 27 | 28 | public static PBRouter getInstance() { 29 | if(instance == null) { 30 | instance = new PBRouter(); 31 | } 32 | 33 | return instance; 34 | } 35 | 36 | private PBRouter() { 37 | 38 | } 39 | 40 | public Map getActionMap() { 41 | return actionMap; 42 | } 43 | 44 | public void setActionMap(Map actionMap) { 45 | this.actionMap = actionMap; 46 | } 47 | 48 | /** 49 | * 50 | * @Title: getActionByRequestType 51 | * @Description: 根据头的type类型获得具体的action 52 | * @param @param type 53 | * @param @return 54 | * @return ActionItem 55 | * @throws 56 | */ 57 | public ActionDescricptor getActionByRequestType(int type) { 58 | return actionMap.get(type); 59 | } 60 | 61 | /** 62 | * 63 | * @Title: load 64 | * @Description: 装在配置,配置文件格式如下: 65 | * 66 | * 67 | * 68 | * com.mogujie.ares.extend.action.Monitor 69 | * heartbeat 70 | * 1 71 | * 1 72 | * 73 | * ${channel.remoteAddress} 74 | * 75 | * 76 | * 77 | * 78 | * 79 | * 80 | * 81 | * @param @param file 82 | * @param @throws Exception 83 | * @return void 84 | * @throws 85 | */ 86 | @SuppressWarnings({"unchecked"}) 87 | public void load(String file) throws Exception { 88 | if(file == null || file.length() == 0) { 89 | throw new Exception("Route file is not specified!"); 90 | } 91 | 92 | InputStream is = PBRouter.class.getClassLoader().getResourceAsStream(file); 93 | if(is == null) { 94 | throw new Exception("Route file is not found! " + file); 95 | } 96 | SAXReader reader = new SAXReader(); 97 | try { 98 | org.dom4j.Document configDocument = reader.read(is); 99 | List nodes = configDocument.selectNodes("//route/requests/request"); 100 | Node node; 101 | ActionDescricptor item; 102 | for(int i = 0; i < nodes.size(); i++) 103 | { 104 | item = new ActionDescricptor(); 105 | 106 | node = nodes.get(i); 107 | Node actionClassNode = node.selectSingleNode("action-class"); 108 | item.setActionClass(actionClassNode.getStringValue()); 109 | Node methodNode = node.selectSingleNode("method"); 110 | item.setMethod(methodNode.getStringValue()); 111 | Node requestTypeNode = node.selectSingleNode("request-type"); 112 | item.setRequestType(Integer.parseInt(requestTypeNode.getStringValue())); 113 | Node responseTypeNode = node.selectSingleNode("response-type"); 114 | item.setResponseType(Integer.parseInt(responseTypeNode.getStringValue())); 115 | 116 | // params 117 | Node paramsNode = node.selectSingleNode("params"); 118 | List paramNodes = paramsNode.selectNodes("*"); // 取得所有的子节点 119 | Map params = new LinkedHashMap(); 120 | Node param; 121 | for(int j = 0; j < paramNodes.size(); j++) { 122 | param = paramNodes.get(j); 123 | params.put(param.getStringValue(), param.getName()); 124 | } 125 | item.setParams(params); 126 | 127 | // filters 128 | Node filter; 129 | Node filtersNode = node.selectSingleNode("filters"); 130 | List filterNodes = filtersNode.selectNodes("*"); 131 | List filters = new ArrayList(); 132 | for(int j = 0; j < filterNodes.size(); j++) { 133 | filter = filterNodes.get(j); 134 | filters.add(filter.getStringValue()); 135 | } 136 | String[] str = new String[filters.size()]; 137 | filters.toArray(str); 138 | item.setFilters(str); 139 | 140 | actionMap.put(item.getRequestType(), item); 141 | } 142 | } catch (DocumentException e) { 143 | throw e; 144 | } 145 | } 146 | 147 | /** 148 | * 149 | * @ClassName: ActionItem 150 | * @Description: 单个Action的描述类 151 | * @author ziye - ziye(at)mogujie.com 152 | * @date 2013-7-20 下午5:42:09 153 | * 154 | */ 155 | public class ActionDescricptor{ 156 | 157 | // 类名 158 | private String actionClass; 159 | 160 | // 处理请求的方法名 161 | private String method; 162 | 163 | // 请求头的type,这种type的请求才处理 164 | private int requestType; 165 | 166 | // 响应的type 167 | private int responseType; 168 | 169 | // 请求的参数 170 | private Map params; 171 | 172 | // filter过滤 173 | private String[] filters; 174 | 175 | public ActionDescricptor() { 176 | } 177 | 178 | public String getActionClass() { 179 | return actionClass; 180 | } 181 | 182 | public void setActionClass(String actionClass) { 183 | this.actionClass = actionClass; 184 | } 185 | 186 | public String getMethod() { 187 | return method; 188 | } 189 | 190 | public void setMethod(String method) { 191 | this.method = method; 192 | } 193 | 194 | public int getRequestType() { 195 | return requestType; 196 | } 197 | 198 | public void setRequestType(int requestType) { 199 | this.requestType = requestType; 200 | } 201 | 202 | public Map getParams() { 203 | return params; 204 | } 205 | 206 | public void setParams(Map params) { 207 | this.params = params; 208 | } 209 | 210 | public String[] getFilters() { 211 | return filters; 212 | } 213 | 214 | public void setFilters(String[] filters) { 215 | this.filters = filters; 216 | } 217 | 218 | public int getResponseType() { 219 | return responseType; 220 | } 221 | 222 | public void setResponseType(int responseType) { 223 | this.responseType = responseType; 224 | } 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/UserAction.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.sql.SQLException; 4 | import java.util.Arrays; 5 | import java.util.Iterator; 6 | import java.util.Map; 7 | import java.util.Set; 8 | 9 | import com.mogujie.ares.data.User; 10 | import com.mogujie.ares.extend.BaseAction; 11 | import com.mogujie.ares.lib.logger.Logger; 12 | import com.mogujie.ares.lib.logger.LoggerFactory; 13 | import com.mogujie.ares.lib.net.DataBuffer; 14 | import com.mogujie.ares.model.UserModel; 15 | import com.mogujie.ares.util.MoguUtil; 16 | 17 | /** 18 | * 19 | * @Description: 用户相关的类 20 | * @author ziye - ziye[at]mogujie.com 21 | * @date 2013-8-12 下午4:55:45 22 | * 23 | */ 24 | public class UserAction extends BaseAction { 25 | 26 | private static final Logger logger = LoggerFactory 27 | .getLogger(UserAction.class); 28 | 29 | /** 30 | * 31 | * @Description: 获取用户信息 32 | * @param fromUserId 33 | * @param userIds 34 | * @return 35 | */ 36 | public DataBuffer getUsersInfo(int fromUserId, int[] userIds, 37 | DataBuffer attachment, int version) { 38 | logger.info("get users info : " + Arrays.toString(userIds)); 39 | DataBuffer buffer; 40 | if (userIds == null || userIds.length <= 0) { 41 | buffer = new DataBuffer(); 42 | buffer.writeInt(fromUserId); 43 | buffer.writeInt(0); 44 | return MoguUtil.writeAttachments(buffer, attachment); 45 | } 46 | 47 | try { 48 | Map users = UserModel.getInstance().getUserInfo( 49 | userIds); 50 | buffer = new DataBuffer(); 51 | buffer.writeInt(fromUserId); // 发请求的用户 52 | buffer.writeInt(users.size()); // 查询到详细信息的用户数 53 | User user; 54 | Iterator it = users.keySet().iterator(); 55 | String logText = "response userInfo: "; 56 | while (it.hasNext()) { 57 | user = users.get(it.next()); 58 | buffer.writeInt(user.getUserId()); // 用户ID 59 | buffer.writeString(user.getUname()); // 用户名 60 | buffer.writeString(user.getUnick()); // 用户昵称 61 | buffer.writeString(user.getAvatar()); // 用户头像 62 | buffer.writeString(user.getTitle()); // 用户职称 63 | buffer.writeString(user.getPosition()); // 用户地址 64 | buffer.writeInt(user.getStatus()); // 用户在职等状态 65 | buffer.writeInt(user.getSex()); // 用户性别 66 | buffer.writeInt(user.getDepartId()); // 用户所在部门ID 67 | buffer.writeInt(user.getJobNumber()); // 用户工号 68 | buffer.writeString(user.getTelphone()); // 用户电话 69 | buffer.writeString(user.getMail()); // 用户邮箱 70 | logText += "userId=" + user.getUserId() + ", "; 71 | } 72 | logger.info(logText); 73 | } catch (SQLException e) { 74 | logger.error("get users info error with reason : ", e); 75 | buffer = new DataBuffer(); 76 | buffer.writeInt(fromUserId); 77 | buffer.writeInt(0); 78 | } 79 | 80 | return MoguUtil.writeAttachments(buffer, attachment); 81 | } 82 | 83 | /** 84 | * 85 | * @Description: 获取所有用户信息 86 | * @param fromUserId 87 | * @return 88 | */ 89 | public DataBuffer getAllUsersInfo(int fromUserId, DataBuffer attachment, 90 | int version) { 91 | logger.info("get all users info by : " + fromUserId); 92 | DataBuffer buffer; 93 | if (fromUserId <= 0) { 94 | buffer = new DataBuffer(); 95 | buffer.writeInt(fromUserId); 96 | buffer.writeInt(0); 97 | buffer.writeInt(attachment.readableBytes()); 98 | if (attachment.readableBytes() > 0) { 99 | buffer.writeDataBuffer(attachment); 100 | } 101 | return buffer; 102 | } 103 | 104 | try { 105 | Set users = UserModel.getInstance().getAllUserInfo(); 106 | buffer = new DataBuffer(); 107 | buffer.writeInt(fromUserId); // 发请求的用户 108 | buffer.writeInt(users.size()); // 查询到详细信息的用户数 109 | User user; 110 | Iterator it = users.iterator(); 111 | while (it.hasNext()) { 112 | user = it.next(); 113 | buffer.writeInt(user.getUserId()); // 用户ID 114 | buffer.writeString(user.getUname()); // 用户名 115 | buffer.writeString(user.getUnick()); // 用户昵称 116 | buffer.writeString(user.getAvatar()); // 用户头像 117 | buffer.writeString(user.getTitle()); // 用户职称 118 | buffer.writeString(user.getPosition()); // 用户地址 119 | buffer.writeInt(user.getStatus()); // 用户在职等状态 120 | buffer.writeInt(user.getSex()); // 用户性别 121 | buffer.writeInt(user.getDepartId()); // 用户所在部门ID 122 | buffer.writeInt(user.getJobNumber()); // 用户工号 123 | buffer.writeString(user.getTelphone()); // 用户电话 124 | buffer.writeString(user.getMail()); // 用户邮箱 125 | } 126 | } catch (SQLException e) { 127 | logger.error("get all user info error with reason", e); 128 | buffer = new DataBuffer(); 129 | buffer.writeInt(fromUserId); 130 | buffer.writeInt(0); 131 | } 132 | 133 | return MoguUtil.writeAttachments(buffer, attachment); 134 | } 135 | 136 | // /* 137 | // * @Description: 修改用户头像 138 | // * @param userId 139 | // * 用户Id 140 | // * @param avatar 141 | // * 用户头像url 142 | // * @return 143 | // */ 144 | // public DataBuffer alterAvatar(int userId, String avatar, 145 | // DataBuffer attachment, int version) { 146 | // // logger.info("login: " + userId + ", new avatar: " + avatar); 147 | // int resultCode = 0; 148 | // // 数据校验扔到model层,这里不需要判断 149 | // try { 150 | // resultCode = UserModel.getInstance().alterAvatar(userId, avatar); 151 | // } catch (Exception e) { 152 | // resultCode = 1; 153 | // logger.error("error: update user's avatar failed! userId: " 154 | // + userId + " avatar: " + avatar + e.toString()); 155 | // } 156 | // DataBuffer buffer = new DataBuffer(); 157 | // buffer.writeInt(userId); 158 | // buffer.writeInt(resultCode); 159 | // 160 | // return MoguUtil.writeAttachments(buffer, attachment); 161 | // } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/TimerManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import java.util.ArrayList; 4 | import java.util.HashMap; 5 | import java.util.Iterator; 6 | import java.util.List; 7 | import java.util.Map; 8 | import java.util.concurrent.ConcurrentHashMap; 9 | import java.util.concurrent.ExecutionException; 10 | import java.util.concurrent.ScheduledFuture; 11 | import java.util.concurrent.TimeUnit; 12 | 13 | import com.mogujie.ares.configure.SysConstants; 14 | import com.mogujie.ares.lib.logger.Logger; 15 | import com.mogujie.ares.lib.logger.LoggerFactory; 16 | import com.mogujie.ares.timer.Timer; 17 | 18 | /** 19 | * 20 | * @Description: 定时脚本管理 21 | * @author ziye - ziye[at]mogujie.com 22 | * @date 2013-7-22 下午1:03:05 23 | * 24 | * @param 25 | */ 26 | public class TimerManager 27 | { 28 | private static final Logger logger = LoggerFactory.getLogger(TimerManager.class); 29 | 30 | ConcurrentHashMap> timerConfigure = new ConcurrentHashMap>(); 31 | 32 | private List tasks = new ArrayList(); 33 | 34 | ConcurrentHashMap> taskFutures = new ConcurrentHashMap>(); 35 | 36 | private boolean isLaunch = false; 37 | 38 | private Timer timer; // 一个线程池 39 | 40 | private static TimerManager timerManagerInstance; 41 | 42 | public static TimerManager getInstance() 43 | { 44 | if(timerManagerInstance == null) 45 | { 46 | timerManagerInstance = new TimerManager(); 47 | } 48 | return timerManagerInstance; 49 | } 50 | 51 | private TimerManager() { 52 | initialize(); 53 | } 54 | 55 | /** 56 | * 57 | * @Description: 初始化 58 | */ 59 | private void initialize() 60 | { 61 | timerConfigure = ConfigureManager.getInstance().getTimerConfig(); 62 | 63 | timer = Timer.getInstance(); 64 | } 65 | 66 | /** 67 | * 68 | * @Description: 创建所有初始化的任务 69 | */ 70 | private void createInitializeAllTasks() 71 | { 72 | Iterator iter = timerConfigure.keySet().iterator(); 73 | while(iter.hasNext()) 74 | { 75 | String taskName = iter.next(); 76 | try { 77 | Class taskClass; 78 | taskClass = Class.forName(taskName); 79 | Object taskInstance = taskClass.newInstance(); 80 | if(taskInstance != null) { 81 | Runnable taskRunnable = (Runnable) taskInstance; 82 | tasks.add(taskRunnable); 83 | } 84 | } catch (ClassNotFoundException e) { 85 | logger.error("", e); 86 | } catch (InstantiationException e) { 87 | logger.error("", e); 88 | } catch (IllegalAccessException e) { 89 | logger.error("", e); 90 | } 91 | } 92 | } 93 | 94 | /** 95 | * 96 | * @throws Exception 97 | * @Description: 提交一个初始化的任务 98 | */ 99 | protected void submitInitialTasks() throws Exception 100 | { 101 | if(tasks.size() > 0) 102 | { 103 | Iterator iter = tasks.iterator(); 104 | while(iter.hasNext()) 105 | { 106 | try{ 107 | Runnable initialTask = iter.next(); 108 | HashMap taskConfig = timerConfigure.get(initialTask.getClass().getName()); 109 | if( ! taskConfig.get("enable").equals(SysConstants.TASK_ENABLE_RUN)) { 110 | continue; 111 | } 112 | 113 | String taskType = taskConfig.get("taskType"); 114 | if(taskType.equals("rateTask")) { 115 | submitFixedRateTask(initialTask); 116 | } else if(taskType.equals("delayTask")) { 117 | submitFixedDelayTask(initialTask); 118 | } else if(taskType.equals("oneShot")) { 119 | submitOneShotTask(initialTask); 120 | } 121 | } catch (Exception e) { 122 | throw e; 123 | } 124 | } 125 | } 126 | } 127 | 128 | /** 129 | * 130 | * @Description: 初始化加载 131 | * @throws Exception 132 | */ 133 | public void lanuch() throws Exception 134 | { 135 | if( ! isLaunch) 136 | { 137 | createInitializeAllTasks(); 138 | 139 | submitInitialTasks(); 140 | } 141 | } 142 | 143 | /** 144 | * 提交定时类task 145 | */ 146 | public void submitFixedRateTask(Runnable task) 147 | { 148 | logger.info("submit fixed rate task"); 149 | String taskName = task.getClass().getName(); 150 | long initialDelay = Integer.valueOf(timerConfigure.get(taskName).get("initdelay")); 151 | long period = Integer.valueOf(timerConfigure.get(taskName).get("periodordelay")); 152 | taskFutures.put(taskName, timer.submitFixedRateTask(task, initialDelay, period, TimeUnit.SECONDS)); 153 | } 154 | 155 | /** 156 | * 提交delay循环执行的task 157 | */ 158 | public void submitFixedDelayTask(Runnable task) 159 | { 160 | String taskName = task.getClass().getName(); 161 | long initialDelay = Integer.valueOf(timerConfigure.get(taskName).get("initialdelay")); 162 | long delay = Integer.valueOf(timerConfigure.get(taskName).get("periodordelay")); 163 | taskFutures.put(taskName, timer.submitFixedDelayTask(task, initialDelay, delay, TimeUnit.SECONDS)); 164 | } 165 | 166 | /** 167 | * 提交仅执行一次的task 168 | */ 169 | public void submitOneShotTask(Runnable task) 170 | { 171 | String taskName = task.getClass().getName(); 172 | long initialDelay = Integer.valueOf(timerConfigure.get(taskName).get("initaildelay")); 173 | taskFutures.put(taskName, timer.submitOneShotTask(task, initialDelay, TimeUnit.SECONDS)); 174 | } 175 | 176 | /** 177 | * 178 | * @Description: 关闭定时任务 179 | */ 180 | public void shutDown() 181 | { 182 | if(timer != null) 183 | { 184 | timer.shutDown(); 185 | 186 | clean(); 187 | } 188 | } 189 | 190 | /** 191 | * 192 | * @Description: 关闭定时任务,不等待当前自然结束 193 | */ 194 | public void shutDownNow() 195 | { 196 | if(timer != null) 197 | { 198 | timer.shutDownNow(); 199 | 200 | clean(); 201 | } 202 | } 203 | 204 | /** 205 | * 206 | * @Description: 擦屁股 207 | */ 208 | private void clean() 209 | { 210 | if(taskFutures.size() > 0) 211 | { 212 | taskFutures.clear(); 213 | } 214 | 215 | if(tasks.size() > 0) 216 | { 217 | tasks.clear(); 218 | } 219 | } 220 | 221 | /** 222 | * 检查task是否都完成了,如果没有,则堵塞调用的线程 223 | */ 224 | public void checkTasksCompleted() 225 | { 226 | if(taskFutures.size() > 0) 227 | { 228 | Iterator>> iter = taskFutures.entrySet().iterator(); 229 | while(iter.hasNext()) 230 | { 231 | Map.Entry> entry = iter.next(); 232 | try { 233 | entry.getValue().get(); // 这里会wait 234 | } catch (InterruptedException e) { 235 | logger.error("", e); 236 | } catch (ExecutionException e) { 237 | logger.error("", e); 238 | } 239 | } 240 | } 241 | } 242 | } 243 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | 5 | com.mogujie 6 | mogutalk-business 7 | 0.0.1-SNAPSHOT 8 | jar 9 | 10 | mogutalk-business 11 | http://maven.apache.org 12 | 13 | 14 | 15 | 16 | UTF-8 17 | 1.6 18 | STDOUT 19 | db-dev.properties 20 | cache-dev.properties 21 | 22 | 23 | 24 | 25 | product 26 | 27 | 28 | db-online.properties 29 | cache-online.properties 30 | 31 | 32 | 33 | 34 | 35 | 36 | dom4j 37 | dom4j 38 | 1.6 39 | 40 | 41 | jaxen 42 | jaxen 43 | 1.1.4 44 | 45 | 46 | mysql 47 | mysql-connector-java 48 | 5.1.25 49 | 50 | 51 | com.google.code.maven-play-plugin.org.allcolor.shanidom 52 | jaxen 53 | 1.1.1-patched-shani-1.4.17 54 | 55 | 56 | dom4j 57 | dom4j 58 | 1.6.1 59 | 60 | 61 | com.google.guava 62 | guava 63 | 14.0.1 64 | 65 | 66 | com.alibaba 67 | druid 68 | 0.2.9 69 | 70 | 71 | redis.clients 72 | jedis 73 | 2.0.0 74 | jar 75 | compile 76 | 77 | 78 | io.netty 79 | netty 80 | 3.6.6.Final 81 | 82 | 83 | 84 | org.slf4j 85 | jcl-over-slf4j 86 | 1.7.2 87 | 88 | 89 | ch.qos.logback 90 | logback-core 91 | 0.9.29 92 | 93 | 94 | ch.qos.logback 95 | logback-classic 96 | 0.9.29 97 | 98 | 99 | slf4j-api 100 | org.slf4j 101 | 102 | 103 | ch.qos.logback 104 | logback-core 105 | 106 | 107 | 108 | 109 | org.apache.httpcomponents 110 | httpclient 111 | 4.3.3 112 | 113 | 114 | commons-httpclient 115 | commons-httpclient 116 | 3.1 117 | 118 | 119 | commons-util 120 | commons-util 121 | final 122 | 123 | 124 | commons-lang 125 | commons-lang 126 | 2.6 127 | 128 | 129 | com.fasterxml.jackson.core 130 | jackson-core 131 | 2.3.2 132 | 133 | 134 | org.codehaus.jackson 135 | jackson-core-lgpl 136 | 1.9.13 137 | 138 | 139 | org.codehaus.jackson 140 | jackson-core-asl 141 | 1.9.13 142 | 143 | 144 | org.codehaus.jackson 145 | jackson-mapper-asl 146 | 1.9.13 147 | 148 | 149 | 150 | 151 | junit 152 | junit 153 | 4.8.1 154 | test 155 | 156 | 157 | 158 | 159 | 160 | org.apache.maven.plugins 161 | maven-surefire-plugin 162 | 2.4.2 163 | 164 | true 165 | 166 | 167 | 168 | maven-assembly-plugin 169 | 170 | false 171 | 172 | jar-with-dependencies 173 | 174 | 175 | 176 | com.mogujie.ares.MainServer 177 | 178 | 179 | 180 | 181 | 182 | make-assembly 183 | package 184 | 185 | assembly 186 | 187 | 188 | 189 | 190 | 191 | org.apache.maven.plugins 192 | maven-compiler-plugin 193 | 2.3.2 194 | 195 | ${version.jdk} 196 | ${version.jdk} 197 | ${project.build.sourceEncoding} 198 | 199 | 200 | 201 | org.apache.maven.plugins 202 | maven-resources-plugin 203 | 204 | ${project.build.sourceEncoding} 205 | 206 | 207 | 208 | 209 | 210 | src/main/resources 211 | true 212 | 213 | 214 | 215 | 216 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/Friendship.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.sql.SQLException; 4 | import java.util.HashMap; 5 | import java.util.Map; 6 | 7 | import com.mogujie.ares.configure.BizConstants; 8 | import com.mogujie.ares.data.Group; 9 | import com.mogujie.ares.data.Relationship; 10 | import com.mogujie.ares.data.User; 11 | import com.mogujie.ares.extend.BaseAction; 12 | import com.mogujie.ares.lib.logger.Logger; 13 | import com.mogujie.ares.lib.logger.LoggerFactory; 14 | import com.mogujie.ares.lib.net.DataBuffer; 15 | import com.mogujie.ares.model.GroupModel; 16 | import com.mogujie.ares.model.RelationshipModel; 17 | import com.mogujie.ares.model.UserModel; 18 | import com.mogujie.ares.util.MoguUtil; 19 | 20 | /* 21 | * @Description: 好友相关的请求 22 | * @author ziye - ziye[at]mogujie.com 23 | * @date 2013-7-21 下午1:27:09 24 | */ 25 | public class Friendship extends BaseAction { 26 | 27 | private static final Logger logger = LoggerFactory 28 | .getLogger(Friendship.class); 29 | private static User serviceUser; // 服务号小T 30 | private static Map mapFilterUserIds = new HashMap();// 要过滤的用户id 31 | 32 | public Friendship() { 33 | try { 34 | serviceUser = UserModel.getInstance().getServerUserInfo(); 35 | if (null == serviceUser) { 36 | throw new IllegalArgumentException( 37 | "can't initialize server user info"); 38 | } 39 | mapFilterUserIds.put(serviceUser.getUserId(), 1); 40 | } catch (SQLException e) { 41 | logger.error("initialize server user info error with reason : ", e); 42 | } 43 | } 44 | 45 | /* 46 | * 47 | * @Description: 获取用户的最近联系人 48 | * 49 | * @param userId 用户id 50 | * 51 | * @return 52 | */ 53 | public DataBuffer getUserRecentContact(int userId, DataBuffer attachment, 54 | int version) { 55 | DataBuffer buffer = null; 56 | 57 | if (userId <= 0) { 58 | buffer = new DataBuffer(); 59 | buffer.writeInt(userId); 60 | buffer.writeInt(0); 61 | return MoguUtil.writeAttachments(buffer, attachment); 62 | } 63 | 64 | DataBuffer tmpBuffer = new DataBuffer(); 65 | buffer = new DataBuffer(); 66 | buffer.writeInt(userId); 67 | int count = 0; 68 | StringBuffer logBuffer = new StringBuffer(); 69 | 70 | try { 71 | logger.info("get recent contact list by " + userId); 72 | // 取好友列表 73 | Relationship[] friendshipArray = RelationshipModel.getInstance() 74 | .getRecentContactByUserId(userId, 100); 75 | 76 | if (serviceUser != null) { 77 | mapFilterUserIds.put(serviceUser.getUserId(), 1); 78 | tmpBuffer.writeInt(serviceUser.getUserId()); 79 | tmpBuffer.writeInt(1767200461); // 2026-01-01 服务号默认置顶 80 | count++; 81 | } 82 | int fuid; 83 | if (friendshipArray != null && friendshipArray.length > 0) { 84 | for (int i = 0; i < friendshipArray.length; i++) { 85 | fuid = friendshipArray[i].getFriendUserId(); 86 | if (mapFilterUserIds.containsKey(fuid)) { 87 | continue; 88 | } 89 | tmpBuffer.writeInt(fuid); 90 | tmpBuffer.writeInt(friendshipArray[i].getUpdated()); 91 | logBuffer.append(", " + fuid + "-updateTime = " + friendshipArray[i].getUpdated() ); // log 92 | count++; 93 | } 94 | } 95 | } catch (SQLException e) { 96 | logger.error("get recent contact list error with reason : ", e); 97 | } 98 | logger.info("get recent contact list: userId=" + userId + ", friends:" 99 | + logBuffer.toString()); 100 | if (tmpBuffer != null && tmpBuffer.readableBytes() > 0) { 101 | buffer.writeInt(count); 102 | buffer.writeDataBuffer(tmpBuffer); 103 | } else { 104 | buffer.writeInt(0); 105 | } 106 | 107 | return MoguUtil.writeAttachments(buffer, attachment); 108 | } 109 | 110 | /* 111 | * 112 | * @Description: 删除用户的最近联系人或群 113 | * 114 | * @param userId 用户id 115 | * 116 | * @param friendUserId 最近联系ID 117 | * 118 | * @param friendUserType 最近联系ID类型:1用户;2群 119 | * 120 | * @return 121 | */ 122 | public DataBuffer deleteUserRecentContact(int userId, int friendUserId, 123 | int friendUserType, DataBuffer attachment, int version) { 124 | DataBuffer buffer = null; 125 | 126 | if (userId <= 0 || friendUserId <= 0 || friendUserType <= 0 127 | || BizConstants.SYS_SERVER_USER_ID == friendUserId) { 128 | buffer = new DataBuffer(); 129 | buffer.writeInt(userId); 130 | buffer.writeInt(0); 131 | buffer.writeInt(friendUserId); 132 | buffer.writeInt(friendUserType); 133 | return MoguUtil.writeAttachments(buffer, attachment); 134 | } 135 | 136 | boolean isSuccess = false; 137 | try { 138 | if (1 == friendUserType) { 139 | isSuccess = RelationshipModel.getInstance() 140 | .deleteRecentContactByUserId(userId, friendUserId); 141 | } else { 142 | Group group = GroupModel.getInstance().getGroupInfo( 143 | friendUserId); 144 | // 如果群不存在则删除失败,群主也能将自己建的群从最近联系群中删除 145 | if (group == null || friendUserId != group.getGroupId()) { 146 | isSuccess = false; 147 | } else { 148 | isSuccess = GroupModel.getInstance() 149 | .deleteRecentContactByGroupId(userId, friendUserId, 150 | group); 151 | } 152 | } 153 | } catch (SQLException e) { 154 | logger.error("delete recent contact error: userId = " + userId 155 | + ", friendUserId = " + friendUserId + ", friendUserType =" 156 | + friendUserType, e); 157 | } 158 | 159 | buffer = new DataBuffer(); 160 | buffer.writeInt(userId); // 用户Id 161 | if (isSuccess) { // 成功 162 | logger.info("delete recent contact success: result=" + isSuccess 163 | + ", userId=" + userId + ", friendUserId = " + friendUserId 164 | + ", friendUserType = " + friendUserType); 165 | buffer.writeInt(0); // 结果 166 | buffer.writeInt(friendUserId); 167 | buffer.writeInt(friendUserType); 168 | } else { // 失败 169 | logger.info("delete recent contact error: result=" + isSuccess 170 | + ", userId=" + userId + ", friendUserId = " + friendUserId 171 | + ", friendUserType = " + friendUserType); 172 | buffer.writeInt(1); // 结果 173 | buffer.writeInt(friendUserId); 174 | buffer.writeInt(friendUserType); 175 | } 176 | 177 | return MoguUtil.writeAttachments(buffer, attachment); 178 | } 179 | 180 | } 181 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/manager/ElegantStopManager.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.manager; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.FileWriter; 8 | import java.io.IOException; 9 | import java.util.Iterator; 10 | import java.util.Map; 11 | import java.util.concurrent.ConcurrentHashMap; 12 | import java.util.concurrent.ExecutorService; 13 | import java.util.concurrent.TimeUnit; 14 | 15 | import org.jboss.netty.channel.ChannelHandlerContext; 16 | 17 | import com.mogujie.ares.configure.BizConstants; 18 | import com.mogujie.ares.configure.SysConstants; 19 | import com.mogujie.ares.lib.logger.Logger; 20 | import com.mogujie.ares.lib.logger.LoggerFactory; 21 | import com.mogujie.ares.lib.net.DataBuffer; 22 | import com.mogujie.ares.lib.net.Packet; 23 | 24 | /** 25 | * 26 | * @Description: 传说中石头的优雅退出,单例 27 | * @author shitou - shitou[at]mogujie.com 28 | * @date 2013-7-22 上午11:15:53 29 | * 30 | */ 31 | public class ElegantStopManager 32 | { 33 | private int port = 0; 34 | 35 | public static final Logger logger = LoggerFactory.getLogger(ElegantStopManager.class); 36 | 37 | private static ElegantStopManager instance = null; 38 | 39 | public static ElegantStopManager getInstance(int port) 40 | { 41 | if(instance == null) 42 | { 43 | instance = new ElegantStopManager(); 44 | instance.port = port; 45 | instance.initialize(); 46 | } 47 | return instance; 48 | } 49 | 50 | public void initialize() 51 | { 52 | resetStopConfigFileContent(); 53 | generateShutDownShellFile(); 54 | } 55 | 56 | /** 57 | * 启动的时候,重置文件内容 58 | */ 59 | public void resetStopConfigFileContent() 60 | { 61 | File stopConfigFile = new File(getShutDownFilePath()); 62 | if(stopConfigFile.exists()) 63 | { 64 | stopConfigFile.delete(); 65 | } 66 | } 67 | 68 | /** 69 | * 判断是否停止正在运行的实例 70 | * @return 71 | */ 72 | public boolean isStopCurrentJavaInstance() 73 | { 74 | boolean isStop = false; 75 | File stopConfigFile = new File(getShutDownFilePath()); 76 | // 文件不存在则新建个文件 77 | if( ! stopConfigFile.exists()) 78 | { 79 | try { 80 | stopConfigFile.createNewFile(); 81 | } catch (IOException e) { 82 | logger.error("", e); 83 | } 84 | return isStop; 85 | } 86 | 87 | BufferedReader bufferedReader = null; 88 | try { 89 | bufferedReader = new BufferedReader(new FileReader(stopConfigFile)); 90 | String stopFileContent = bufferedReader.readLine(); 91 | isStop = SysConstants.ELEGANT_STOP_CONTENT.equals(stopFileContent); 92 | } catch (FileNotFoundException e) { 93 | logger.error("", e); 94 | } catch (IOException e) { 95 | logger.error("", e); 96 | } finally { 97 | try { 98 | if(bufferedReader != null) { 99 | bufferedReader.close(); 100 | } 101 | } catch (IOException e) { 102 | logger.error("", e); 103 | } 104 | } 105 | return isStop; 106 | } 107 | 108 | /** 109 | * @Description: 包装一个停止的数据包, type=200 110 | * @return 111 | */ 112 | protected Packet generateStopReceivePacket() 113 | { 114 | Packet stopPacket = new Packet(); 115 | stopPacket.setLength(SysConstants.PROTOCOL_HEADER_LENGTH + 4); 116 | stopPacket.setVersion(SysConstants.PROTOCOL_PREVIOUS_VERSION); 117 | stopPacket.setFlag((byte)0); 118 | stopPacket.setServiceId(BizConstants.DEFAULT_SERVICEID); 119 | stopPacket.setCommandId(BizConstants.COMMANDID_STOP_RECEIVE); 120 | stopPacket.setError((char)0); 121 | stopPacket.setReserved((char)0); 122 | DataBuffer dataBuffer = new DataBuffer(4); // 数据部分 123 | dataBuffer.writeInt(1); 124 | stopPacket.setContentBuffer(dataBuffer); 125 | return stopPacket; 126 | } 127 | 128 | /** 129 | * 130 | * @Description: netty停止接收数据 131 | * 向每个客户端都发一个即将关闭的数据包,告诉她们:“我要挂了~” 132 | */ 133 | public void nettyStopReceivePacket() 134 | { 135 | ConcurrentHashMap nettyClients = NetworkManager.getInstance().getClientMap(); 136 | if(nettyClients.size() > 0) 137 | { 138 | Iterator> iter = nettyClients.entrySet().iterator(); 139 | while(iter.hasNext()) 140 | { 141 | Map.Entry entry = iter.next(); 142 | 143 | ChannelHandlerContext nettyClient = entry.getValue(); 144 | nettyClient.getChannel().write(generateStopReceivePacket()); 145 | } 146 | } 147 | 148 | } 149 | 150 | /** 151 | * 152 | * @Description: 退出系统 153 | */ 154 | public void shutdown() { 155 | 156 | //告诉MsgServer,停止发送新的数据,并断开连接 157 | nettyStopReceivePacket(); 158 | 159 | //断开netty 160 | NetworkManager networkManager = NetworkManager.getInstance(); 161 | if(networkManager != null) { 162 | 163 | //检查是否还有work thread,如果有,sleep 164 | ExecutorService executor = NetworkManager.getInstance().getNettyWorkerTheadPool(); 165 | //可能需要先暂停,再调用awaitTermination 166 | executor.shutdown(); 167 | try { 168 | if( executor != null && !executor.awaitTermination(10, TimeUnit.SECONDS)) 169 | { 170 | executor.shutdownNow(); 171 | logger.error("Unable to completed all netty works"); 172 | } 173 | } catch (InterruptedException e) { 174 | executor.shutdownNow(); 175 | logger.error("", e); 176 | } 177 | 178 | networkManager.shutdown(); 179 | } 180 | 181 | //关闭Timer 182 | TimerManager timerManager = TimerManager.getInstance(); 183 | if(timerManager != null) { 184 | 185 | timerManager.shutDown(); 186 | 187 | //检查timer是否关闭完成了,如果没有,则sleep 188 | timerManager.checkTasksCompleted(); 189 | 190 | } 191 | 192 | //关闭DB 193 | DBManager dbManager = DBManager.getInstance(); 194 | if(dbManager != null) { 195 | DBManager.getInstance().shutDown(); 196 | } 197 | //关闭cache 198 | CacheManager cacheManager = CacheManager.getInstance(); 199 | if(cacheManager != null) { 200 | CacheManager.getInstance().shutDown(); 201 | } 202 | } 203 | 204 | /** 205 | * 获取shutdown的文件路径 206 | * @return 207 | */ 208 | public String getShutDownFilePath() 209 | { 210 | String filePath = null; 211 | if(port > 0) 212 | { 213 | filePath = SysConstants.ELEGANT_STOP_FILE + port; 214 | } 215 | return filePath; 216 | } 217 | 218 | /** 219 | * 生成shutdown文件 220 | */ 221 | public void generateShutDownShellFile() 222 | { 223 | if(port > 0) 224 | { 225 | String shutDownShell = "echo " + SysConstants.ELEGANT_STOP_CONTENT + " > " + getShutDownFilePath(); 226 | FileWriter fileWriter = null; 227 | try { 228 | File shellFile = new File(SysConstants.ELEGANT_SHUTDOWN_SHELL_SCRIPT + port + ".sh"); 229 | if( ! shellFile.exists()) 230 | { 231 | shellFile.createNewFile(); 232 | } 233 | fileWriter = new FileWriter(shellFile); 234 | fileWriter.write(shutDownShell); 235 | fileWriter.flush(); 236 | } catch (IOException e) { 237 | logger.error("", e); 238 | } finally { 239 | if(fileWriter != null) 240 | { 241 | try { 242 | fileWriter.close(); 243 | } catch (IOException e) { 244 | logger.error(" ", e); 245 | } 246 | } 247 | } 248 | } 249 | } 250 | 251 | /** 252 | * 253 | * @Description: 启动检查是否关闭storage的线程 254 | */ 255 | public void startCheckShutdownThread() 256 | { 257 | new Thread( 258 | new Runnable() { 259 | @Override 260 | public void run() { 261 | 262 | while(true) 263 | { 264 | if(isStopCurrentJavaInstance()) //是否需要停止 265 | { 266 | shutdown(); 267 | //关闭该线程 268 | break; 269 | } 270 | try { 271 | Thread.sleep(SysConstants.CHECK_STOP_GAP_TIME); 272 | } catch (InterruptedException e) { 273 | logger.error("", e); 274 | } 275 | } 276 | } 277 | } 278 | ).start(); 279 | } 280 | 281 | } 282 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/extend/action/MessageCounter.java: -------------------------------------------------------------------------------- 1 | package com.mogujie.ares.extend.action; 2 | 3 | import java.sql.SQLException; 4 | import java.util.Iterator; 5 | import java.util.List; 6 | import java.util.Map; 7 | import java.util.Map.Entry; 8 | 9 | import com.mogujie.ares.data.Counter; 10 | import com.mogujie.ares.data.Group; 11 | import com.mogujie.ares.extend.BaseAction; 12 | import com.mogujie.ares.lib.logger.Logger; 13 | import com.mogujie.ares.lib.logger.LoggerFactory; 14 | import com.mogujie.ares.lib.net.DataBuffer; 15 | import com.mogujie.ares.model.CounterModel; 16 | import com.mogujie.ares.model.GroupModel; 17 | import com.mogujie.ares.model.MessageModel; 18 | import com.mogujie.ares.util.MoguUtil; 19 | 20 | public class MessageCounter extends BaseAction { 21 | 22 | private static final Logger logger = LoggerFactory 23 | .getLogger(MessageCounter.class); 24 | 25 | /* 26 | * 获得未读消息计数 27 | * 28 | * @param userId 请求的用户ID 29 | */ 30 | public DataBuffer unread(int userId, DataBuffer attachment, int version) { 31 | logger.info("unread count: userId=" + userId); 32 | DataBuffer buffer = new DataBuffer(); 33 | buffer.writeInt(userId); 34 | 35 | Counter userUnreadCount = CounterModel.getInstance().getUnreadMsgCount( 36 | userId); 37 | Map userUnreadInfo = userUnreadCount.getUnreadCount(); 38 | String unreadCounterList = ""; 39 | if (userUnreadInfo != null && userUnreadInfo.size() > 0) { 40 | buffer.writeInt(userUnreadInfo.size()); 41 | Iterator> iter = userUnreadInfo 42 | .entrySet().iterator(); 43 | int uid; 44 | int count; 45 | while (iter.hasNext()) { 46 | Map.Entry entry = iter.next(); 47 | uid = Integer.valueOf(entry.getKey()); 48 | count = Integer.valueOf(entry.getValue()); 49 | buffer.writeInt(uid); 50 | buffer.writeInt(count); 51 | unreadCounterList += uid + "=" + count + ", "; 52 | } 53 | } else { 54 | buffer.writeInt(0); 55 | } 56 | logger.info("return unread count: userId = " + userId + " - " 57 | + unreadCounterList); 58 | 59 | return MoguUtil.writeAttachments(buffer, attachment); 60 | } 61 | 62 | /* 63 | * @auther ziye 64 | * 65 | * @Description: 清理消息计数,已读 66 | * 67 | * @param commandId 68 | * 69 | * @param requestId 70 | * 71 | * @param userId 72 | * 73 | * @param friendUserId 74 | * 75 | * @return 76 | */ 77 | public DataBuffer clear(int commandId, int requestId, int userId, 78 | int friendUserId, int version) { 79 | logger.info("clear counter: requestId=" + requestId + ", userId=" 80 | + userId + ", friendUserId=" + friendUserId); 81 | 82 | int result = 0; 83 | if (!CounterModel.getInstance().clearUserUnreadItemCount(userId, 84 | friendUserId)) { 85 | result = 1; 86 | } 87 | try { 88 | MessageModel.getInstance().deleteUserReadedDialogMessages(userId, 89 | friendUserId); 90 | } catch (SQLException e) { 91 | logger.error("", e); 92 | } 93 | 94 | DataBuffer responseBuffer = new DataBuffer(); 95 | responseBuffer.writeInt(requestId); 96 | responseBuffer.writeInt(result); 97 | responseBuffer.writeChar((char) commandId); 98 | responseBuffer.writeInt(userId); 99 | responseBuffer.writeInt(friendUserId); 100 | 101 | return responseBuffer; 102 | } 103 | 104 | /* 105 | * 106 | * @Description: 获取群未读消息 107 | * 108 | * @param userId 109 | * 110 | * @param attachment 111 | * 112 | * @param version 113 | * 114 | * @return 115 | */ 116 | public DataBuffer groupUnread(int userId, DataBuffer attachment, int version) { 117 | logger.info("group unread count: userId=" + userId); 118 | DataBuffer buffer = new DataBuffer(); 119 | buffer.writeInt(userId); 120 | 121 | String values = ""; 122 | try { 123 | List groups = GroupModel.getInstance().getGroupsByUserId( 124 | userId, false); 125 | if (groups != null && !groups.isEmpty()) { 126 | int groupCount = groups.size(); 127 | int[] groupIds = new int[groupCount]; 128 | Group groupInfo = null; 129 | for (int i = 0; i < groupCount; i++) { 130 | groupInfo = groups.get(i); 131 | if (groupInfo != null && groupInfo.getGroupId() > 0) { 132 | groupIds[i] = groupInfo.getGroupId(); 133 | } 134 | } 135 | Map userUnreadCount = CounterModel 136 | .getInstance() 137 | .getUserGroupUnreadCount(userId, groupIds); 138 | if (userUnreadCount != null && !userUnreadCount.isEmpty()) { 139 | values = userUnreadCount.toString(); 140 | DataBuffer tempDataBuffer = new DataBuffer(); 141 | Iterator> it = userUnreadCount 142 | .entrySet().iterator(); 143 | int groupId = 0; 144 | int count = 0; 145 | int num = 0; 146 | Entry entry = null; 147 | while (it.hasNext()) { 148 | entry = it.next(); 149 | groupId = entry.getKey(); 150 | count = entry.getValue(); 151 | if (groupId > 0 && count > 0) { 152 | tempDataBuffer.writeInt(groupId); 153 | tempDataBuffer.writeInt(count); 154 | num++; 155 | } 156 | } 157 | buffer.writeInt(num); 158 | if (num > 0) { 159 | buffer.writeDataBuffer(tempDataBuffer); 160 | } 161 | } else { 162 | buffer.writeInt(0); 163 | } 164 | } else { 165 | buffer.writeInt(0); 166 | } 167 | } catch (SQLException e) { 168 | logger.error("group unread, userId" + userId, e); 169 | buffer.writeInt(0); 170 | } 171 | 172 | logger.info("return group unread count: userId = " + userId + " - " 173 | + values); 174 | 175 | return MoguUtil.writeAttachments(buffer, attachment); 176 | } 177 | 178 | /* 179 | * @auther ziye 180 | * 181 | * @Description: 清除用户在这个群的未读消息计数,全部置为已读 182 | * 183 | * @param commandId 184 | * 185 | * @param requestId 186 | * 187 | * @param userId 188 | * 189 | * @param friendUserId 190 | * 191 | * @return 192 | */ 193 | public DataBuffer clearUserGroup(int commandId, int userId, int groupId, 194 | int version) { 195 | logger.info("clear counter: userId=" + userId + ", groupId=" + groupId); 196 | 197 | int result = 0; 198 | if (!CounterModel.getInstance().clearUserGroupCounter(userId, groupId)) { 199 | result = 1; 200 | } 201 | 202 | DataBuffer buffer = new DataBuffer(); 203 | buffer.writeInt(0); 204 | buffer.writeInt(result); 205 | buffer.writeChar((char) commandId); 206 | buffer.writeInt(userId); 207 | buffer.writeInt(groupId); 208 | 209 | return buffer; 210 | } 211 | 212 | } 213 | -------------------------------------------------------------------------------- /src/main/java/com/mogujie/ares/model/AudioModel.java: -------------------------------------------------------------------------------- 1 | /** 2 | * unread construct 3 | * userId => { 4 | * firendUserId => count 5 | * } 6 | * key construct : u + userId 7 | * 8 | * markread construct 9 | * userId => { 10 | * firendUserId => count 11 | * ... 12 | * } 13 | * key construct : m + userId 14 | * 15 | */ 16 | package com.mogujie.ares.model; 17 | 18 | import java.sql.Connection; 19 | import java.sql.PreparedStatement; 20 | import java.sql.ResultSet; 21 | import java.sql.SQLException; 22 | import java.sql.Statement; 23 | import java.util.Arrays; 24 | import java.util.HashMap; 25 | import java.util.Iterator; 26 | import java.util.Map; 27 | 28 | import org.apache.commons.lang.StringUtils; 29 | 30 | import com.mogujie.ares.util.MoguArrayUtil; 31 | import com.mogujie.ares.util.MoguByteUtil; 32 | import com.mogujie.ares.data.Audio; 33 | import com.mogujie.ares.lib.logger.Logger; 34 | import com.mogujie.ares.lib.logger.LoggerFactory; 35 | import com.mogujie.ares.manager.DBManager; 36 | import com.mogujie.ares.manager.DBManager.DBPoolName; 37 | import com.mogujie.ares.manager.FileManager; 38 | 39 | /** 40 | * 41 | * @Description: 计数器相关操作 42 | * @author shitou - shitou[at]mogujie.com 43 | * @date 2013-7-22 下午2:19:39 44 | * 45 | */ 46 | public class AudioModel 47 | { 48 | 49 | private static AudioModel instance; 50 | private static final Logger logger = LoggerFactory.getLogger(AudioModel.class); 51 | 52 | 53 | public static AudioModel getInstance() 54 | { 55 | if(instance == null) 56 | { 57 | instance = new AudioModel(); 58 | } 59 | return instance; 60 | } 61 | 62 | private AudioModel(){} 63 | 64 | /** 65 | * 66 | * @Description: 保持一个语音文件并返回语音路径 67 | * @param bytes 68 | * @param userId 69 | * @param toUserId 70 | * @return 保持的audioid 71 | */ 72 | public Audio saveAudio(int userId, int toUserId, Audio audio, int created) { 73 | 74 | if(audio == null || audio.getData() == null 75 | || audio.getData().length <= 0 || audio.getCostTime() <= 0) { 76 | return null; 77 | } 78 | 79 | byte[] data = audio.getData(); 80 | String path = FileManager.getInstance().saveAudioBinary(data); 81 | if(StringUtils.isEmpty(path)) { 82 | return null; 83 | } 84 | audio.setCreated(created); 85 | audio.setFileSize(data.length); 86 | audio.setPath(path); 87 | audio.setUserId(userId); 88 | audio.setToUserId(toUserId); 89 | int id = saveAudioInfo(audio); 90 | audio.setId(id); 91 | return audio; 92 | } 93 | 94 | public Audio parseAudio(byte[] bytes) { 95 | if(bytes.length <= 4) { return null; } 96 | Audio audio = null; 97 | try { 98 | byte[] costByte = Arrays.copyOfRange(bytes, 0, 4); 99 | byte[] data = Arrays.copyOfRange(bytes, 4, bytes.length); 100 | int cost = MoguByteUtil.getInstance().convert2Int(costByte); 101 | if(cost <= 0) { 102 | return null; 103 | } 104 | audio = new Audio(); 105 | audio.setCostTime(cost); 106 | audio.setData(data); 107 | } catch(Exception e) { 108 | return null; 109 | } 110 | return audio; 111 | } 112 | 113 | /** 114 | * 115 | * @Description: 数据库记录语音文件的路径 116 | * @param userId 117 | * @param toUserId 118 | * @param path 119 | * @param size 120 | * @param created 121 | * @return 122 | */ 123 | private int saveAudioInfo(Audio audio) { 124 | DBManager dbManager = DBManager.getInstance(); 125 | Connection conn = dbManager.getConnection(DBPoolName.macim_master); 126 | PreparedStatement statement = null; 127 | ResultSet rs = null; 128 | int succCount = 0; 129 | int id = 0; 130 | try { 131 | String sql = "insert into IMAudio(`userId`, `toUserId`, `path`, `fileSize`, `costTime`, `created`) " + 132 | "values(?, ?, ?, ?, ?, ?)"; 133 | statement = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); 134 | int index = 1; 135 | statement.setInt(index++, audio.getUserId()); 136 | statement.setInt(index++, audio.getToUserId()); 137 | statement.setString(index++, audio.getPath()); 138 | statement.setInt(index++, audio.getFileSize()); 139 | statement.setInt(index++, audio.getCostTime()); 140 | statement.setInt(index++, audio.getCreated()); 141 | succCount = statement.executeUpdate(); 142 | if(succCount > 0) { 143 | rs = statement.getGeneratedKeys(); 144 | if(rs.next()) { 145 | id = rs.getInt(1); 146 | } 147 | } 148 | } catch (SQLException e) { 149 | logger.error(audio.getUserId() + " - " + audio.getToUserId() + " - " + audio.getPath(), e); 150 | } finally { 151 | dbManager.release(DBPoolName.macim_master, conn, statement, null); 152 | } 153 | 154 | return id; 155 | } 156 | 157 | /** 158 | * 159 | * @Description: 读取语音额外信息,除语音内容外 160 | * @param audioIds 161 | * @return 162 | */ 163 | public Map getAudiosInfo(int[] audioIds) { 164 | Map audioMap = new HashMap(); 165 | if(audioIds == null || audioIds.length == 0) { 166 | return audioMap; 167 | } 168 | DBManager dbManager = DBManager.getInstance(); 169 | Connection conn = dbManager.getConnection(DBPoolName.macim_slave); 170 | PreparedStatement statement = null; 171 | ResultSet rs = null; 172 | try { 173 | StringBuilder sb = new StringBuilder("select * from IMAudio where id in ("); 174 | int length = audioIds.length; 175 | int cnt = 0; 176 | for(int i = 0; i < length; i++) { 177 | if(audioIds[i] <= 0) {continue;} 178 | sb.append("?,"); 179 | cnt++; 180 | } 181 | if(cnt <= 0) { 182 | return audioMap; 183 | } 184 | String sql = sb.subSequence(0, sb.length() - 1) + ")"; 185 | statement = conn.prepareStatement(sql); 186 | int index = 1; 187 | for(int i = 0; i < length; i++) { 188 | if(audioIds[i] <= 0) {continue;} 189 | statement.setInt(index++, audioIds[i]); 190 | } 191 | rs = statement.executeQuery(); 192 | 193 | Audio audio; 194 | while(rs.next()) { 195 | audio = new Audio(); 196 | audio.setId(rs.getInt("id")); 197 | audio.setUserId(rs.getInt("userId")); 198 | audio.setToUserId(rs.getInt("toUserId")); 199 | audio.setPath(rs.getString("path")); 200 | audio.setFileSize(rs.getInt("fileSize")); 201 | audio.setCostTime(rs.getInt("costTime")); 202 | audio.setCreated(rs.getInt("created")); 203 | audioMap.put(audio.getId(), audio); 204 | } 205 | } catch (SQLException e) { 206 | logger.error(Arrays.toString(audioIds), e); 207 | } finally { 208 | dbManager.release(DBPoolName.macim_slave, conn, statement, rs); 209 | } 210 | 211 | return audioMap; 212 | } 213 | 214 | /** 215 | * 216 | * @Description: 读取一段语音的详细信息,包括语音文件内容 217 | * @param audioIds 218 | * @return 219 | */ 220 | public Map readAudios(int[] audioIds) { 221 | Map audioMap = new HashMap(); 222 | if(audioIds == null || audioIds.length == 0) { 223 | return audioMap; 224 | } 225 | audioIds = MoguArrayUtil.getInstance().arrayUnique(audioIds); 226 | audioMap = getAudiosInfo(audioIds); 227 | logger.info("read audios:" + Arrays.toString(audioIds)); 228 | if(!audioMap.isEmpty()) { 229 | Iterator