wildfire chat server source initial submit
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
package com.xiaoleilu.loServer;
|
||||
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.DateUtil;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.action.ClassUtil;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.ActionHandler;
|
||||
import com.xiaoleilu.loServer.handler.HttpFileServerHandler;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.codec.http.HttpServerCodec;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LoServer starter<br>
|
||||
* 用于启动服务器的主对象<br>
|
||||
* 使用LoServer.start()启动服务器<br>
|
||||
* 服务的Action类和端口等设置在ServerSetting中设置
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LoFileServer {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(LoFileServer.class);
|
||||
private int port;
|
||||
private IMessagesStore messagesStore;
|
||||
private Channel channel;
|
||||
|
||||
public LoFileServer(int port, IMessagesStore messagesStore) {
|
||||
this.port = port;
|
||||
this.messagesStore = messagesStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void start() throws InterruptedException {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// Configure the server.
|
||||
final EventLoopGroup bossGroup = new NioEventLoopGroup(1);
|
||||
final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
try {
|
||||
final ServerBootstrap b = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_BACKLOG, 1024) // 服务端可连接队列大小
|
||||
.option(ChannelOption.SO_KEEPALIVE, true)
|
||||
.option(ChannelOption.SO_REUSEADDR, true)
|
||||
.option(ChannelOption.TCP_NODELAY, true)
|
||||
.option(ChannelOption.SO_SNDBUF, 1024*1024*10)
|
||||
.option(ChannelOption.SO_RCVBUF, 1024*1024*10)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
socketChannel.pipeline().addLast(new HttpRequestDecoder());
|
||||
socketChannel.pipeline().addLast(new HttpResponseEncoder());
|
||||
socketChannel.pipeline().addLast(new ChunkedWriteHandler());
|
||||
socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));
|
||||
socketChannel.pipeline().addLast(new HttpFileServerHandler());
|
||||
}
|
||||
});
|
||||
|
||||
channel = b.bind(port).sync().channel();
|
||||
Logger.info("***** Welcome To LoServer on port [{}], startting spend {}ms *****", port, DateUtil.spendMs(start));
|
||||
} finally {
|
||||
|
||||
}
|
||||
}
|
||||
public void shutdown() {
|
||||
if (this.channel != null) {
|
||||
this.channel.close();
|
||||
try {
|
||||
this.channel.closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package com.xiaoleilu.loServer;
|
||||
|
||||
import com.xiaoleilu.hutool.util.DateUtil;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.AdminActionHandler;
|
||||
import com.xiaoleilu.loServer.handler.IMActionHandler;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.netty.bootstrap.ServerBootstrap;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelInitializer;
|
||||
import io.netty.channel.ChannelOption;
|
||||
import io.netty.channel.EventLoopGroup;
|
||||
import io.netty.channel.nio.NioEventLoopGroup;
|
||||
import io.netty.channel.socket.SocketChannel;
|
||||
import io.netty.channel.socket.nio.NioServerSocketChannel;
|
||||
import io.netty.handler.codec.http.HttpObjectAggregator;
|
||||
import io.netty.handler.codec.http.HttpRequestDecoder;
|
||||
import io.netty.handler.codec.http.HttpResponseEncoder;
|
||||
import io.netty.handler.stream.ChunkedWriteHandler;
|
||||
import com.xiaoleilu.loServer.action.ClassUtil;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* LoServer starter<br>
|
||||
* 用于启动服务器的主对象<br>
|
||||
* 使用LoServer.start()启动服务器<br>
|
||||
* 服务的Action类和端口等设置在ServerSetting中设置
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class LoServer {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(LoServer.class);
|
||||
private int port;
|
||||
private int adminPort;
|
||||
private IMessagesStore messagesStore;
|
||||
private ISessionsStore sessionsStore;
|
||||
private Channel channel;
|
||||
private Channel adminChannel;
|
||||
|
||||
public LoServer(int port, int adminPort, IMessagesStore messagesStore, ISessionsStore sessionsStore) {
|
||||
this.port = port;
|
||||
this.adminPort = adminPort;
|
||||
this.messagesStore = messagesStore;
|
||||
this.sessionsStore = sessionsStore;
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动服务
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void start() throws InterruptedException {
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
// Configure the server.
|
||||
final EventLoopGroup bossGroup = new NioEventLoopGroup(2);
|
||||
final EventLoopGroup workerGroup = new NioEventLoopGroup();
|
||||
|
||||
registerAllAction();
|
||||
|
||||
try {
|
||||
final ServerBootstrap b = new ServerBootstrap();
|
||||
final ServerBootstrap adminB = new ServerBootstrap();
|
||||
b.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||
.option(ChannelOption.SO_REUSEADDR, true)
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.childOption(ChannelOption.SO_SNDBUF, 1024*64)
|
||||
.childOption(ChannelOption.SO_RCVBUF, 1024*64)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
socketChannel.pipeline().addLast(new HttpRequestDecoder());
|
||||
socketChannel.pipeline().addLast(new HttpResponseEncoder());
|
||||
socketChannel.pipeline().addLast(new ChunkedWriteHandler());
|
||||
socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));
|
||||
socketChannel.pipeline().addLast(new IMActionHandler(messagesStore, sessionsStore));
|
||||
}
|
||||
});
|
||||
|
||||
channel = b.bind(port).sync().channel();
|
||||
|
||||
|
||||
adminB.group(bossGroup, workerGroup)
|
||||
.channel(NioServerSocketChannel.class)
|
||||
.option(ChannelOption.SO_BACKLOG, 10240) // 服务端可连接队列大小
|
||||
.childOption(ChannelOption.SO_KEEPALIVE, true)
|
||||
.option(ChannelOption.SO_REUSEADDR, true)
|
||||
.childOption(ChannelOption.TCP_NODELAY, true)
|
||||
.childOption(ChannelOption.SO_SNDBUF, 1024*64)
|
||||
.childOption(ChannelOption.SO_RCVBUF, 1024*64)
|
||||
.childHandler(new ChannelInitializer<SocketChannel>() {
|
||||
@Override
|
||||
protected void initChannel(SocketChannel socketChannel) throws Exception {
|
||||
socketChannel.pipeline().addLast(new HttpRequestDecoder());
|
||||
socketChannel.pipeline().addLast(new HttpResponseEncoder());
|
||||
socketChannel.pipeline().addLast(new ChunkedWriteHandler());
|
||||
socketChannel.pipeline().addLast(new HttpObjectAggregator(100 * 1024 * 1024));
|
||||
socketChannel.pipeline().addLast(new AdminActionHandler(messagesStore, sessionsStore));
|
||||
}
|
||||
});
|
||||
|
||||
adminChannel = adminB.bind(adminPort).sync().channel();
|
||||
Logger.info("***** Welcome To LoServer on port [{},{}], startting spend {}ms *****", port, adminPort, DateUtil.spendMs(start));
|
||||
} finally {
|
||||
|
||||
}
|
||||
}
|
||||
public void shutdown() {
|
||||
if (this.channel!= null) {
|
||||
this.channel.close();
|
||||
try {
|
||||
this.channel.closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
if (this.adminChannel != null) {
|
||||
this.adminChannel.close();
|
||||
try {
|
||||
this.adminChannel.closeFuture().sync();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void registerAllAction() {
|
||||
try {
|
||||
for (Class cls:ClassUtil.getAllAssignedClass(Action.class)
|
||||
) {
|
||||
if(cls.getAnnotation(Route.class) != null) {
|
||||
ServerSetting.setAction((Class<? extends Action>)cls);
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (ClassNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer;
|
||||
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
public class RestResult {
|
||||
|
||||
|
||||
int code;
|
||||
String msg;
|
||||
Object result;
|
||||
|
||||
public static RestResult ok(Object object) {
|
||||
return resultOf(ErrorCode.ERROR_CODE_SUCCESS, ErrorCode.ERROR_CODE_SUCCESS.getMsg(), object);
|
||||
}
|
||||
|
||||
public static RestResult ok() {
|
||||
return resultOf(ErrorCode.ERROR_CODE_SUCCESS, ErrorCode.ERROR_CODE_SUCCESS.getMsg(), null);
|
||||
}
|
||||
|
||||
public static RestResult resultOf(ErrorCode errorCode) {
|
||||
return resultOf(errorCode, errorCode.msg, null);
|
||||
}
|
||||
|
||||
public static RestResult resultOf(ErrorCode errorCode, String msg) {
|
||||
return resultOf(errorCode, msg, null);
|
||||
}
|
||||
|
||||
public static RestResult resultOf(ErrorCode errorCode, String msg, Object object) {
|
||||
RestResult result = new RestResult();
|
||||
result.code = errorCode.code;
|
||||
result.msg = msg;
|
||||
result.result = object;
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setErrorCode(ErrorCode errorCode) {
|
||||
setCode(errorCode.code);
|
||||
}
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public Object getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(Object result) {
|
||||
this.result = result;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
package com.xiaoleilu.loServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.xiaoleilu.hutool.lang.Singleton;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.FileUtil;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.action.DefaultIndexAction;
|
||||
import com.xiaoleilu.loServer.action.UnknownErrorAction;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.exception.ServerSettingException;
|
||||
import com.xiaoleilu.loServer.filter.Filter;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 全局设定文件
|
||||
* @author xiaoleilu
|
||||
*
|
||||
*/
|
||||
public class ServerSetting {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(ServerSetting.class);
|
||||
|
||||
//-------------------------------------------------------- Default value start
|
||||
/** 默认的字符集编码 */
|
||||
public final static String DEFAULT_CHARSET = "utf-8";
|
||||
|
||||
public final static String MAPPING_ALL = "/*";
|
||||
|
||||
public final static String MAPPING_ERROR = "/_error";
|
||||
//-------------------------------------------------------- Default value end
|
||||
|
||||
/** 字符编码 */
|
||||
private static String charset = DEFAULT_CHARSET;
|
||||
/** 端口 */
|
||||
private static int port = 8090;
|
||||
/** 根目录 */
|
||||
private static File root;
|
||||
/** Filter映射表 */
|
||||
private static Map<String, Filter> filterMap;
|
||||
/** Action映射表 */
|
||||
private static Map<String, Action> getActionMap;
|
||||
private static Map<String, Action> postActionMap;
|
||||
private static Map<String, Action> putActionMap;
|
||||
private static Map<String, Action> deleteActionMap;
|
||||
private static Map<String, Action> errorActionMap;
|
||||
|
||||
static{
|
||||
filterMap = new ConcurrentHashMap<String, Filter>();
|
||||
|
||||
getActionMap = new ConcurrentHashMap<String, Action>();
|
||||
postActionMap = new ConcurrentHashMap<String, Action>();
|
||||
|
||||
putActionMap = new ConcurrentHashMap<String, Action>();
|
||||
|
||||
deleteActionMap = new ConcurrentHashMap<String, Action>();
|
||||
|
||||
errorActionMap = new ConcurrentHashMap<String, Action>();
|
||||
errorActionMap.put(StrUtil.SLASH, new DefaultIndexAction());
|
||||
errorActionMap.put(MAPPING_ERROR, new UnknownErrorAction());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获取编码
|
||||
*/
|
||||
public static String getCharset() {
|
||||
return charset;
|
||||
}
|
||||
/**
|
||||
* @return 字符集
|
||||
*/
|
||||
public static Charset charset() {
|
||||
return Charset.forName(getCharset());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置编码
|
||||
* @param charset 编码
|
||||
*/
|
||||
public static void setCharset(String charset) {
|
||||
ServerSetting.charset = charset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 监听端口
|
||||
*/
|
||||
public static int getPort() {
|
||||
return port;
|
||||
}
|
||||
/**
|
||||
* 设置监听端口
|
||||
* @param port 端口
|
||||
*/
|
||||
public static void setPort(int port) {
|
||||
ServerSetting.port = port;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------------------------- Root start
|
||||
/**
|
||||
* @return 根目录
|
||||
*/
|
||||
public static File getRoot() {
|
||||
return root;
|
||||
}
|
||||
/**
|
||||
* @return 根目录
|
||||
*/
|
||||
public static boolean isRootAvailable() {
|
||||
if(root != null && root.isDirectory() && root.isHidden() == false && root.canRead()){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* @return 根目录
|
||||
*/
|
||||
public static String getRootPath() {
|
||||
return FileUtil.getAbsolutePath(root);
|
||||
}
|
||||
/**
|
||||
* 根目录
|
||||
* @param root 根目录绝对路径
|
||||
*/
|
||||
public static void setRoot(String root) {
|
||||
ServerSetting.root = FileUtil.mkdir(root);
|
||||
Logger.debug("Set root to [{}]", ServerSetting.root.getAbsolutePath());
|
||||
}
|
||||
/**
|
||||
* 根目录
|
||||
* @param root 根目录绝对路径
|
||||
*/
|
||||
public static void setRoot(File root) {
|
||||
if(root.exists() == false){
|
||||
root.mkdirs();
|
||||
}else if(root.isDirectory() == false){
|
||||
throw new ServerSettingException(StrUtil.format("{} is not a directory!", root.getPath()));
|
||||
}
|
||||
ServerSetting.root = root;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------- Root end
|
||||
|
||||
//----------------------------------------------------------------------------------------------- Filter start
|
||||
/**
|
||||
* @return 获取FilterMap
|
||||
*/
|
||||
public static Map<String, Filter> getFilterMap() {
|
||||
return filterMap;
|
||||
}
|
||||
/**
|
||||
* 获得路径对应的Filter
|
||||
* @param path 路径,为空时将获得 根目录对应的Action
|
||||
* @return Filter
|
||||
*/
|
||||
public static Filter getFilter(String path){
|
||||
if(StrUtil.isBlank(path)){
|
||||
path = StrUtil.SLASH;
|
||||
}
|
||||
return getFilterMap().get(path.trim());
|
||||
}
|
||||
/**
|
||||
* 设置FilterMap
|
||||
* @param filterMap FilterMap
|
||||
*/
|
||||
public static void setFilterMap(Map<String, Filter> filterMap) {
|
||||
ServerSetting.filterMap = filterMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Filter类,已有的Filter类将被覆盖
|
||||
* @param path 拦截路径(必须以"/"开头)
|
||||
* @param filter Action类
|
||||
*/
|
||||
public static void setFilter(String path, Filter filter) {
|
||||
if(StrUtil.isBlank(path)){
|
||||
path = StrUtil.SLASH;
|
||||
}
|
||||
|
||||
if(null == filter) {
|
||||
Logger.warn("Added blank action, pass it.");
|
||||
return;
|
||||
}
|
||||
//所有路径必须以 "/" 开头,如果没有则补全之
|
||||
if(false == path.startsWith(StrUtil.SLASH)) {
|
||||
path = StrUtil.SLASH + path;
|
||||
}
|
||||
|
||||
ServerSetting.filterMap.put(path, filter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Filter类,已有的Filter类将被覆盖
|
||||
* @param path 拦截路径(必须以"/"开头)
|
||||
* @param filterClass Filter类
|
||||
*/
|
||||
public static void setFilter(String path, Class<? extends Filter> filterClass) {
|
||||
setFilter(path, (Filter)Singleton.get(filterClass));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------- Filter end
|
||||
|
||||
//----------------------------------------------------------------------------------------------- Action start
|
||||
/**
|
||||
* @return 获取ActionMap
|
||||
*/
|
||||
public static Map<String, Action> getActionMap(String method) {
|
||||
if (method.equals("GET")) {
|
||||
return getActionMap;
|
||||
} else if(method.equals("POST")) {
|
||||
return postActionMap;
|
||||
} else if(method.equals("PUT")) {
|
||||
return putActionMap;
|
||||
} else if(method.equals("DELETE")) {
|
||||
return deleteActionMap;
|
||||
}
|
||||
return getActionMap;
|
||||
}
|
||||
|
||||
public static Action getErrorAction(String path) {
|
||||
return errorActionMap.get(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得路径对应的Action
|
||||
* @param path 路径,为空时将获得 根目录对应的Action
|
||||
* @return Action
|
||||
*/
|
||||
public static Action getAction(String path, String method){
|
||||
if(StrUtil.isBlank(path)){
|
||||
path = StrUtil.SLASH;
|
||||
}
|
||||
return getActionMap(method).get(path.trim());
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Action类,已有的Action类将被覆盖
|
||||
* @param path 拦截路径(必须以"/"开头)
|
||||
* @param action Action类
|
||||
*/
|
||||
public static void setAction(String path, Action action) {
|
||||
if(StrUtil.isBlank(path)){
|
||||
path = StrUtil.SLASH;
|
||||
}
|
||||
|
||||
if(null == action) {
|
||||
Logger.warn("Added blank action, pass it.");
|
||||
return;
|
||||
}
|
||||
//所有路径必须以 "/" 开头,如果没有则补全之
|
||||
if(false == path.startsWith(StrUtil.SLASH)) {
|
||||
path = StrUtil.SLASH + path;
|
||||
}
|
||||
String method = "GET";
|
||||
HttpMethod methodAnnotation = action.getClass().getAnnotation(HttpMethod.class);
|
||||
if (methodAnnotation != null) {
|
||||
method = methodAnnotation.value();
|
||||
}
|
||||
ServerSetting.getActionMap(method).put(path, action);
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加Action类,已有的Action类将被覆盖<br>
|
||||
* 所有Action都是以单例模式存在的!
|
||||
* @param path 拦截路径(必须以"/"开头)
|
||||
* @param actionClass Action类
|
||||
*/
|
||||
public static void setAction(String path, Class<? extends Action> actionClass) {
|
||||
setAction(path, (Action)Singleton.get(actionClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加Action类,已有的Action类将被覆盖<br>
|
||||
* 自动读取Route的注解来获得Path路径
|
||||
* @param action 带注解的Action对象
|
||||
*/
|
||||
public static void setAction(Action action) {
|
||||
final Route route = action.getClass().getAnnotation(Route.class);
|
||||
if(route != null){
|
||||
final String path = route.value();
|
||||
if(StrUtil.isNotBlank(path)){
|
||||
setAction(path, action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ServerSettingException("Can not find Route annotation,please add annotation to Action class!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加Action类,已有的Action类将被覆盖<br>
|
||||
* 所有Action都是以单例模式存在的!
|
||||
* @param actionClass 带注解的Action类
|
||||
*/
|
||||
public static void setAction(Class<? extends Action> actionClass) {
|
||||
setAction((Action)Singleton.get(actionClass));
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------- Action start
|
||||
|
||||
}
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.admin.GetIMTokenAction;
|
||||
import com.xiaoleilu.loServer.annotation.RequireAuthentication;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.DBUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
import static win.liyufan.im.ErrorCode.ERROR_CODE_SUCCESS;
|
||||
|
||||
/**
|
||||
* 请求处理接口<br>
|
||||
* 当用户请求某个Path,则调用相应Action的doAction方法
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
|
||||
abstract public class Action {
|
||||
public static IMessagesStore messagesStore = null;
|
||||
public static ISessionsStore sessionsStore = null;
|
||||
|
||||
public ChannelHandlerContext ctx;
|
||||
|
||||
protected boolean isSync = true;
|
||||
|
||||
public ErrorCode preAction(Request request, Response response) {
|
||||
if (getClass().getAnnotation(RequireAuthentication.class) != null) {
|
||||
//do authentication
|
||||
}
|
||||
|
||||
return ERROR_CODE_SUCCESS;
|
||||
}
|
||||
public boolean doAction(Request request, Response response) {
|
||||
ErrorCode errorCode = preAction(request, response);
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
//事务逻辑有缺陷,先注释掉
|
||||
// if (isTransactionAction() && !(this instanceof IMAction)) {
|
||||
// DBUtil.beginTransaction();
|
||||
// try {
|
||||
// action(request, response);
|
||||
// DBUtil.commit();
|
||||
// } catch (Exception e) {
|
||||
// e.printStackTrace();
|
||||
// DBUtil.roolback();
|
||||
// throw e;
|
||||
// }
|
||||
// } else {
|
||||
action(request, response);
|
||||
// }
|
||||
afterAction(request, response);
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if (errorCode == null) {
|
||||
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), RestResult.resultOf(errorCode));
|
||||
response.setContent(new Gson().toJson(result));
|
||||
response.send();
|
||||
}
|
||||
|
||||
if(this instanceof IMAction || this instanceof RouteAction || this instanceof GetIMTokenAction) {
|
||||
isSync = false;
|
||||
}
|
||||
return isSync;
|
||||
}
|
||||
public boolean isTransactionAction() {
|
||||
return false;
|
||||
}
|
||||
abstract public void action(Request request, Response response);
|
||||
public void afterAction(Request request, Response response) {
|
||||
|
||||
}
|
||||
|
||||
|
||||
protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {
|
||||
if (request instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
Gson gson = new Gson();
|
||||
T t = gson.fromJson(content, cls);
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
import java.util.jar.JarFile;
|
||||
|
||||
public class ClassUtil {
|
||||
|
||||
/**
|
||||
* 获取同一路径下所有子类或接口实现类
|
||||
*
|
||||
* @param cls
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static List<Class<?>> getAllAssignedClass(Class<?> cls) throws IOException,
|
||||
ClassNotFoundException {
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
for (Class<?> c : getClasses(cls)) {
|
||||
if (cls.isAssignableFrom(c) && !cls.equals(c)) {
|
||||
classes.add(c);
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取得当前类路径下的所有类
|
||||
*
|
||||
* @param cls
|
||||
* @return
|
||||
* @throws IOException
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
public static List<Class<?>> getClasses(Class<?> cls) throws IOException,
|
||||
ClassNotFoundException {
|
||||
String pk = cls.getPackage().getName();
|
||||
// String path = pk.replace('.', '/');
|
||||
// ClassLoader classloader = Thread.currentThread().getContextClassLoader();
|
||||
// URL url = classloader.getResource(path);
|
||||
// String type = url.getProtocol();
|
||||
//
|
||||
// System.out.println("the type is " + type);
|
||||
// System.out.println(url.getPath());
|
||||
//
|
||||
// return getClasses(new File(url.getFile()), pk);
|
||||
List<String> classNames = getClassName(pk, true);
|
||||
List<Class<?>> classes = new ArrayList<>();
|
||||
for (String className :
|
||||
classNames) {
|
||||
if (className.endsWith(".class")) {
|
||||
className = className.substring(0, className.length() - 6);
|
||||
className = className.substring(className.lastIndexOf("/")+1, className.length());
|
||||
}
|
||||
|
||||
classes.add(Class.forName(className));
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 迭代查找类
|
||||
*
|
||||
* @param dir
|
||||
* @param pk
|
||||
* @return
|
||||
* @throws ClassNotFoundException
|
||||
*/
|
||||
private static List<Class<?>> getClasses(File dir, String pk) throws ClassNotFoundException {
|
||||
System.out.println(dir.getAbsolutePath());
|
||||
List<Class<?>> classes = new ArrayList<Class<?>>();
|
||||
if (!dir.exists()) {
|
||||
return classes;
|
||||
}
|
||||
for (File f : dir.listFiles()) {
|
||||
if (f.isDirectory()) {
|
||||
classes.addAll(getClasses(f, pk + "." + f.getName()));
|
||||
}
|
||||
String name = f.getName();
|
||||
if (name.endsWith(".class")) {
|
||||
classes.add(Class.forName(pk + "." + name.substring(0, name.length() - 6)));
|
||||
}
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取某包下所有类
|
||||
* @param packageName 包名
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
public static List<String> getClassName(String packageName, boolean childPackage) {
|
||||
List<String> fileNames = null;
|
||||
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||
String packagePath = packageName.replace(".", "/");
|
||||
URL url = loader.getResource(packagePath);
|
||||
if (url != null) {
|
||||
String type = url.getProtocol();
|
||||
if (type.equals("file")) {
|
||||
fileNames = getClassNameByFile(url.getPath(), null, childPackage);
|
||||
} else if (type.equals("jar")) {
|
||||
fileNames = getClassNameByJar(url.getPath(), childPackage);
|
||||
}
|
||||
} else {
|
||||
fileNames = getClassNameByJars(((URLClassLoader) loader).getURLs(), packagePath, childPackage);
|
||||
}
|
||||
return fileNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从项目文件获取某包下所有类
|
||||
* @param filePath 文件路径
|
||||
* @param className 类名集合
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByFile(String filePath, List<String> className, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
File file = new File(filePath);
|
||||
File[] childFiles = file.listFiles();
|
||||
for (File childFile : childFiles) {
|
||||
if (childFile.isDirectory()) {
|
||||
if (childPackage) {
|
||||
myClassName.addAll(getClassNameByFile(childFile.getPath(), myClassName, childPackage));
|
||||
}
|
||||
} else {
|
||||
String childFilePath = childFile.getPath();
|
||||
if (childFilePath.endsWith(".class")) {
|
||||
if (childFilePath.indexOf("\\classes") >= 0 || childFilePath.indexOf("/classes") >= 0) {
|
||||
int start = childFilePath.indexOf("\\classes");
|
||||
if (start == -1) {
|
||||
start = childFilePath.indexOf("/classes");
|
||||
}
|
||||
childFilePath = childFilePath.substring(start + 9, childFilePath.lastIndexOf("."));
|
||||
}
|
||||
childFilePath = childFilePath.replace("\\", ".");
|
||||
childFilePath = childFilePath.replace("/", ".");
|
||||
myClassName.add(childFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从jar获取某包下所有类
|
||||
* @param jarPath jar文件路径
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByJar(String jarPath, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
String[] jarInfo = jarPath.split("!");
|
||||
String jarFilePath = jarInfo[0].substring(jarInfo[0].indexOf("/"));
|
||||
String packagePath = jarInfo[1].substring(1);
|
||||
try {
|
||||
JarFile jarFile = new JarFile(jarFilePath);
|
||||
Enumeration<JarEntry> entrys = jarFile.entries();
|
||||
while (entrys.hasMoreElements()) {
|
||||
JarEntry jarEntry = entrys.nextElement();
|
||||
String entryName = jarEntry.getName();
|
||||
|
||||
if (entryName.endsWith(".class")) {
|
||||
if (childPackage) {
|
||||
if (entryName.startsWith(packagePath)) {
|
||||
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
|
||||
myClassName.add(entryName);
|
||||
}
|
||||
} else {
|
||||
int index = entryName.lastIndexOf("/");
|
||||
String myPackagePath;
|
||||
if (index != -1) {
|
||||
myPackagePath = entryName.substring(0, index);
|
||||
} else {
|
||||
myPackagePath = entryName;
|
||||
}
|
||||
if (myPackagePath.equals(packagePath)) {
|
||||
entryName = entryName.replace("/", ".").substring(0, entryName.lastIndexOf("."));
|
||||
myClassName.add(entryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从所有jar中搜索该包,并获取该包下所有类
|
||||
* @param urls URL集合
|
||||
* @param packagePath 包路径
|
||||
* @param childPackage 是否遍历子包
|
||||
* @return 类的完整名称
|
||||
*/
|
||||
private static List<String> getClassNameByJars(URL[] urls, String packagePath, boolean childPackage) {
|
||||
List<String> myClassName = new ArrayList<String>();
|
||||
if (urls != null) {
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
URL url = urls[i];
|
||||
String urlPath = url.getPath();
|
||||
// 不必搜索classes文件夹
|
||||
if (urlPath.endsWith("classes/")) {
|
||||
continue;
|
||||
}
|
||||
String jarPath = urlPath + "!/" + packagePath;
|
||||
myClassName.addAll(getClassNameByJar(jarPath, childPackage));
|
||||
}
|
||||
}
|
||||
return myClassName;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
|
||||
/**
|
||||
* 默认的主页Action,当访问主页且没有定义主页Action时,调用此Action
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class DefaultIndexAction extends Action{
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
response.setContent("Welcome to LoServer.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.DateUtil;
|
||||
import com.xiaoleilu.hutool.util.FileUtil;
|
||||
import com.xiaoleilu.hutool.util.ReUtil;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.loServer.ServerSetting;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 默认的主页Action,当访问主页且没有定义主页Action时,调用此Action
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class FileAction extends Action {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(FileAction.class);
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (false == Request.METHOD_GET.equalsIgnoreCase(request.getMethod())) {
|
||||
response.sendError(HttpResponseStatus.METHOD_NOT_ALLOWED, "Please use GET method to request file!");
|
||||
return;
|
||||
}
|
||||
|
||||
if(ServerSetting.isRootAvailable() == false){
|
||||
response.sendError(HttpResponseStatus.NOT_FOUND, "404 Root dir not avaliable!");
|
||||
return;
|
||||
}
|
||||
|
||||
final File file = getFileByPath(request.getPath());
|
||||
Logger.debug("Client [{}] get file [{}]", request.getIp(), file.getPath());
|
||||
|
||||
// 隐藏文件,跳过
|
||||
if (file.isHidden() || !file.exists()) {
|
||||
response.sendError(HttpResponseStatus.NOT_FOUND, "404 File not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
// 非文件,跳过
|
||||
if (false == file.isFile()) {
|
||||
response.sendError(HttpResponseStatus.FORBIDDEN, "403 Forbidden!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache Validation
|
||||
String ifModifiedSince = request.getHeader(HttpHeaderNames.IF_MODIFIED_SINCE.toString());
|
||||
if (StrUtil.isNotBlank(ifModifiedSince)) {
|
||||
Date ifModifiedSinceDate = null;
|
||||
try {
|
||||
ifModifiedSinceDate = DateUtil.parse(ifModifiedSince, HTTP_DATE_FORMATER);
|
||||
} catch (Exception e) {
|
||||
Logger.warn("If-Modified-Since header parse error: {}", e.getMessage());
|
||||
}
|
||||
if(ifModifiedSinceDate != null) {
|
||||
// 只对比到秒一级别
|
||||
long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000;
|
||||
long fileLastModifiedSeconds = file.lastModified() / 1000;
|
||||
if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
|
||||
Logger.debug("File {} not modified.", file.getPath());
|
||||
response.sendNotModified();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response.setContent(file);
|
||||
}
|
||||
|
||||
private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
|
||||
private static final SimpleDateFormat HTTP_DATE_FORMATER = new SimpleDateFormat(DateUtil.HTTP_DATETIME_PATTERN, Locale.US);
|
||||
|
||||
|
||||
/**
|
||||
* 通过URL中的path获得文件的绝对路径
|
||||
*
|
||||
* @param httpPath Http请求的Path
|
||||
* @return 文件绝对路径
|
||||
*/
|
||||
public static File getFileByPath(String httpPath) {
|
||||
// Decode the path.
|
||||
try {
|
||||
httpPath = URLDecoder.decode(httpPath, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
|
||||
if (httpPath.isEmpty() || httpPath.charAt(0) != '/') {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 路径安全检查
|
||||
if (httpPath.contains("/.") || httpPath.contains("./") || httpPath.charAt(0) == '.' || httpPath.charAt(httpPath.length() - 1) == '.' || ReUtil.isMatch(INSECURE_URI, httpPath)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 转换为绝对路径
|
||||
return FileUtil.file(ServerSetting.getRoot(), httpPath);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.MemorySessionStore;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.moquette.spi.impl.security.AES;
|
||||
import io.moquette.spi.security.Tokenor;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("/im")
|
||||
@HttpMethod("POST")
|
||||
public class IMAction extends Action {
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
|
||||
String str = new String(bytes);
|
||||
try {
|
||||
bytes = Base64.getDecoder().decode(str);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return;
|
||||
}
|
||||
|
||||
String cid = fullHttpRequest.headers().get("cid");
|
||||
byte[] cbytes = Base64.getDecoder().decode(cid);
|
||||
cbytes = AES.AESDecrypt(cbytes, null, true);
|
||||
if (cbytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return;
|
||||
}
|
||||
cid = new String(cbytes);
|
||||
|
||||
MemorySessionStore.Session session = sessionsStore.getSession(cid);
|
||||
|
||||
if (session != null) {
|
||||
bytes = AES.AESDecrypt(bytes, session.getSecret(), true);
|
||||
} else {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (bytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);
|
||||
String token = wrapper.getToken();
|
||||
String userId = Tokenor.getUserId(token.getBytes());
|
||||
if (userId == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null);
|
||||
} else {
|
||||
RPCCenter.getInstance().sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), userId, TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
sendResponse(response, null, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if(contents == null) {
|
||||
ByteBuf ackPayload = Unpooled.buffer();
|
||||
ackPayload.ensureWritable(1).writeByte(errorCode.getCode());
|
||||
response.setContent(ackPayload);
|
||||
} else {
|
||||
response.setContent(contents);
|
||||
}
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
/**
|
||||
* 错误堆栈Action类
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class NotFoundAction extends Action{
|
||||
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(NotFoundAction.class);
|
||||
|
||||
public final static String ERROR_PARAM_NAME = "_e";
|
||||
|
||||
private final static String TEMPLATE_ERROR = "<!DOCTYPE html><html><head><title>LoServer - Error report</title><style>h1,h3 {color:white; background-color: gray;}</style></head><body><h1>HTTP Status {} - {}</h1><hr size=\"1\" noshade=\"noshade\" /><p>{}</p><hr size=\"1\" noshade=\"noshade\" /><h3>LoServer</h3></body></html>";
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
response.sendError(HttpResponseStatus.NOT_FOUND, "404 Not found!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.protobuf.InvalidProtocolBufferException;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.persistence.MemorySessionStore;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.moquette.spi.impl.security.AES;
|
||||
import io.moquette.spi.security.Tokenor;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("/route")
|
||||
@HttpMethod("POST")
|
||||
public class RouteAction extends Action {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(RouteAction.class);
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
response.setContentType("application/octet-stream");
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();
|
||||
boolean b = false;
|
||||
if ("web".equalsIgnoreCase(fullHttpRequest.headers().get("p"))) {
|
||||
b = true;
|
||||
}
|
||||
|
||||
final boolean base64Response = b;
|
||||
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
|
||||
String str = new String(bytes);
|
||||
try {
|
||||
bytes = Base64.getDecoder().decode(str);
|
||||
} catch (IllegalArgumentException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
return;
|
||||
}
|
||||
|
||||
String cid = fullHttpRequest.headers().get("cid");
|
||||
byte[] cbytes = Base64.getDecoder().decode(cid);
|
||||
cbytes = AES.AESDecrypt(cbytes, null, true);
|
||||
if (cbytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
return;
|
||||
}
|
||||
cid = new String(cbytes);
|
||||
|
||||
String uid = fullHttpRequest.headers().get("uid");
|
||||
byte[] ubytes = Base64.getDecoder().decode(uid);
|
||||
ubytes = AES.AESDecrypt(ubytes, null, true);
|
||||
if (ubytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
return;
|
||||
}
|
||||
uid = new String(ubytes);
|
||||
|
||||
|
||||
MemorySessionStore.Session session = sessionsStore.sessionForClientAndUser(uid, cid);
|
||||
if (session == null) {
|
||||
ErrorCode errorCode = sessionsStore.createNewSession(uid, cid, true);
|
||||
if (errorCode != ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
sendResponse(response, errorCode, null, base64Response);
|
||||
return;
|
||||
}
|
||||
session = sessionsStore.sessionForClientAndUser(uid, cid);
|
||||
}
|
||||
|
||||
|
||||
if (session != null) {
|
||||
bytes = AES.AESDecrypt(bytes, session.getSecret(), true);
|
||||
} else {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (bytes == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SECRECT_KEY_MISMATCH, null, base64Response);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
WFCMessage.IMHttpWrapper wrapper = WFCMessage.IMHttpWrapper.parseFrom(bytes);
|
||||
String token = wrapper.getToken();
|
||||
String userId = Tokenor.getUserId(token.getBytes());
|
||||
LOG.info("RouteAction token={}, userId={}", token, userId);
|
||||
if (userId == null) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TOKEN_ERROR, null, base64Response);
|
||||
} else {
|
||||
RPCCenter.getInstance().sendRequest(userId, wrapper.getClientId(), wrapper.getRequest(), wrapper.getData().toByteArray(), userId, TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
sendResponse(response, null, result, base64Response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null, base64Response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null, base64Response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
} catch (InvalidProtocolBufferException e) {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_INVALID_DATA, null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void sendResponse(Response response, ErrorCode errorCode, byte[] contents, boolean base64Response) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if(contents == null) {
|
||||
ByteBuf ackPayload = Unpooled.buffer();
|
||||
ackPayload.ensureWritable(1).writeByte(errorCode.getCode());
|
||||
response.setContent(ackPayload);
|
||||
} else {
|
||||
response.setContent(contents);
|
||||
}
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 错误堆栈Action类
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class UnknownErrorAction extends Action{
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(UnknownErrorAction.class);
|
||||
|
||||
public final static String ERROR_PARAM_NAME = "_e";
|
||||
|
||||
private final static String TEMPLATE_ERROR = "<!DOCTYPE html><html><head><title>LoServer - Error report</title><style>h1,h3 {color:white; background-color: gray;}</style></head><body><h1>HTTP Status {} - {}</h1><hr size=\"1\" noshade=\"noshade\" /><p>{}</p><hr size=\"1\" noshade=\"noshade\" /><h3>LoServer</h3></body></html>";
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,344 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import com.hazelcast.util.StringUtil;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.RequireAuthentication;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.*;
|
||||
import io.moquette.server.config.MediaServerConfig;
|
||||
import io.moquette.spi.impl.security.AES;
|
||||
import io.moquette.spi.security.DES;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.handler.codec.http.multipart.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.xiaoleilu.loServer.handler.HttpResponseHelper.getFileExt;
|
||||
|
||||
@Route("/fs")
|
||||
@HttpMethod("POST")
|
||||
@RequireAuthentication
|
||||
public class UploadFileAction extends Action {
|
||||
private static final String KEY = "imfile";
|
||||
private static final Logger logger = LoggerFactory.getLogger(UploadFileAction.class);
|
||||
private static final HttpDataFactory factory = new DefaultHttpDataFactory(false);
|
||||
|
||||
public static class InvalidateTokenExecption extends Exception {
|
||||
|
||||
}
|
||||
|
||||
public static String getToken(int type) {
|
||||
String signKey = KEY + "|" + (System.currentTimeMillis()) + "|" + type;
|
||||
try {
|
||||
return DES.encryptDES(signKey);
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static int validateToken(String token) throws InvalidateTokenExecption {
|
||||
try {
|
||||
String signKey = DES.decryptDES(token);
|
||||
String[] parts = signKey.split("\\|");
|
||||
if(parts.length == 3) {
|
||||
if(parts[0].equals(KEY)) {
|
||||
long timestamp = Long.parseLong(parts[1]);
|
||||
if(Math.abs(System.currentTimeMillis() - timestamp) < 2 * 60 * 60 * 1000) {
|
||||
return Integer.parseInt(parts[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// TODO Auto-generated catch block
|
||||
//e.printStackTrace();
|
||||
}
|
||||
throw new InvalidateTokenExecption();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request r, Response response) {
|
||||
if (r.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
FullHttpRequest request = (FullHttpRequest) r.getNettyRequest();
|
||||
String requestId = UUID.randomUUID().toString().replace("-", "");
|
||||
logger.info("HttpFileServerHandler received a request: method=" + request.getMethod() + ", uri=" + request.getUri() + ", requestId=" + requestId);
|
||||
|
||||
if (!request.getDecoderResult().isSuccess()) {
|
||||
logger.warn("http decode failed!");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("http decode failed");
|
||||
return;
|
||||
}
|
||||
|
||||
multipartUpload(request, requestId, response);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* multipart上传
|
||||
*/
|
||||
private void multipartUpload(FullHttpRequest request, String requestId, Response response) {
|
||||
HttpPostRequestDecoder decoder = null;
|
||||
try {
|
||||
decoder = new HttpPostRequestDecoder(factory, request);
|
||||
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
|
||||
logger.error("Failed to decode file data!", e1);
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("Failed to decode file data!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (decoder != null) {
|
||||
if (request instanceof HttpContent) {
|
||||
HttpContent chunk = (HttpContent) request;
|
||||
try {
|
||||
decoder.offer(chunk);
|
||||
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
|
||||
logger.warn("BAD_REQUEST, Failed to decode file data");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("Failed to decode file data!");
|
||||
return;
|
||||
}
|
||||
|
||||
long fileTotalSize = 0;
|
||||
if (request.headers().contains("X-File-Total-Size")) {
|
||||
try {
|
||||
fileTotalSize = Integer.parseInt(request.headers().get("X-File-Total-Size"));
|
||||
} catch (Exception e) {
|
||||
logger.warn("invalid X-File-Total-Size value!");
|
||||
}
|
||||
}
|
||||
|
||||
readHttpDataChunkByChunk(response, decoder, requestId, HttpHeaders.isKeepAlive(request));
|
||||
|
||||
if (chunk instanceof LastHttpContent) {
|
||||
|
||||
}
|
||||
} else {
|
||||
logger.warn("BAD_REQUEST, Not a http request");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("Not a http request");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* readHttpDataChunkByChunk
|
||||
*/
|
||||
private void readHttpDataChunkByChunk(Response response, HttpPostRequestDecoder decoder, String requestId, boolean isKeepAlive) {
|
||||
try {
|
||||
int[] bucket = new int[1];
|
||||
bucket[0] = -1;
|
||||
while (decoder.hasNext()) {
|
||||
InterfaceHttpData data = decoder.next();
|
||||
if (data != null) {
|
||||
try {
|
||||
if(!writeFileUploadData(data, response, requestId, isKeepAlive, bucket)) {
|
||||
break;
|
||||
}
|
||||
} finally {
|
||||
data.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info("chunk end");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writeFileUploadData
|
||||
*/
|
||||
private boolean writeFileUploadData(InterfaceHttpData data, Response response, String requestId, boolean isKeepAlive, int[] bucket) {
|
||||
try {
|
||||
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
|
||||
FileUpload fileUpload = (FileUpload) data;
|
||||
|
||||
String remoteFileName = fileUpload.getFilename();
|
||||
long remoteFileSize = fileUpload.length();
|
||||
|
||||
if(bucket[0] == -1) {
|
||||
logger.warn("Not authenticated!");
|
||||
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("Not authenticated!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(remoteFileName)) {
|
||||
logger.warn("remoteFileName is empty!");
|
||||
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("file name is empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(requestId)) {
|
||||
logger.warn("requestId is empty!");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("requestId is empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (remoteFileSize > 50 * 1024 * 1024) {
|
||||
logger.warn("file over limite!(" + remoteFileSize + ")");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("file over limite!");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String remoteFileExt = "";
|
||||
if (remoteFileName.lastIndexOf(".") == -1) {
|
||||
remoteFileExt = "octetstream";
|
||||
remoteFileName = remoteFileName + "." + remoteFileExt;
|
||||
|
||||
} else {
|
||||
remoteFileExt = getFileExt(remoteFileName);
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(remoteFileExt) || remoteFileExt.equals("ing")) {
|
||||
logger.warn("Invalid file extention name");
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("Invalid file extention name");
|
||||
return false;
|
||||
}
|
||||
|
||||
int remoteFileTotalSize = (int) remoteFileSize;
|
||||
|
||||
|
||||
ByteBuf byteBuf = null;
|
||||
int savedThunkSize = 0; // 分片接收保存的大小
|
||||
int offset = 0; // 断点续传开始位置
|
||||
|
||||
Date nowTime=new Date();
|
||||
SimpleDateFormat time=new SimpleDateFormat("yyyy/MM/dd/HH");
|
||||
String datePath = time.format(nowTime);
|
||||
|
||||
datePath = "fs/" + bucket[0] + "/" + datePath; //add bucket
|
||||
|
||||
String dir = "./" + MediaServerConfig.FILE_STROAGE_ROOT + "/" + datePath;
|
||||
|
||||
File dirFile = new File(dir);
|
||||
boolean bFile = dirFile.exists();
|
||||
|
||||
if(!bFile) {
|
||||
bFile = dirFile.mkdirs();
|
||||
if (!bFile) {
|
||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
response.setContent("服务器错误:无法创建文件");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String filePath = dir + "/" + requestId;
|
||||
logger.info("the file path is " + filePath);
|
||||
|
||||
File tmpFile = new File(filePath);
|
||||
|
||||
logger.info("before write the file");
|
||||
boolean isError = false;
|
||||
while (true) {
|
||||
byte[] thunkData;
|
||||
try {
|
||||
byteBuf = fileUpload.getChunk(128 * 1024);
|
||||
int readableBytesSize = byteBuf.readableBytes();
|
||||
thunkData = new byte[readableBytesSize];
|
||||
byteBuf.readBytes(thunkData);
|
||||
|
||||
put(tmpFile, offset, thunkData);
|
||||
|
||||
savedThunkSize += readableBytesSize;
|
||||
offset += readableBytesSize;
|
||||
|
||||
if (savedThunkSize >= remoteFileSize) {
|
||||
byteBuf.release();
|
||||
fileUpload.release();
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
String relativePath = datePath + "/" + requestId;
|
||||
response.setContent("{\"key\":\"" + relativePath + "\"}");
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("save thunckData error!", e);
|
||||
if (fileUpload != null)
|
||||
fileUpload.release();
|
||||
|
||||
if (byteBuf != null)
|
||||
byteBuf.release();
|
||||
|
||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
response.setContent("服务器错误:" + e.getMessage());
|
||||
isError = true;
|
||||
|
||||
return false;
|
||||
} finally {
|
||||
thunkData = null;
|
||||
if (isError) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if(data.getHttpDataType() == InterfaceHttpData.HttpDataType.Attribute) {
|
||||
Attribute attribute = (Attribute)data;
|
||||
if(attribute.getName().equals("token")) {
|
||||
String token = attribute.getValue();
|
||||
|
||||
try {
|
||||
bucket[0] = validateToken(token);
|
||||
} catch (InvalidateTokenExecption e) {
|
||||
logger.error("无效的token!", e);
|
||||
response.setStatus(HttpResponseStatus.BAD_REQUEST);
|
||||
response.setContent("无效的token:" + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("writeHttpData error!", e);
|
||||
response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
response.setContent("服务器错误:" + e.getMessage());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void put(File file, long pos, byte[] data) throws Exception {
|
||||
RandomAccessFile raf = null;
|
||||
try {
|
||||
raf = new RandomAccessFile(file, "rwd");
|
||||
raf.seek(pos);
|
||||
raf.write(data);
|
||||
} finally {
|
||||
try {
|
||||
if (raf != null)
|
||||
raf.close();
|
||||
} catch (Exception e) {
|
||||
logger.warn("release error!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputUserLogin;
|
||||
import com.xiaoleilu.loServer.pojos.OutputLoginData;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.moquette.spi.impl.security.TokenAuthenticator;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.GitRepositoryState;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Route("/api/version")
|
||||
@HttpMethod("GET")
|
||||
public class VersionAction extends Action {
|
||||
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
|
||||
try {
|
||||
response.setContent(new Gson().toJson(GitRepositoryState.getGitRepositoryState()));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
response.setContent("No version info!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateUser;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.RateLimiter;
|
||||
|
||||
abstract public class AdminAction extends Action {
|
||||
private static String SECRET_KEY = "123456";
|
||||
private final RateLimiter mLimitCounter = new RateLimiter(10, 500);
|
||||
public static void setSecretKey(String secretKey) {
|
||||
SECRET_KEY = secretKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ErrorCode preAction(Request request, Response response) {
|
||||
if (!mLimitCounter.isGranted("admin")) {
|
||||
return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
|
||||
}
|
||||
String nonce = request.getHeader("nonce");
|
||||
String timestamp = request.getHeader("timestamp");
|
||||
String sign = request.getHeader("sign");
|
||||
if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign)) {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
Long ts;
|
||||
try {
|
||||
ts = Long.parseLong(timestamp);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {
|
||||
// return ErrorCode.ERROR_CODE_SIGN_EXPIRED;
|
||||
}
|
||||
|
||||
String str = nonce + "|" + SECRET_KEY + "|" + timestamp;
|
||||
String localSign = DigestUtils.sha1Hex(str);
|
||||
return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
protected void sendResponse(Response response, ErrorCode errorCode, Object data) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if (errorCode == null) {
|
||||
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputOutputUserBlockStatus;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/user/status")
|
||||
@HttpMethod("POST")
|
||||
public class BlockUserAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputOutputUserBlockStatus inputUserBlock = getRequestBody(request.getNettyRequest(), InputOutputUserBlockStatus.class);
|
||||
if (inputUserBlock != null
|
||||
&& !StringUtil.isNullOrEmpty(inputUserBlock.getUserId())) {
|
||||
|
||||
ErrorCode errorCode = messagesStore.modifyUserStatus(inputUserBlock.getUserId(), inputUserBlock.getStatus());
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result;
|
||||
result = RestResult.resultOf(errorCode);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
|
||||
RPCCenter.getInstance().sendRequest(null, null, RPCCenter.KICKOFF_USER_REQUEST, inputUserBlock.getUserId().getBytes(), inputUserBlock.getUserId(), TargetEntry.Type.TARGET_TYPE_USER, null);
|
||||
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, null);
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputGetUserInfo;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateUser;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("/admin/user/onlinestatus")
|
||||
@HttpMethod("POST")
|
||||
public class CheckUserOnlineAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);
|
||||
if (inputUserId == null || !StringUtil.isNullOrEmpty(inputUserId.getUserId())) {
|
||||
RPCCenter.getInstance().sendRequest(null, null, RPCCenter.CHECK_USER_ONLINE_REQUEST, inputUserId.getUserId().getBytes(), inputUserId.getUserId(), TargetEntry.Type.TARGET_TYPE_USER, null);
|
||||
return;
|
||||
} else {
|
||||
sendResponse(response, ErrorCode.INVALID_PARAMETER, null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateChatroom;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateChatroom;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.UUIDGenerator;
|
||||
|
||||
@Route("/admin/chatroom")
|
||||
@HttpMethod("PUT")
|
||||
public class CreateChatroomAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
Gson gson = new Gson();
|
||||
InputCreateChatroom inputCreateChatroom = gson.fromJson(content, InputCreateChatroom.class);
|
||||
if (inputCreateChatroom != null
|
||||
&& !StringUtil.isNullOrEmpty(inputCreateChatroom.getTitle())) {
|
||||
|
||||
if (StringUtil.isNullOrEmpty(inputCreateChatroom.getChatroomId())) {
|
||||
inputCreateChatroom.setChatroomId(messagesStore.getShortUUID());
|
||||
}
|
||||
|
||||
if (inputCreateChatroom.getPortrait() == null || inputCreateChatroom.getPortrait().length() == 0) {
|
||||
inputCreateChatroom.setPortrait("https://avatars.io/gravatar/" + inputCreateChatroom.getChatroomId());
|
||||
}
|
||||
|
||||
WFCMessage.ChatroomInfo info = inputCreateChatroom.toChatroomInfo();
|
||||
|
||||
messagesStore.createChatroom(inputCreateChatroom.getChatroomId(), info);
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok(new OutputCreateChatroom(inputCreateChatroom.getChatroomId()));
|
||||
response.setContent(new Gson().toJson(result));
|
||||
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateGroup;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateGroupResult;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("admin/group")
|
||||
@HttpMethod("PUT")
|
||||
public class CreateGroupAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputCreateGroup inputCreateGroup = getRequestBody(request.getNettyRequest(), InputCreateGroup.class);
|
||||
if (inputCreateGroup.isValide()) {
|
||||
RPCCenter.getInstance().sendRequest(inputCreateGroup.getOperator(), null, IMTopic.CreateGroupTopic, inputCreateGroup.toProtoGroupRequest().toByteArray(), inputCreateGroup.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
byte[] data = new byte[byteBuf.readableBytes()];
|
||||
byteBuf.readBytes(data);
|
||||
String groupId = new String(data);
|
||||
sendResponse(response, null, new OutputCreateGroupResult(groupId));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateRobot;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateRobot;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.UUIDGenerator;
|
||||
|
||||
@Route("admin/robot/create")
|
||||
@HttpMethod("POST")
|
||||
public class CreateRobotAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputCreateRobot inputCreateRobot = getRequestBody(request.getNettyRequest(), InputCreateRobot.class);
|
||||
if (inputCreateRobot != null
|
||||
&& !StringUtil.isNullOrEmpty(inputCreateRobot.getName())) {
|
||||
|
||||
if(StringUtil.isNullOrEmpty(inputCreateRobot.getPassword())) {
|
||||
inputCreateRobot.setPassword(UUIDGenerator.getUUID());
|
||||
}
|
||||
|
||||
if(StringUtil.isNullOrEmpty(inputCreateRobot.getUserId())) {
|
||||
inputCreateRobot.setUserId(messagesStore.getShortUUID());
|
||||
}
|
||||
|
||||
if (inputCreateRobot.getPortrait() == null || inputCreateRobot.getPortrait().length() == 0) {
|
||||
inputCreateRobot.setPortrait("https://avatars.io/gravatar/" + inputCreateRobot.getUserId());
|
||||
}
|
||||
|
||||
WFCMessage.User newUser = inputCreateRobot.toUser();
|
||||
|
||||
|
||||
messagesStore.addUserInfo(newUser, inputCreateRobot.getPassword());
|
||||
|
||||
if (StringUtil.isNullOrEmpty(inputCreateRobot.getOwner())) {
|
||||
inputCreateRobot.setOwner(inputCreateRobot.getUserId());
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(inputCreateRobot.getSecret())) {
|
||||
inputCreateRobot.setSecret(UUIDGenerator.getUUID());
|
||||
}
|
||||
|
||||
messagesStore.addRobot(inputCreateRobot.toRobot());
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok(new OutputCreateRobot(inputCreateRobot.getUserId(), inputCreateRobot.getSecret()));
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateUser;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateUser;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.UUIDGenerator;
|
||||
|
||||
@Route("admin/user/create")
|
||||
@HttpMethod("POST")
|
||||
public class CreateUserAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputCreateUser inputCreateUser = getRequestBody(request.getNettyRequest(), InputCreateUser.class);
|
||||
if (inputCreateUser != null
|
||||
&& !StringUtil.isNullOrEmpty(inputCreateUser.getName())) {
|
||||
|
||||
if(StringUtil.isNullOrEmpty(inputCreateUser.getPassword())) {
|
||||
inputCreateUser.setPassword(UUIDGenerator.getUUID());
|
||||
}
|
||||
|
||||
if(StringUtil.isNullOrEmpty(inputCreateUser.getUserId())) {
|
||||
inputCreateUser.setUserId(messagesStore.getShortUUID());
|
||||
}
|
||||
|
||||
if (inputCreateUser.getPortrait() == null || inputCreateUser.getPortrait().length() == 0) {
|
||||
inputCreateUser.setPortrait("https://avatars.io/gravatar/" + inputCreateUser.getUserId());
|
||||
}
|
||||
|
||||
WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()
|
||||
.setUid(StringUtil.isNullOrEmpty(inputCreateUser.getUserId()) ? "" : inputCreateUser.getUserId());
|
||||
if (inputCreateUser.getName() != null)
|
||||
newUserBuilder.setName(inputCreateUser.getName());
|
||||
if (inputCreateUser.getDisplayName() != null)
|
||||
newUserBuilder.setDisplayName(StringUtil.isNullOrEmpty(inputCreateUser.getDisplayName()) ? inputCreateUser.getName() : inputCreateUser.getDisplayName());
|
||||
if (inputCreateUser.getPortrait() != null)
|
||||
newUserBuilder.setPortrait(inputCreateUser.getPortrait());
|
||||
if (inputCreateUser.getEmail() != null)
|
||||
newUserBuilder.setEmail(inputCreateUser.getEmail());
|
||||
if (inputCreateUser.getAddress() != null)
|
||||
newUserBuilder.setAddress(inputCreateUser.getAddress());
|
||||
if (inputCreateUser.getCompany() != null)
|
||||
newUserBuilder.setCompany(inputCreateUser.getCompany());
|
||||
|
||||
if (inputCreateUser.getSocial() != null)
|
||||
newUserBuilder.setSocial(inputCreateUser.getSocial());
|
||||
|
||||
|
||||
if (inputCreateUser.getMobile() != null)
|
||||
newUserBuilder.setMobile(inputCreateUser.getMobile());
|
||||
newUserBuilder.setGender(inputCreateUser.getGender());
|
||||
if (inputCreateUser.getExtra() != null)
|
||||
newUserBuilder.setExtra(inputCreateUser.getExtra());
|
||||
|
||||
newUserBuilder.setUpdateDt(System.currentTimeMillis());
|
||||
|
||||
messagesStore.addUserInfo(newUserBuilder.build(), inputCreateUser.getPassword());
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok(new OutputCreateUser(inputCreateUser.getUserId(), inputCreateUser.getName()));
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputDestoryChatroom;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("/admin/chatroom")
|
||||
@HttpMethod("DELETE")
|
||||
public class DestoryChatroomAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest)request.getNettyRequest();
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
Gson gson = new Gson();
|
||||
InputDestoryChatroom inputDestoryChatroom = gson.fromJson(content, InputDestoryChatroom.class);
|
||||
if (inputDestoryChatroom != null
|
||||
&& !StringUtil.isNullOrEmpty(inputDestoryChatroom.getChatroomId())) {
|
||||
|
||||
messagesStore.destoryChatroom(inputDestoryChatroom.getChatroomId());
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok();
|
||||
response.setContent(new Gson().toJson(result));
|
||||
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.OutputGetChatroomInfo;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("/admin/chatroom")
|
||||
@HttpMethod("GET")
|
||||
public class GetChatroomInfoAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
|
||||
String chatroomid = request.getParam("id");
|
||||
if (!StringUtil.isNullOrEmpty(chatroomid)) {
|
||||
|
||||
WFCMessage.ChatroomInfo info = messagesStore.getChatroomInfo(chatroomid);
|
||||
|
||||
RestResult result;
|
||||
if (info == null) {
|
||||
result = RestResult.ok(new OutputGetChatroomInfo(chatroomid, messagesStore.getChatroomMemberCount(chatroomid), info));
|
||||
} else {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_SUCCESS);
|
||||
}
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputGetToken;
|
||||
import com.xiaoleilu.loServer.pojos.OutputGetIMTokenData;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.Base64;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("/admin/user/token")
|
||||
@HttpMethod("POST")
|
||||
public class GetIMTokenAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetToken input = getRequestBody(request.getNettyRequest(), InputGetToken.class);
|
||||
String userId = input.getUserId();
|
||||
|
||||
|
||||
WFCMessage.GetTokenRequest getTokenRequest = WFCMessage.GetTokenRequest.newBuilder().setUserId(userId).setClientId(input.getClientId()).build();
|
||||
RPCCenter.getInstance().sendRequest(userId, input.getClientId(), IMTopic.GetTokenTopic, getTokenRequest.toByteArray(), userId, TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ErrorCode errorCode1 = ErrorCode.fromCode(result[0]);
|
||||
if (errorCode1 == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
//ba errorcode qudiao
|
||||
byte[] data = new byte[result.length -1];
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
data[i] = result[i+1];
|
||||
}
|
||||
String token = Base64.getEncoder().encodeToString(data);
|
||||
|
||||
sendResponse(response, null, new OutputGetIMTokenData(userId, token));
|
||||
} else {
|
||||
sendResponse(response, errorCode1, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
+68
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateUser;
|
||||
import com.xiaoleilu.loServer.pojos.InputGetUserInfo;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateUser;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/user/info")
|
||||
@HttpMethod("POST")
|
||||
public class GetUserAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);
|
||||
if (inputUserId != null
|
||||
&& (!StringUtil.isNullOrEmpty(inputUserId.getUserId()) || !StringUtil.isNullOrEmpty(inputUserId.getName()))) {
|
||||
|
||||
WFCMessage.User user = null;
|
||||
if(!StringUtil.isNullOrEmpty(inputUserId.getUserId())) {
|
||||
user = messagesStore.getUserInfo(inputUserId.getUserId());
|
||||
} else if(!StringUtil.isNullOrEmpty(inputUserId.getName())) {
|
||||
user = messagesStore.getUserInfoByName(inputUserId.getName());
|
||||
} else if(!StringUtil.isNullOrEmpty(inputUserId.getMobile())) {
|
||||
user = messagesStore.getUserInfoByMobile(inputUserId.getMobile());
|
||||
}
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result;
|
||||
if (user == null) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
result = RestResult.ok(InputCreateUser.fromPbUser(user));
|
||||
}
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
|
||||
@Route("admin/user/statuslist")
|
||||
@HttpMethod("POST")
|
||||
public class GetUserBlockListAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok(messagesStore.getUserStatusList());
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputGetUserInfo;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateUser;
|
||||
import com.xiaoleilu.loServer.pojos.OutputUserStatus;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/user/checkstatus")
|
||||
@HttpMethod("POST")
|
||||
public class GetUserBlockStatusAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);
|
||||
if (inputUserId != null
|
||||
&& !StringUtil.isNullOrEmpty(inputUserId.getUserId())) {
|
||||
|
||||
int status = messagesStore.getUserStatus(inputUserId.getUserId());
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.ok(new OutputUserStatus(status));
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.RecallMessageData;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("admin/message/recall")
|
||||
@HttpMethod("POST")
|
||||
public class RecallMessageAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
RecallMessageData recallMessageData = getRequestBody(request.getNettyRequest(), RecallMessageData.class);
|
||||
if (recallMessageData != null && !StringUtil.isNullOrEmpty(recallMessageData.getOperator())) {
|
||||
|
||||
WFCMessage.INT64Buf idBuf = WFCMessage.INT64Buf.newBuilder().setId(recallMessageData.getMessageUid()).build();
|
||||
RPCCenter.getInstance().sendRequest(recallMessageData.getOperator(), null, IMTopic.RecallMessageTopic, idBuf.toByteArray(), recallMessageData.getOperator(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageData;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageResult;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("admin/message/send")
|
||||
@HttpMethod("POST")
|
||||
public class SendMessageAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
SendMessageData sendMessageData = getRequestBody(request.getNettyRequest(), SendMessageData.class);
|
||||
if (SendMessageData.isValide(sendMessageData)) {
|
||||
RPCCenter.getInstance().sendRequest(sendMessageData.getSender(), null, IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), sendMessageData.getSender(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
long messageId = byteBuf.readLong();
|
||||
long timestamp = byteBuf.readLong();
|
||||
sendResponse(response, null, new SendMessageResult(messageId, timestamp));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputOutputSensitiveWords;
|
||||
import com.xiaoleilu.loServer.pojos.InputOutputUserBlockStatus;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/sensitive/add")
|
||||
@HttpMethod("POST")
|
||||
public class SensitiveWordAddAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputOutputSensitiveWords input = getRequestBody(request.getNettyRequest(), InputOutputSensitiveWords.class);
|
||||
if (input != null && input.getWords() != null && !input.getWords().isEmpty()) {
|
||||
ErrorCode errorCode = messagesStore.addSensitiveWords(input.getWords()) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_SERVER_ERROR;
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
sendResponse(response, errorCode, null);
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputOutputSensitiveWords;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/sensitive/del")
|
||||
@HttpMethod("POST")
|
||||
public class SensitiveWordDeleteAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputOutputSensitiveWords input = getRequestBody(request.getNettyRequest(), InputOutputSensitiveWords.class);
|
||||
if (input != null && input.getWords() != null && !input.getWords().isEmpty()) {
|
||||
ErrorCode errorCode = messagesStore.removeSensitiveWords(input.getWords()) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_SERVER_ERROR;
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
|
||||
sendResponse(response, errorCode, null);
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.admin;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputOutputSensitiveWords;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Route("admin/sensitive/query")
|
||||
@HttpMethod("POST")
|
||||
public class SensitiveWordQueryAction extends AdminAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
List<String> words = messagesStore.getAllSensitiveWords();
|
||||
InputOutputSensitiveWords out = new InputOutputSensitiveWords();
|
||||
out.setWords(words);
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_SUCCESS, out);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.channel;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.RateLimiter;
|
||||
|
||||
abstract public class ChannelAction extends Action {
|
||||
private final RateLimiter mLimitCounter = new RateLimiter(10, 200);
|
||||
protected WFCMessage.ChannelInfo channelInfo;
|
||||
|
||||
@Override
|
||||
public ErrorCode preAction(Request request, Response response) {
|
||||
String nonce = request.getHeader("nonce");
|
||||
String timestamp = request.getHeader("timestamp");
|
||||
String sign = request.getHeader("sign");
|
||||
String cid = request.getHeader("cid");
|
||||
|
||||
if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign) || StringUtil.isNullOrEmpty(cid)) {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (!mLimitCounter.isGranted(cid)) {
|
||||
return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
|
||||
}
|
||||
|
||||
Long ts;
|
||||
try {
|
||||
ts = Long.parseLong(timestamp);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {
|
||||
return ErrorCode.ERROR_CODE_SIGN_EXPIRED;
|
||||
}
|
||||
|
||||
channelInfo = messagesStore.getChannelInfo(cid);
|
||||
if (channelInfo == null) {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
String str = nonce + "|" + channelInfo.getSecret() + "|" + timestamp;
|
||||
String localSign = DigestUtils.sha1Hex(str);
|
||||
return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
protected void sendResponse(Response response, ErrorCode errorCode, Object data) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if (errorCode == null) {
|
||||
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
response.send();
|
||||
}
|
||||
|
||||
protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {
|
||||
if (request instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
Gson gson = new Gson();
|
||||
T t = gson.fromJson(content, cls);
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.channel;
|
||||
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.admin.AdminAction;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.Conversation;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageData;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageResult;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import static cn.wildfirechat.proto.ProtoConstants.ConversationType.ConversationType_Channel;
|
||||
|
||||
@Route("channel/message/send")
|
||||
@HttpMethod("POST")
|
||||
public class SendMessageAction extends ChannelAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
SendMessageData sendMessageData = getRequestBody(request.getNettyRequest(), SendMessageData.class);
|
||||
sendMessageData.setConv(new Conversation());
|
||||
sendMessageData.getConv().setType(ConversationType_Channel);
|
||||
sendMessageData.getConv().setTarget(channelInfo.getTargetId());
|
||||
sendMessageData.setSender(channelInfo.getOwner());
|
||||
if (SendMessageData.isValide(sendMessageData)) {
|
||||
RPCCenter.getInstance().sendRequest(sendMessageData.getSender(), null, IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), sendMessageData.getSender(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
long messageId = byteBuf.readLong();
|
||||
long timestamp = byteBuf.readLong();
|
||||
sendResponse(response, null, new SendMessageResult(messageId, timestamp));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.robot;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.InputCreateUser;
|
||||
import com.xiaoleilu.loServer.pojos.InputGetUserInfo;
|
||||
import com.xiaoleilu.loServer.pojos.OutputCreateUser;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
|
||||
@Route("admin/robot/user_info")
|
||||
@HttpMethod("POST")
|
||||
public class GetUserAction extends RobotAction {
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
InputGetUserInfo inputUserId = getRequestBody(request.getNettyRequest(), InputGetUserInfo.class);
|
||||
if (inputUserId != null
|
||||
&& (!StringUtil.isNullOrEmpty(inputUserId.getUserId()) || !StringUtil.isNullOrEmpty(inputUserId.getName()))) {
|
||||
|
||||
WFCMessage.User user = null;
|
||||
if(!StringUtil.isNullOrEmpty(inputUserId.getUserId())) {
|
||||
user = messagesStore.getUserInfo(inputUserId.getUserId());
|
||||
} else if(!StringUtil.isNullOrEmpty(inputUserId.getName())) {
|
||||
user = messagesStore.getUserInfoByName(inputUserId.getName());
|
||||
} else if(!StringUtil.isNullOrEmpty(inputUserId.getMobile())) {
|
||||
user = messagesStore.getUserInfoByMobile(inputUserId.getMobile());
|
||||
}
|
||||
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result;
|
||||
if (user == null) {
|
||||
result = RestResult.resultOf(ErrorCode.ERROR_CODE_NOT_EXIST);
|
||||
} else {
|
||||
result = RestResult.ok(InputCreateUser.fromPbUser(user));
|
||||
}
|
||||
|
||||
response.setContent(new Gson().toJson(result));
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.robot;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.spi.impl.Utils;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.RateLimiter;
|
||||
|
||||
abstract public class RobotAction extends Action {
|
||||
private final RateLimiter mLimitCounter = new RateLimiter(10, 1000);
|
||||
|
||||
protected WFCMessage.Robot robot;
|
||||
|
||||
@Override
|
||||
public ErrorCode preAction(Request request, Response response) {
|
||||
String nonce = request.getHeader("nonce");
|
||||
String timestamp = request.getHeader("timestamp");
|
||||
String sign = request.getHeader("sign");
|
||||
String rid = request.getHeader("rid");
|
||||
if (StringUtil.isNullOrEmpty(nonce) || StringUtil.isNullOrEmpty(timestamp) || StringUtil.isNullOrEmpty(sign) || StringUtil.isNullOrEmpty(rid)) {
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (mLimitCounter.isGranted(rid)) {
|
||||
return ErrorCode.ERROR_CODE_OVER_FREQUENCY;
|
||||
}
|
||||
|
||||
Long ts;
|
||||
try {
|
||||
ts = Long.parseLong(timestamp);
|
||||
} catch (NumberFormatException e) {
|
||||
e.printStackTrace();
|
||||
return ErrorCode.INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
if (System.currentTimeMillis() - ts > 2 * 60 * 60 * 1000) {
|
||||
return ErrorCode.ERROR_CODE_SIGN_EXPIRED;
|
||||
}
|
||||
|
||||
robot = messagesStore.getRobot(rid);
|
||||
if (robot == null) {
|
||||
return ErrorCode.ERROR_CODE_NOT_EXIST;
|
||||
}
|
||||
|
||||
String str = nonce + "|" + robot.getSecret() + "|" + timestamp;
|
||||
String localSign = DigestUtils.sha1Hex(str);
|
||||
return localSign.equals(sign) ? ErrorCode.ERROR_CODE_SUCCESS : ErrorCode.ERROR_CODE_AUTH_FAILURE;
|
||||
}
|
||||
|
||||
protected void sendResponse(Response response, ErrorCode errorCode, Object data) {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
if (errorCode == null) {
|
||||
errorCode = ErrorCode.ERROR_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
RestResult result = RestResult.resultOf(errorCode, errorCode.getMsg(), data);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
response.send();
|
||||
}
|
||||
|
||||
protected <T> T getRequestBody(HttpRequest request, Class<T> cls) {
|
||||
if (request instanceof FullHttpRequest) {
|
||||
FullHttpRequest fullHttpRequest = (FullHttpRequest) request;
|
||||
byte[] bytes = Utils.readBytesAndRewind(fullHttpRequest.content());
|
||||
String content = new String(bytes);
|
||||
Gson gson = new Gson();
|
||||
T t = gson.fromJson(content, cls);
|
||||
return t;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.action.robot;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import com.google.gson.Gson;
|
||||
import com.xiaoleilu.loServer.RestResult;
|
||||
import com.xiaoleilu.loServer.action.admin.AdminAction;
|
||||
import com.xiaoleilu.loServer.annotation.HttpMethod;
|
||||
import com.xiaoleilu.loServer.annotation.Route;
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageData;
|
||||
import com.xiaoleilu.loServer.pojos.SendMessageResult;
|
||||
import io.moquette.persistence.RPCCenter;
|
||||
import io.moquette.persistence.TargetEntry;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import win.liyufan.im.ErrorCode;
|
||||
import win.liyufan.im.IMTopic;
|
||||
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@Route("admin/robot/send")
|
||||
@HttpMethod("POST")
|
||||
public class SendMessageAction extends RobotAction {
|
||||
|
||||
@Override
|
||||
public boolean isTransactionAction() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(Request request, Response response) {
|
||||
if (request.getNettyRequest() instanceof FullHttpRequest) {
|
||||
SendMessageData sendMessageData = getRequestBody(request.getNettyRequest(), SendMessageData.class);
|
||||
sendMessageData.setSender(robot.getUid());
|
||||
if (SendMessageData.isValide(sendMessageData)) {
|
||||
RPCCenter.getInstance().sendRequest(sendMessageData.getSender(), null, IMTopic.SendMessageTopic, sendMessageData.toProtoMessage().toByteArray(), sendMessageData.getSender(), TargetEntry.Type.TARGET_TYPE_USER, new RPCCenter.Callback() {
|
||||
@Override
|
||||
public void onSuccess(byte[] result) {
|
||||
ByteBuf byteBuf = Unpooled.buffer();
|
||||
byteBuf.writeBytes(result);
|
||||
ErrorCode errorCode = ErrorCode.fromCode(byteBuf.readByte());
|
||||
if (errorCode == ErrorCode.ERROR_CODE_SUCCESS) {
|
||||
long messageId = byteBuf.readLong();
|
||||
long timestamp = byteBuf.readLong();
|
||||
sendResponse(response, null, new SendMessageResult(messageId, timestamp));
|
||||
} else {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(ErrorCode errorCode) {
|
||||
sendResponse(response, errorCode, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTimeout() {
|
||||
sendResponse(response, ErrorCode.ERROR_CODE_TIMEOUT, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Executor getResponseExecutor() {
|
||||
return command -> {
|
||||
ctx.executor().execute(command);
|
||||
};
|
||||
}
|
||||
});
|
||||
} else {
|
||||
response.setStatus(HttpResponseStatus.OK);
|
||||
RestResult result = RestResult.resultOf(ErrorCode.INVALID_PARAMETER);
|
||||
response.setContent(new Gson().toJson(result));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.annotation;
|
||||
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/
|
||||
@Inherited/*只用于class,可被子类继承*/
|
||||
public @interface HttpMethod {
|
||||
String value() default "GET";
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.annotation;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/
|
||||
@Inherited/*只用于class,可被子类继承*/
|
||||
public @interface RequireAuthentication {
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.annotation;
|
||||
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
|
||||
/**
|
||||
* 注解,用于自定义访问的URL路径<br>
|
||||
* 值可以是一个请求路径,如果需要指定HTTP方法,在前面加方法名用":"分隔既可<br>
|
||||
* @author loolly
|
||||
*
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)/*保留的时间长短*/
|
||||
@Inherited/*只用于class,可被子类继承*/
|
||||
public @interface Route {
|
||||
String value();
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.xiaoleilu.loServer.exception;
|
||||
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
|
||||
/**
|
||||
* 设置异常
|
||||
* @author xiaoleilu
|
||||
*/
|
||||
public class ServerSettingException extends RuntimeException{
|
||||
private static final long serialVersionUID = -4134588858314744501L;
|
||||
|
||||
public ServerSettingException(Throwable e) {
|
||||
super(e);
|
||||
}
|
||||
|
||||
public ServerSettingException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ServerSettingException(String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params));
|
||||
}
|
||||
|
||||
public ServerSettingException(String message, Throwable throwable) {
|
||||
super(message, throwable);
|
||||
}
|
||||
|
||||
public ServerSettingException(Throwable throwable, String messageTemplate, Object... params) {
|
||||
super(StrUtil.format(messageTemplate, params), throwable);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.xiaoleilu.loServer.filter;
|
||||
|
||||
import com.xiaoleilu.loServer.handler.Request;
|
||||
import com.xiaoleilu.loServer.handler.Response;
|
||||
|
||||
/**
|
||||
* 过滤器接口<br>
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public interface Filter {
|
||||
|
||||
/**
|
||||
* 执行过滤
|
||||
* @param request 请求对象
|
||||
* @param response 响应对象
|
||||
* @return 如果返回true,则继续执行下一步内容,否则中断
|
||||
*/
|
||||
public boolean doFilter(Request request, Response response);
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import com.hazelcast.core.HazelcastInstance;
|
||||
import com.xiaoleilu.hutool.lang.Singleton;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.loServer.ServerSetting;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.action.UnknownErrorAction;
|
||||
import com.xiaoleilu.loServer.action.FileAction;
|
||||
import com.xiaoleilu.loServer.filter.Filter;
|
||||
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Action处理单元
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
abstract public class ActionHandler extends SimpleChannelInboundHandler<FullHttpRequest> {
|
||||
private static final Logger Logger = LoggerFactory.getLogger(ActionHandler.class);
|
||||
|
||||
public ActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {
|
||||
Action.messagesStore = messagesStore;
|
||||
Action.sessionsStore = sessionsStore;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest fullHttpRequest) throws Exception {
|
||||
Logger.info("Http request whit url {}", fullHttpRequest.uri());
|
||||
final Request request = Request.build(ctx, fullHttpRequest);
|
||||
final Response response = Response.build(ctx, request);
|
||||
|
||||
response.setContentType("application/json");
|
||||
try {
|
||||
//do filter
|
||||
boolean isPass = this.doFilter(request, response);
|
||||
|
||||
if(isPass){
|
||||
//do action
|
||||
this.doAction(ctx, request, response);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Action errorAction = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);
|
||||
request.putParam(UnknownErrorAction.ERROR_PARAM_NAME, e);
|
||||
response.setContent(e.toString());
|
||||
errorAction.doAction(request, response);
|
||||
|
||||
//如果发送请求未被触发,则触发之,否则跳过。
|
||||
if(!response.isSent()){
|
||||
response.send();
|
||||
}
|
||||
|
||||
ctx.fireExceptionCaught(e);
|
||||
ctx.close();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
|
||||
super.exceptionCaught(ctx, cause);
|
||||
Logger.warn("{}", cause.getMessage());
|
||||
Channel channel = ctx.channel();
|
||||
if(channel.isActive())ctx.close();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------- Private method start
|
||||
/**
|
||||
* 执行过滤
|
||||
* @param request 请求
|
||||
* @param response 响应
|
||||
* @@return 是否继续
|
||||
*/
|
||||
private boolean doFilter(Request request, Response response) {
|
||||
//全局过滤器
|
||||
Filter filter = ServerSetting.getFilter(ServerSetting.MAPPING_ALL);
|
||||
if(null != filter){
|
||||
if(false == filter.doFilter(request, response)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//自定义Path过滤器
|
||||
filter = ServerSetting.getFilter(request.getPath());
|
||||
if(null != filter){
|
||||
if(false == filter.doFilter(request, response)){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
abstract boolean isValidePath(String path);
|
||||
/**
|
||||
* 执行Action
|
||||
* @param request 请求对象
|
||||
* @param response 响应对象
|
||||
*/
|
||||
private void doAction(ChannelHandlerContext ctx, Request request, Response response){
|
||||
Action action;
|
||||
if (isValidePath(request.getPath())) {
|
||||
action = ServerSetting.getAction(request.getPath(), request.getMethod().toUpperCase());
|
||||
} else {
|
||||
action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);
|
||||
}
|
||||
|
||||
if (action == null && (request.getPath().startsWith("/api") || request.getPath().startsWith("/admin"))) {
|
||||
action = ServerSetting.getErrorAction(ServerSetting.MAPPING_ERROR);
|
||||
}
|
||||
|
||||
if (null == action) {
|
||||
//查找匹配所有路径的Action
|
||||
action = ServerSetting.getAction(ServerSetting.MAPPING_ALL, request.getMethod());
|
||||
if(null == action){
|
||||
// 非Action方法,调用静态文件读取
|
||||
action = Singleton.get(FileAction.class);
|
||||
}
|
||||
}
|
||||
action.ctx = ctx;
|
||||
|
||||
boolean isSync = action.doAction(request, response);
|
||||
|
||||
if(isSync) {
|
||||
//如果发送请求未被触发,则触发之,否则跳过。
|
||||
if(!response.isSent()){
|
||||
response.send();
|
||||
}
|
||||
}
|
||||
}
|
||||
//---------------------------------------------------------------------------------------- Private method start
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import com.xiaoleilu.hutool.lang.Singleton;
|
||||
import com.xiaoleilu.loServer.ServerSetting;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.action.FileAction;
|
||||
import com.xiaoleilu.loServer.action.UnknownErrorAction;
|
||||
import com.xiaoleilu.loServer.filter.Filter;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Action处理单元
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class AdminActionHandler extends ActionHandler {
|
||||
private static final Logger Logger = LoggerFactory.getLogger(AdminActionHandler.class);
|
||||
|
||||
public AdminActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {
|
||||
super(messagesStore, sessionsStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValidePath(String path) {
|
||||
if (path.startsWith("/admin")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelPromise;
|
||||
import io.netty.channel.FileRegion;
|
||||
import io.netty.handler.codec.http.DefaultHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpContentCompressor;
|
||||
|
||||
/**
|
||||
* 解决大文件传输与Gzip压缩冲突问题
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class HttpChunkContentCompressor extends HttpContentCompressor {
|
||||
@Override
|
||||
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
|
||||
StaticLog.debug("Write object [{}]", msg);
|
||||
|
||||
if (msg instanceof FileRegion || msg instanceof DefaultHttpResponse) {
|
||||
//文件传输不经过Gzip压缩
|
||||
ctx.write(msg, promise);
|
||||
}else{
|
||||
super.write(ctx, msg, promise);
|
||||
}
|
||||
}
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class HttpFileServerController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpFileServerController.class);
|
||||
private Map<String, ChannelHandlerContext> contextMap = null; //
|
||||
|
||||
private static class BrokenUploadInfoHandlerHolder {
|
||||
private static HttpFileServerController singleton = new HttpFileServerController();
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*/
|
||||
private HttpFileServerController() {
|
||||
contextMap = new ConcurrentHashMap<String, ChannelHandlerContext>();
|
||||
}
|
||||
|
||||
/**
|
||||
* getInstance
|
||||
*/
|
||||
public static HttpFileServerController getInstance() {
|
||||
return BrokenUploadInfoHandlerHolder.singleton;
|
||||
}
|
||||
|
||||
/**
|
||||
* mapChannelHandlerContext
|
||||
*
|
||||
* @param requestId
|
||||
* @param ctx
|
||||
*/
|
||||
public synchronized void mapChannelHandlerContext(String requestId, ChannelHandlerContext ctx) {
|
||||
if (contextMap.containsKey(requestId)) {
|
||||
logger.warn("contextMap has already contained the key:" + requestId);
|
||||
}
|
||||
|
||||
contextMap.put(requestId, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* getContext
|
||||
*
|
||||
* @param requestId
|
||||
* @return
|
||||
*/
|
||||
public ChannelHandlerContext getChannelHandlerContext(String requestId) {
|
||||
if (!contextMap.containsKey(requestId)) {
|
||||
logger.warn("contextMap not contains the key:" + requestId);
|
||||
return null;
|
||||
}
|
||||
|
||||
return contextMap.get(requestId);
|
||||
}
|
||||
|
||||
/**
|
||||
* removeContext
|
||||
*
|
||||
* @param requestId
|
||||
*/
|
||||
public void removeChannelHandlerContext(String requestId) {
|
||||
if (!contextMap.containsKey(requestId)) {
|
||||
logger.warn("contextMap not contains the key:" + requestId);
|
||||
return;
|
||||
}
|
||||
|
||||
contextMap.remove(requestId);
|
||||
// logger.info("contextMap remove done.(" + requestId + ")");
|
||||
}
|
||||
}
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import io.moquette.server.config.MediaServerConfig;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.handler.codec.http.multipart.*;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.xiaoleilu.loServer.handler.HttpResponseHelper.getFileExt;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.*;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_HEADERS;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
public class HttpFileServerHandler extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpFileServerHandler.class);
|
||||
private static final HttpDataFactory factory = new DefaultHttpDataFactory(false);
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
try {
|
||||
if (msg instanceof FullHttpRequest) {
|
||||
FullHttpRequest request = (FullHttpRequest) msg;
|
||||
String requestId = UUID.randomUUID().toString().replace("-", "");
|
||||
logger.info("HttpFileServerHandler received a request: method=" + request.getMethod() + ", uri=" + request.getUri() + ", requestId=" + requestId);
|
||||
|
||||
if (!request.getDecoderResult().isSuccess()) {
|
||||
logger.warn("http decode failed!");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.getMethod() == HttpMethod.GET) {
|
||||
download(ctx, request, requestId);
|
||||
} else if (request.getMethod() == HttpMethod.POST) {
|
||||
multipartUpload(ctx, request, requestId);
|
||||
} else if (request.getMethod() == HttpMethod.DELETE) {
|
||||
delete(ctx, request, requestId);
|
||||
} else if (request.getMethod() == HttpMethod.OPTIONS) {
|
||||
doOptions(ctx, request);
|
||||
} else {
|
||||
logger.warn("METHOD_NOT_ALLOWED!(methodName=" + request.getMethod().name() + ")");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
|
||||
}
|
||||
} else {
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "Not a http request");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("HttpFileServerHandler.channelRead0() process error!", e);
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
|
||||
try {
|
||||
if (ctx.channel().isActive()) {
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
logger.warn("exceptionCaught:" + cause.getMessage());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.warn("exceptionCaught error!" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* multipart上传
|
||||
*/
|
||||
private void multipartUpload(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {
|
||||
HttpPostRequestDecoder decoder = null;
|
||||
try {
|
||||
decoder = new HttpPostRequestDecoder(factory, request);
|
||||
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
|
||||
logger.error("Failed to decode file data!", e1);
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "Failed to decode file data!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (decoder != null) {
|
||||
if (request instanceof HttpContent) {
|
||||
HttpContent chunk = (HttpContent) request;
|
||||
try {
|
||||
decoder.offer(chunk);
|
||||
} catch (HttpPostRequestDecoder.ErrorDataDecoderException e1) {
|
||||
logger.warn("BAD_REQUEST, Failed to decode file data");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "Failed to decode file data");
|
||||
return;
|
||||
}
|
||||
|
||||
long fileTotalSize = 0;
|
||||
if (request.headers().contains("X-File-Total-Size")) {
|
||||
try {
|
||||
fileTotalSize = Integer.parseInt(request.headers().get("X-File-Total-Size"));
|
||||
} catch (Exception e) {
|
||||
logger.warn("invalid X-File-Total-Size value!");
|
||||
}
|
||||
}
|
||||
|
||||
readHttpDataChunkByChunk(ctx, decoder, requestId, HttpHeaders.isKeepAlive(request));
|
||||
|
||||
if (chunk instanceof LastHttpContent) {
|
||||
releaseRequest(request, decoder);
|
||||
}
|
||||
} else {
|
||||
logger.warn("BAD_REQUEST, Not a http request");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "Not a http request");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* readHttpDataChunkByChunk
|
||||
*/
|
||||
private void readHttpDataChunkByChunk(ChannelHandlerContext ctx, HttpPostRequestDecoder decoder, String requestId, boolean isKeepAlive) {
|
||||
try {
|
||||
while (decoder.hasNext()) {
|
||||
InterfaceHttpData data = decoder.next();
|
||||
if (data != null) {
|
||||
try {
|
||||
writeFileUploadData(data, ctx, requestId, isKeepAlive);
|
||||
} finally {
|
||||
data.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.info("chunk end");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* writeFileUploadData
|
||||
*/
|
||||
private void writeFileUploadData(InterfaceHttpData data, ChannelHandlerContext ctx, String requestId, boolean isKeepAlive) {
|
||||
try {
|
||||
if (data.getHttpDataType() == InterfaceHttpData.HttpDataType.FileUpload) {
|
||||
FileUpload fileUpload = (FileUpload) data;
|
||||
|
||||
String remoteFileName = fileUpload.getFilename();
|
||||
long remoteFileSize = fileUpload.length();
|
||||
if (StringUtil.isNullOrEmpty(remoteFileName)) {
|
||||
logger.warn("remoteFileName is empty!");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "file name is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(requestId)) {
|
||||
logger.warn("requestId is empty!");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "requestId is empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (remoteFileSize > 10 * 1024 * 1024) {
|
||||
logger.warn("file over limite!(" + remoteFileSize + ")");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "file over limite!");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String remoteFileExt = "";
|
||||
if (remoteFileName.lastIndexOf(".") == -1) {
|
||||
remoteFileExt = "octetstream";
|
||||
remoteFileName = remoteFileName + "." + remoteFileExt;
|
||||
|
||||
} else {
|
||||
remoteFileExt = getFileExt(remoteFileName);
|
||||
}
|
||||
|
||||
if (StringUtil.isNullOrEmpty(remoteFileExt) || remoteFileExt.equals("ing")) {
|
||||
logger.warn("Invalid file extention name");
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "Invalid file extention name");
|
||||
return;
|
||||
}
|
||||
|
||||
int remoteFileTotalSize = (int) remoteFileSize;
|
||||
|
||||
HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);
|
||||
|
||||
ByteBuf byteBuf = null;
|
||||
int savedThunkSize = 0; // 分片接收保存的大小
|
||||
int offset = 0; // 断点续传开始位置
|
||||
|
||||
File tmpFile = new File("./" + MediaServerConfig.FILE_STROAGE_ROOT + "/" + requestId);
|
||||
|
||||
boolean isError = false;
|
||||
while (true) {
|
||||
byte[] thunkData;
|
||||
try {
|
||||
byteBuf = fileUpload.getChunk(128 * 1024);
|
||||
int readableBytesSize = byteBuf.readableBytes();
|
||||
thunkData = new byte[readableBytesSize];
|
||||
byteBuf.readBytes(thunkData);
|
||||
|
||||
put(tmpFile, offset, thunkData);
|
||||
|
||||
savedThunkSize += readableBytesSize;
|
||||
offset += readableBytesSize;
|
||||
|
||||
if (savedThunkSize >= remoteFileSize) {
|
||||
byteBuf.release();
|
||||
fileUpload.release();
|
||||
HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.OK, HttpHeaders.Values.APPLICATION_JSON, "{\"key\":\"" + requestId + "\"}", true, false);
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("save thunckData error!", e);
|
||||
if (fileUpload != null)
|
||||
fileUpload.release();
|
||||
|
||||
if (byteBuf != null)
|
||||
byteBuf.release();
|
||||
|
||||
HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
isError = true;
|
||||
|
||||
return;
|
||||
} finally {
|
||||
thunkData = null;
|
||||
if (isError) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("writeHttpData error!", e);
|
||||
HttpResponseHelper.sendResponse(requestId, ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
public static void put(File file, long pos, byte[] data) throws Exception {
|
||||
RandomAccessFile raf = null;
|
||||
try {
|
||||
raf = new RandomAccessFile(file, "rwd");
|
||||
raf.seek(pos);
|
||||
raf.write(data);
|
||||
} finally {
|
||||
try {
|
||||
if (raf != null)
|
||||
raf.close();
|
||||
} catch (Exception e) {
|
||||
logger.warn("release error!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载
|
||||
*/
|
||||
private void download(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {
|
||||
// try {
|
||||
// final String httpUri = request.getUri();
|
||||
// if (httpUri.toLowerCase().equals("/favicon.ico")) {
|
||||
// logger.warn("invalid httpUri(" + httpUri + ", requestId=" + requestId + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "invalid httpUri");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// String typedDownloadInfo = MetaDataIndexHandler.getTypedDownloadInfo(httpUri);
|
||||
// if (StringUtil.isNullOrEmpty(typedDownloadInfo)) {
|
||||
// logger.warn("invalid httpUri(" + httpUri + ", requestId=" + requestId + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "invalid httpUri");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// MetaDataIndex metadataIndex = MetaDataIndexHandler.parseTypedDownloadInfo(typedDownloadInfo);
|
||||
// if (metadataIndex == null) {
|
||||
// logger.warn("invalid typedDownloadInfo!(" + typedDownloadInfo + ", requestId=" + requestId + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "invalid downloadFileName");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// int fileSize = MetaDataHandler.getDataFieldLength(metadataIndex);
|
||||
// int chunkSize = FileStorageConst.Stroage_Remote_Invoke_Thunk_Size;
|
||||
// int chunkCount = fileSize % chunkSize == 0 ? (int) (fileSize / chunkSize) : (int) (fileSize / chunkSize + 1);
|
||||
//
|
||||
// ClusterNode toNode = StorageClusterRouterManager.getInstance().getDownloadNode(metadataIndex.getClusterNode());
|
||||
// if(toNode == null) {
|
||||
// logger.warn("toNode is null!(" + typedDownloadInfo + ", requestId=" + requestId + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.NOT_FOUND, "File Not Existed");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// ClusterNode fromNode = StorageClusterRouterManager.getInstance().getSelfNode();
|
||||
// ActorSystem actorSystem = StorageClusterRouterManager.getInstance().getStorageActorSystem();
|
||||
// ActorRef toActorRef = actorSystem.actorOf(toNode.getIp(), toNode.getRpcPort(), ActorType.DownloadActor.getName());
|
||||
// ActorRef fromActorRef = actorSystem.actorOf(fromNode.getIp(),fromNode.getRpcPort(), ActorType.HttpFileServerActor.getName());
|
||||
//
|
||||
// HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);
|
||||
//
|
||||
// DownloadMsg downloadMsg = new DownloadMsg();
|
||||
// downloadMsg.setRequestId(requestId);
|
||||
// downloadMsg.setIsKeepAlive(HttpHeaders.isKeepAlive(request));
|
||||
// downloadMsg.setClusterNode(metadataIndex.getClusterNode());
|
||||
// downloadMsg.setFileSize(fileSize);
|
||||
// downloadMsg.setChunkIndex(0);
|
||||
// downloadMsg.setChunkSize(chunkSize);
|
||||
// downloadMsg.setChunkCount(chunkCount);
|
||||
// downloadMsg.setTime(metadataIndex.getTime());
|
||||
// downloadMsg.setBigFileIndex(metadataIndex.getBigFileIndex());
|
||||
// downloadMsg.setOffset(metadataIndex.getOffset());
|
||||
// downloadMsg.setMetaDataTotalLength(metadataIndex.getMetaDataTotalLength());
|
||||
// downloadMsg.setFileType(metadataIndex.getFileType());
|
||||
// downloadMsg.setBigFilePath(metadataIndex.getBigFilePath());
|
||||
// downloadMsg.setStorageEngineVersion(metadataIndex.getStorageEngineVersion());
|
||||
// toActorRef.tell(downloadMsg, fromActorRef);
|
||||
// } catch (Exception e) {
|
||||
// logger.error("download error!", e);
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
// } finally {
|
||||
// releaseRequest(request, null);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*/
|
||||
private void delete(ChannelHandlerContext ctx, FullHttpRequest request, String requestId) {
|
||||
// try {
|
||||
// final String httpUri = request.getUri();
|
||||
// String typedDownloadInfo = MetaDataIndexHandler.getTypedDownloadInfo(httpUri);
|
||||
// if (StringUtil.isNullOrEmpty(typedDownloadInfo)) {
|
||||
// logger.warn("invalid httpUri(" + httpUri + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "invalid httpUri");
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// MetaDataIndex metadataIndex = MetaDataIndexHandler.parseTypedDownloadInfo(typedDownloadInfo);
|
||||
// if (metadataIndex == null) {
|
||||
// logger.warn("invalid typedDownloadInfo!(" + typedDownloadInfo + ")");
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.BAD_REQUEST, "invalid downloadFileName");
|
||||
// }
|
||||
//
|
||||
// ClusterNode toNode = StorageClusterRouterManager.getInstance().getClusterNode(metadataIndex.getClusterNode());
|
||||
// ClusterNode fromNode = StorageClusterRouterManager.getInstance().getSelfNode();
|
||||
// ActorSystem actorSystem = StorageClusterRouterManager.getInstance().getStorageActorSystem();
|
||||
// ActorRef toActorRef = actorSystem.actorOf(toNode.getIp(), toNode.getRpcPort(), ActorType.DeleteActor.getName());
|
||||
// ActorRef fromActorRef = actorSystem.actorOf(fromNode.getIp(),fromNode.getRpcPort(), ActorType.HttpFileServerActor.getName());
|
||||
//
|
||||
// HttpFileServerController.getInstance().mapChannelHandlerContext(requestId, ctx);
|
||||
//
|
||||
// DeleteMsg downloadMsg = new DeleteMsg();
|
||||
// downloadMsg.setRequestId(requestId);
|
||||
// downloadMsg.setIsKeepAlive(HttpHeaders.isKeepAlive(request));
|
||||
// downloadMsg.setClusterNode(metadataIndex.getClusterNode());
|
||||
// downloadMsg.setTime(metadataIndex.getTime());
|
||||
// downloadMsg.setBigFileIndex(metadataIndex.getBigFileIndex());
|
||||
// downloadMsg.setOffset(metadataIndex.getOffset());
|
||||
// downloadMsg.setMetaDataTotalLength(metadataIndex.getMetaDataTotalLength());
|
||||
// downloadMsg.setFileType(metadataIndex.getFileType());
|
||||
// downloadMsg.setBigFilePath(metadataIndex.getBigFilePath());
|
||||
// downloadMsg.setStorageEngineVersion(metadataIndex.getStorageEngineVersion());
|
||||
// toActorRef.tell(downloadMsg, fromActorRef);
|
||||
// } catch (Exception e) {
|
||||
// logger.error("delete error!", e);
|
||||
// HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
// } finally {
|
||||
// releaseRequest(request, null);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* HTTP能力探测
|
||||
*/
|
||||
private void doOptions(ChannelHandlerContext ctx, FullHttpRequest request) {
|
||||
try {
|
||||
boolean isKeepAlive = HttpHeaders.isKeepAlive(request);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NO_CONTENT);
|
||||
response.headers().set(CONTENT_TYPE, HttpHeaders.Values.APPLICATION_JSON);
|
||||
response.headers().set(TRANSFER_ENCODING, "chunked");
|
||||
if (isKeepAlive)
|
||||
response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, DELETE, OPTIONS");
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_HEADERS, "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization");
|
||||
|
||||
ChannelFuture future = ctx.channel().writeAndFlush(response);
|
||||
if (!isKeepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.error("doOptions error!", e);
|
||||
HttpResponseHelper.sendResponse("", ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
|
||||
} finally {
|
||||
releaseRequest(request, null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* releaseRequest
|
||||
*/
|
||||
private void releaseRequest(FullHttpRequest request, HttpPostRequestDecoder decoder) {
|
||||
try {
|
||||
if (request != null)
|
||||
request.release();
|
||||
|
||||
request = null;
|
||||
|
||||
if (decoder != null)
|
||||
decoder.destroy();
|
||||
|
||||
decoder = null;
|
||||
} catch (Exception e) {
|
||||
logger.error("reset error!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import com.xiaoleilu.hutool.util.FileUtil;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.*;
|
||||
import io.netty.util.CharsetUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import javax.activation.MimetypesFileTypeMap;
|
||||
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_RANGE;
|
||||
import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
|
||||
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;
|
||||
|
||||
|
||||
public class HttpResponseHelper {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(HttpResponseHelper.class);
|
||||
private static final MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();
|
||||
|
||||
/**
|
||||
* sendResponse
|
||||
*
|
||||
* @param ctx
|
||||
* @param status
|
||||
*/
|
||||
public static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status) {
|
||||
sendResponse(requestId, ctx, status, "status: " + status.toString() + "\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* sendResponse
|
||||
*
|
||||
* @param ctx
|
||||
* @param status
|
||||
* @param msg
|
||||
*/
|
||||
public static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status, String msg) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer(msg, CharsetUtil.UTF_8));
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
||||
removeChannelHandlerContext(requestId, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* sendResponse(成功应答需要注意isKeepAlive和isCloseChannel的值)
|
||||
*
|
||||
* @param requestId
|
||||
* @param ctx
|
||||
* @param status
|
||||
* @param contentType
|
||||
* @param respBodyString
|
||||
* @param isKeepAlive
|
||||
* @param isCloseChannel
|
||||
*/
|
||||
public static void sendResponse(String requestId, ChannelHandlerContext ctx, HttpResponseStatus status, String contentType, String respBodyString, boolean isKeepAlive, boolean isCloseChannel) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, Unpooled.copiedBuffer(respBodyString, CharsetUtil.UTF_8));
|
||||
if (!StringUtil.isNullOrEmpty(contentType)) {
|
||||
response.headers().set(CONTENT_TYPE, contentType);
|
||||
} else {
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
}
|
||||
|
||||
if (isKeepAlive) {
|
||||
response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
|
||||
}
|
||||
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
|
||||
ChannelFuture future = ctx.channel().writeAndFlush(response);
|
||||
if (!isKeepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
removeChannelHandlerContext(requestId, ctx, isCloseChannel);
|
||||
}
|
||||
|
||||
/**
|
||||
* sendResponse
|
||||
*
|
||||
* @param ctx
|
||||
* @param statusCode
|
||||
* @param resultDesc
|
||||
*/
|
||||
public static void sendResponse(String requestId, ChannelHandlerContext ctx, int statusCode, String resultDesc) {
|
||||
HttpResponseStatus httpResponseStatus = new HttpResponseStatus(statusCode, resultDesc);
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, httpResponseStatus, Unpooled.copiedBuffer(resultDesc, CharsetUtil.UTF_8));
|
||||
response.headers().set(CONTENT_TYPE, "text/plain; charset=UTF-8");
|
||||
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, response.content().readableBytes());
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
|
||||
|
||||
removeChannelHandlerContext(requestId, ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* 断点上传204应答
|
||||
*
|
||||
* @param ctx
|
||||
* @param contentRange
|
||||
*/
|
||||
public static void sendBrokenUpload204Resonse(String requestId, ChannelHandlerContext ctx, String contentRange, boolean isKeepAlive, boolean isCloseChannel) {
|
||||
FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NO_CONTENT, Unpooled.copiedBuffer("", CharsetUtil.UTF_8));
|
||||
response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
|
||||
response.headers().set(CONTENT_RANGE, contentRange);
|
||||
|
||||
ChannelFuture future = ctx.channel().writeAndFlush(response);
|
||||
if (!isKeepAlive) {
|
||||
future.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
removeChannelHandlerContext(requestId, ctx, isCloseChannel);
|
||||
}
|
||||
|
||||
|
||||
public static String getMultipartUploadResponseBody(String remoteFileName, String fileUrl) throws Exception {
|
||||
|
||||
return "{\"rc_url\":{\"path\":\"" + fileUrl + "\",\"type\":0}}";
|
||||
}
|
||||
|
||||
/**
|
||||
* getContentType
|
||||
*
|
||||
* @param fileName
|
||||
* @return
|
||||
*/
|
||||
|
||||
public static String getFileExt(String fileName) {
|
||||
int index = fileName.lastIndexOf(".");
|
||||
if (index == -1) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return fileName.substring(index + 1).toLowerCase();
|
||||
}
|
||||
|
||||
public static String getContentType(String fileName) {
|
||||
String fileExtName = getFileExt(fileName);
|
||||
if (fileExtName.equals("png")) { // MimetypesFileTypeMap目前缺少png类型
|
||||
return "image/png";
|
||||
} else {
|
||||
return mimetypesFileTypeMap.getContentType(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* removeChannelHandlerContext
|
||||
*
|
||||
* @param requestId
|
||||
* @param ctx
|
||||
*/
|
||||
private static void removeChannelHandlerContext(String requestId, ChannelHandlerContext ctx) {
|
||||
removeChannelHandlerContext(requestId, ctx, true);
|
||||
}
|
||||
|
||||
private static void removeChannelHandlerContext(String requestId, ChannelHandlerContext ctx, boolean isCloseChannel) {
|
||||
try {
|
||||
if (!StringUtil.isNullOrEmpty(requestId)) {
|
||||
// HttpFileServerController.getInstance().removeChannelHandlerContext(requestId);
|
||||
}
|
||||
|
||||
if (isCloseChannel)
|
||||
ctx.channel().close();
|
||||
} catch (Exception e) {
|
||||
logger.error("close error!", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import com.xiaoleilu.hutool.lang.Singleton;
|
||||
import com.xiaoleilu.loServer.ServerSetting;
|
||||
import com.xiaoleilu.loServer.action.Action;
|
||||
import com.xiaoleilu.loServer.action.FileAction;
|
||||
import com.xiaoleilu.loServer.action.UnknownErrorAction;
|
||||
import com.xiaoleilu.loServer.filter.Filter;
|
||||
import io.moquette.spi.IMessagesStore;
|
||||
import io.moquette.spi.ISessionsStore;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.SimpleChannelInboundHandler;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Action处理单元
|
||||
*
|
||||
* @author Looly
|
||||
*/
|
||||
public class IMActionHandler extends ActionHandler {
|
||||
private static final Logger Logger = LoggerFactory.getLogger(IMActionHandler.class);
|
||||
|
||||
public IMActionHandler(IMessagesStore messagesStore, ISessionsStore sessionsStore) {
|
||||
super(messagesStore, sessionsStore);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValidePath(String path) {
|
||||
if (!path.startsWith("/admin")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,531 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import com.xiaoleilu.hutool.http.HttpUtil;
|
||||
import com.xiaoleilu.hutool.lang.Conver;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.CharsetUtil;
|
||||
import com.xiaoleilu.hutool.util.DateUtil;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.hutool.util.URLUtil;
|
||||
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.handler.codec.http.FullHttpRequest;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpMethod;
|
||||
import io.netty.handler.codec.http.HttpRequest;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.QueryStringDecoder;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
|
||||
import io.netty.handler.codec.http.multipart.Attribute;
|
||||
import io.netty.handler.codec.http.multipart.DefaultHttpDataFactory;
|
||||
import io.netty.handler.codec.http.multipart.FileUpload;
|
||||
import io.netty.handler.codec.http.multipart.HttpDataFactory;
|
||||
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
|
||||
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
|
||||
import io.netty.handler.codec.http.multipart.InterfaceHttpData.HttpDataType;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Http请求对象
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class Request {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(Request.class);
|
||||
|
||||
public static final String METHOD_DELETE = HttpMethod.DELETE.name();
|
||||
public static final String METHOD_HEAD = HttpMethod.HEAD.name();
|
||||
public static final String METHOD_GET = HttpMethod.GET.name();
|
||||
public static final String METHOD_OPTIONS = HttpMethod.OPTIONS.name();
|
||||
public static final String METHOD_POST = HttpMethod.POST.name();
|
||||
public static final String METHOD_PUT = HttpMethod.PUT.name();
|
||||
public static final String METHOD_TRACE = HttpMethod.TRACE.name();
|
||||
|
||||
private static final HttpDataFactory HTTP_DATA_FACTORY = new DefaultHttpDataFactory(DefaultHttpDataFactory.MINSIZE);
|
||||
|
||||
private FullHttpRequest nettyRequest;
|
||||
|
||||
private String path;
|
||||
private String ip;
|
||||
private Map<String, String> headers = new HashMap<String, String>();
|
||||
private Map<String, Object> params = new HashMap<String, Object>();
|
||||
private Map<String, Cookie> cookies = new HashMap<String, Cookie>();
|
||||
|
||||
/**
|
||||
* 构造
|
||||
*
|
||||
* @param ctx ChannelHandlerContext
|
||||
* @param nettyRequest HttpRequest
|
||||
*/
|
||||
private Request(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
|
||||
this.nettyRequest = nettyRequest;
|
||||
final String uri = nettyRequest.uri();
|
||||
this.path = URLUtil.getPath(getUri());
|
||||
|
||||
this.putHeadersAndCookies(nettyRequest.headers());
|
||||
|
||||
// request URI parameters
|
||||
this.putParams(new QueryStringDecoder(uri));
|
||||
if(nettyRequest.method() != HttpMethod.GET){
|
||||
HttpPostRequestDecoder decoder = null;
|
||||
try {
|
||||
decoder = new HttpPostRequestDecoder(HTTP_DATA_FACTORY, nettyRequest);
|
||||
this.putParams(decoder);
|
||||
} finally {
|
||||
if(null != decoder){
|
||||
decoder.destroy();
|
||||
decoder = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IP
|
||||
this.putIp(ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Netty的HttpRequest
|
||||
*/
|
||||
public HttpRequest getNettyRequest() {
|
||||
return this.nettyRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得版本信息
|
||||
*
|
||||
* @return 版本
|
||||
*/
|
||||
public String getProtocolVersion() {
|
||||
return nettyRequest.protocolVersion().text();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得URI(带参数的路径)
|
||||
*
|
||||
* @return URI
|
||||
*/
|
||||
public String getUri() {
|
||||
return nettyRequest.uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得path(不带参数的路径)
|
||||
*/
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得Http方法
|
||||
*
|
||||
* @return Http method
|
||||
*/
|
||||
public String getMethod() {
|
||||
return nettyRequest.method().name();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得IP地址
|
||||
*
|
||||
* @return IP地址
|
||||
*/
|
||||
public String getIp() {
|
||||
return ip;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有头信息
|
||||
*
|
||||
* @return 头信息Map
|
||||
*/
|
||||
public Map<String, String> getHeaders() {
|
||||
return headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* 使用ISO8859_1字符集获得Header内容<br>
|
||||
* 由于Header中很少有中文,故一般情况下无需转码
|
||||
*
|
||||
* @param headerKey 头信息的KEY
|
||||
* @return 值
|
||||
*/
|
||||
public String getHeader(String headerKey) {
|
||||
return headers.get(headerKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否为普通表单(application/x-www-form-urlencoded)
|
||||
*/
|
||||
public boolean isXWwwFormUrlencoded() {
|
||||
return "application/x-www-form-urlencoded".equals(getHeader("Content-Type"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定的Cookie
|
||||
*
|
||||
* @param name cookie名
|
||||
* @return Cookie对象
|
||||
*/
|
||||
public Cookie getCookie(String name) {
|
||||
return cookies.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 获得所有Cookie信息
|
||||
*/
|
||||
public Map<String, Cookie> getCookies() {
|
||||
return this.cookies;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 客户浏览器是否为IE
|
||||
*/
|
||||
public boolean isIE() {
|
||||
String userAgent = getHeader("User-Agent");
|
||||
if (StrUtil.isNotBlank(userAgent)) {
|
||||
userAgent = userAgent.toUpperCase();
|
||||
if (userAgent.contains("MSIE") || userAgent.contains("TRIDENT")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @return 获得请求参数
|
||||
*/
|
||||
public String getParam(String name) {
|
||||
final Object value = params.get(name);
|
||||
if(null == value){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(value instanceof String){
|
||||
return (String)value;
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @return 获得请求参数
|
||||
*/
|
||||
public Object getObjParam(String name) {
|
||||
return params.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得GET请求参数<br>
|
||||
* 会根据浏览器类型自动识别GET请求的编码方式从而解码<br>
|
||||
* charsetOfServlet为null则默认的ISO_8859_1
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param charset 字符集
|
||||
* @return 获得请求参数
|
||||
*/
|
||||
public String getParam(String name, Charset charset) {
|
||||
if (null == charset) {
|
||||
charset = Charset.forName(CharsetUtil.ISO_8859_1);
|
||||
}
|
||||
|
||||
String destCharset = CharsetUtil.UTF_8;
|
||||
if (isIE()) {
|
||||
// IE浏览器GET请求使用GBK编码
|
||||
destCharset = CharsetUtil.GBK;
|
||||
}
|
||||
|
||||
String value = getParam(name);
|
||||
if (METHOD_GET.equalsIgnoreCase(getMethod())) {
|
||||
value = CharsetUtil.convert(value, charset.toString(), destCharset);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得请求参数
|
||||
*/
|
||||
public String getParam(String name, String defaultValue) {
|
||||
String param = getParam(name);
|
||||
return StrUtil.isBlank(param) ? defaultValue : param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Integer类型请求参数
|
||||
*/
|
||||
public Integer getIntParam(String name, Integer defaultValue) {
|
||||
return Conver.toInt(getParam(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得long类型请求参数
|
||||
*/
|
||||
public Long getLongParam(String name, Long defaultValue) {
|
||||
return Conver.toLong(getParam(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Double类型请求参数
|
||||
*/
|
||||
public Double getDoubleParam(String name, Double defaultValue) {
|
||||
return Conver.toDouble(getParam(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Float类型请求参数
|
||||
*/
|
||||
public Float getFloatParam(String name, Float defaultValue) {
|
||||
return Conver.toFloat(getParam(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Boolean类型请求参数
|
||||
*/
|
||||
public Boolean getBoolParam(String name, Boolean defaultValue) {
|
||||
return Conver.toBool(getParam(name), defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式:<br>
|
||||
* 1、yyyy-MM-dd HH:mm:ss <br>
|
||||
* 2、yyyy-MM-dd <br>
|
||||
* 3、HH:mm:ss <br>
|
||||
*
|
||||
* @param name 参数名
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Date类型请求参数,默认格式:
|
||||
*/
|
||||
public Date getDateParam(String name, Date defaultValue) {
|
||||
String param = getParam(name);
|
||||
return StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name 参数名
|
||||
* @param format 格式
|
||||
* @param defaultValue 当客户端未传参的默认值
|
||||
* @return 获得Date类型请求参数
|
||||
*/
|
||||
public Date getDateParam(String name, String format, Date defaultValue) {
|
||||
String param = getParam(name);
|
||||
return StrUtil.isBlank(param) ? defaultValue : DateUtil.parse(param, format);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得请求参数<br>
|
||||
* 列表类型值,常用于表单中的多选框
|
||||
*
|
||||
* @param name 参数名
|
||||
* @return 数组
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public List<String> getArrayParam(String name) {
|
||||
Object value = params.get(name);
|
||||
if(null == value){
|
||||
return null;
|
||||
}
|
||||
|
||||
if(value instanceof List){
|
||||
return (List<String>) value;
|
||||
}else if(value instanceof String){
|
||||
return StrUtil.split((String)value, ',');
|
||||
}else{
|
||||
throw new RuntimeException("Value is not a List type!");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得所有请求参数
|
||||
*
|
||||
* @return Map
|
||||
*/
|
||||
public Map<String, Object> getParams() {
|
||||
return params;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否为长连接
|
||||
*/
|
||||
public boolean isKeepAlive() {
|
||||
final String connectionHeader = getHeader(HttpHeaderNames.CONNECTION.toString());
|
||||
// 无论任何版本Connection为close时都关闭连接
|
||||
if (HttpHeaderValues.CLOSE.toString().equalsIgnoreCase(connectionHeader)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// HTTP/1.0只有Connection为Keep-Alive时才会保持连接
|
||||
if (HttpVersion.HTTP_1_0.text().equals(getProtocolVersion())) {
|
||||
if (false == HttpHeaderValues.KEEP_ALIVE.toString().equalsIgnoreCase(connectionHeader)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// HTTP/1.1默认打开Keep-Alive
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Protected method start
|
||||
/**
|
||||
* 填充参数(GET请求的参数)
|
||||
*
|
||||
* @param decoder QueryStringDecoder
|
||||
*/
|
||||
protected void putParams(QueryStringDecoder decoder) {
|
||||
if (null != decoder) {
|
||||
List<String> valueList;
|
||||
for (Entry<String, List<String>> entry : decoder.parameters().entrySet()) {
|
||||
valueList = entry.getValue();
|
||||
if(null != valueList){
|
||||
this.putParam(entry.getKey(), 1 == valueList.size() ? valueList.get(0) : valueList);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充参数(POST请求的参数)
|
||||
*
|
||||
* @param decoder QueryStringDecoder
|
||||
*/
|
||||
protected void putParams(HttpPostRequestDecoder decoder) {
|
||||
if (null == decoder) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (InterfaceHttpData data : decoder.getBodyHttpDatas()) {
|
||||
putParam(data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充参数
|
||||
*
|
||||
* @param data InterfaceHttpData
|
||||
*/
|
||||
protected void putParam(InterfaceHttpData data) {
|
||||
final HttpDataType dataType = data.getHttpDataType();
|
||||
if (dataType == HttpDataType.Attribute) {
|
||||
//普通参数
|
||||
Attribute attribute = (Attribute) data;
|
||||
try {
|
||||
this.putParam(attribute.getName(), attribute.getValue());
|
||||
} catch (IOException e) {
|
||||
Logger.error(e.toString());
|
||||
}
|
||||
}else if(dataType == HttpDataType.FileUpload){
|
||||
//文件
|
||||
FileUpload fileUpload = (FileUpload) data;
|
||||
if(fileUpload.isCompleted()){
|
||||
try {
|
||||
this.putParam(data.getName(), fileUpload.getFile());
|
||||
} catch (IOException e) {
|
||||
Logger.error(e.toString(), "Get file param [{}] error!", data.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充参数
|
||||
*
|
||||
* @param key 参数名
|
||||
* @param value 参数值
|
||||
*/
|
||||
protected void putParam(String key, Object value) {
|
||||
this.params.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 填充头部信息和Cookie信息
|
||||
*
|
||||
* @param headers HttpHeaders
|
||||
*/
|
||||
protected void putHeadersAndCookies(HttpHeaders headers) {
|
||||
for (Entry<String, String> entry : headers) {
|
||||
this.headers.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
|
||||
// Cookie
|
||||
final String cookieString = this.headers.get(HttpHeaderNames.COOKIE);
|
||||
if (StrUtil.isNotBlank(cookieString)) {
|
||||
final Set<Cookie> cookies = ServerCookieDecoder.LAX.decode(cookieString);
|
||||
for (Cookie cookie : cookies) {
|
||||
this.cookies.put(cookie.name(), cookie);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置客户端IP
|
||||
*
|
||||
* @param ctx ChannelHandlerContext
|
||||
*/
|
||||
protected void putIp(ChannelHandlerContext ctx) {
|
||||
String ip = getHeader("X-Forwarded-For");
|
||||
if (StrUtil.isNotBlank(ip)) {
|
||||
ip = HttpUtil.getMultistageReverseProxyIp(ip);
|
||||
} else {
|
||||
final InetSocketAddress insocket = (InetSocketAddress) ctx.channel().remoteAddress();
|
||||
ip = insocket.getAddress().getHostAddress();
|
||||
}
|
||||
this.ip = ip;
|
||||
}
|
||||
// --------------------------------------------------------- Protected method end
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("\r\nprotocolVersion: ").append(getProtocolVersion()).append("\r\n");
|
||||
sb.append("uri: ").append(getUri()).append("\r\n");
|
||||
sb.append("path: ").append(path).append("\r\n");
|
||||
sb.append("method: ").append(getMethod()).append("\r\n");
|
||||
sb.append("ip: ").append(ip).append("\r\n");
|
||||
sb.append("headers:\r\n ");
|
||||
for (Entry<String, String> entry : headers.entrySet()) {
|
||||
sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
|
||||
}
|
||||
sb.append("params: \r\n");
|
||||
for (Entry<String, Object> entry : params.entrySet()) {
|
||||
sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建Request对象
|
||||
*
|
||||
* @param ctx ChannelHandlerContext
|
||||
* @param nettyRequest Netty的HttpRequest
|
||||
* @return Request
|
||||
*/
|
||||
protected final static Request build(ChannelHandlerContext ctx, FullHttpRequest nettyRequest) {
|
||||
return new Request(ctx, nettyRequest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,592 @@
|
||||
package com.xiaoleilu.loServer.handler;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.nio.charset.Charset;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import com.xiaoleilu.hutool.http.HttpUtil;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
import com.xiaoleilu.hutool.util.CharsetUtil;
|
||||
import com.xiaoleilu.hutool.util.DateUtil;
|
||||
import com.xiaoleilu.hutool.util.StrUtil;
|
||||
import com.xiaoleilu.loServer.ServerSetting;
|
||||
import com.xiaoleilu.loServer.listener.FileProgressiveFutureListener;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.ChannelFuture;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.DefaultFileRegion;
|
||||
import io.netty.handler.codec.http.DefaultFullHttpResponse;
|
||||
import io.netty.handler.codec.http.DefaultHttpHeaders;
|
||||
import io.netty.handler.codec.http.DefaultHttpResponse;
|
||||
import io.netty.handler.codec.http.FullHttpResponse;
|
||||
import io.netty.handler.codec.http.HttpHeaderNames;
|
||||
import io.netty.handler.codec.http.HttpHeaderValues;
|
||||
import io.netty.handler.codec.http.HttpHeaders;
|
||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||
import io.netty.handler.codec.http.HttpVersion;
|
||||
import io.netty.handler.codec.http.LastHttpContent;
|
||||
import io.netty.handler.codec.http.cookie.Cookie;
|
||||
import io.netty.handler.codec.http.cookie.DefaultCookie;
|
||||
import io.netty.handler.codec.http.cookie.ServerCookieEncoder;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 响应对象
|
||||
*
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class Response {
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(Response.class);
|
||||
|
||||
/** 返回内容类型:普通文本 */
|
||||
public final static String CONTENT_TYPE_TEXT = "text/plain";
|
||||
/** 返回内容类型:HTML */
|
||||
public final static String CONTENT_TYPE_HTML = "text/html";
|
||||
/** 返回内容类型:XML */
|
||||
public final static String CONTENT_TYPE_XML = "text/xml";
|
||||
/** 返回内容类型:JAVASCRIPT */
|
||||
public final static String CONTENT_TYPE_JAVASCRIPT = "application/javascript";
|
||||
/** 返回内容类型:JSON */
|
||||
public final static String CONTENT_TYPE_JSON = "application/json";
|
||||
public final static String CONTENT_TYPE_JSON_IE = "text/json";
|
||||
|
||||
private ChannelHandlerContext ctx;
|
||||
private Request request;
|
||||
|
||||
private HttpVersion httpVersion = HttpVersion.HTTP_1_1;
|
||||
private HttpResponseStatus status = HttpResponseStatus.OK;
|
||||
private String contentType = CONTENT_TYPE_HTML;
|
||||
private String charset = ServerSetting.getCharset();
|
||||
private HttpHeaders headers = new DefaultHttpHeaders();
|
||||
private Set<Cookie> cookies = new HashSet<Cookie>();
|
||||
private Object content = Unpooled.EMPTY_BUFFER;
|
||||
//发送完成标记
|
||||
private boolean isSent;
|
||||
|
||||
public Response(ChannelHandlerContext ctx, Request request) {
|
||||
this.ctx = ctx;
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应的Http版本号
|
||||
*
|
||||
* @param httpVersion http版本号对象
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setHttpVersion(HttpVersion httpVersion) {
|
||||
this.httpVersion = httpVersion;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应状态码<br>
|
||||
* 使用io.netty.handler.codec.http.HttpResponseStatus对象
|
||||
*
|
||||
* @param status 状态码
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setStatus(HttpResponseStatus status) {
|
||||
this.status = status;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应状态码
|
||||
*
|
||||
* @param status 状态码
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setStatus(int status) {
|
||||
return setStatus(HttpResponseStatus.valueOf(status));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置Content-Type
|
||||
*
|
||||
* @param contentType Content-Type
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContentType(String contentType) {
|
||||
this.contentType = contentType;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置返回内容的字符集编码
|
||||
*
|
||||
* @param charset 编码
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setCharset(String charset) {
|
||||
this.charset = charset;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加响应的Header<br>
|
||||
* 重复的Header将被叠加
|
||||
*
|
||||
* @param name 名
|
||||
* @param value 值,可以是String,Date, int
|
||||
* @return 自己
|
||||
*/
|
||||
public Response addHeader(String name, Object value) {
|
||||
headers.add(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应的Header<br>
|
||||
* 重复的Header将被替换
|
||||
*
|
||||
* @param name 名
|
||||
* @param value 值,可以是String,Date, int
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setHeader(String name, Object value) {
|
||||
headers.set(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应体长度
|
||||
*
|
||||
* @param contentLength 响应体长度
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContentLength(long contentLength) {
|
||||
setHeader(HttpHeaderNames.CONTENT_LENGTH.toString(), contentLength);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置是否长连接
|
||||
*
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setKeepAlive() {
|
||||
setHeader(HttpHeaderNames.CONNECTION.toString(), HttpHeaderValues.KEEP_ALIVE.toString());
|
||||
return this;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Cookie start
|
||||
/**
|
||||
* 设定返回给客户端的Cookie
|
||||
*
|
||||
* @param cookie
|
||||
* @return 自己
|
||||
*/
|
||||
public Response addCookie(Cookie cookie) {
|
||||
cookies.add(cookie);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定返回给客户端的Cookie
|
||||
*
|
||||
* @param name Cookie名
|
||||
* @param value Cookie值
|
||||
* @return 自己
|
||||
*/
|
||||
public Response addCookie(String name, String value) {
|
||||
return addCookie(new DefaultCookie(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定返回给客户端的Cookie
|
||||
*
|
||||
* @param name cookie名
|
||||
* @param value cookie值
|
||||
* @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. n>0 : Cookie存在的秒数.
|
||||
* @param path Cookie的有效路径
|
||||
* @param domain the Cookie可见的域,依据 RFC 2109 标准
|
||||
* @return 自己
|
||||
*/
|
||||
public Response addCookie(String name, String value, int maxAgeInSeconds, String path, String domain) {
|
||||
Cookie cookie = new DefaultCookie(name, value);
|
||||
if (domain != null) {
|
||||
cookie.setDomain(domain);
|
||||
}
|
||||
cookie.setMaxAge(maxAgeInSeconds);
|
||||
cookie.setPath(path);
|
||||
return addCookie(cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设定返回给客户端的Cookie<br>
|
||||
* Path: "/"<br>
|
||||
* No Domain
|
||||
*
|
||||
* @param name cookie名
|
||||
* @param value cookie值
|
||||
* @param maxAgeInSeconds -1: 关闭浏览器清除Cookie. 0: 立即清除Cookie. n>0 : Cookie存在的秒数.
|
||||
* @return 自己
|
||||
*/
|
||||
public Response addCookie(String name, String value, int maxAgeInSeconds) {
|
||||
return addCookie(name, value, maxAgeInSeconds, "/", null);
|
||||
}
|
||||
// --------------------------------------------------------- Cookie end
|
||||
|
||||
/**
|
||||
* 设置响应HTML文本内容
|
||||
*
|
||||
* @param contentText 响应的文本
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContent(String contentText) {
|
||||
this.content = Unpooled.copiedBuffer(contentText, Charset.forName(charset));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应文本内容
|
||||
*
|
||||
* @param contentText 响应的文本
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setTextContent(String contentText) {
|
||||
setContentType(CONTENT_TYPE_TEXT);
|
||||
return setContent(contentText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应JSON文本内容
|
||||
*
|
||||
* @param contentText 响应的JSON文本
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setJsonContent(String contentText) {
|
||||
setContentType(request.isIE() ? CONTENT_TYPE_JSON : CONTENT_TYPE_JSON);
|
||||
return setContent(contentText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应XML文本内容
|
||||
*
|
||||
* @param contentText 响应的XML文本
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setXmlContent(String contentText) {
|
||||
setContentType(CONTENT_TYPE_XML);
|
||||
return setContent(contentText);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应文本内容
|
||||
*
|
||||
* @param contentBytes 响应的字节
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContent(byte[] contentBytes) {
|
||||
return setContent(Unpooled.copiedBuffer(contentBytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应文本内容
|
||||
*
|
||||
* @param byteBuf 响应的字节
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContent(ByteBuf byteBuf) {
|
||||
this.content = byteBuf;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置响应到客户端的文件
|
||||
*
|
||||
* @param file 文件
|
||||
* @return 自己
|
||||
*/
|
||||
public Response setContent(File file) {
|
||||
this.content = file;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Date and Cache headers for the HTTP Response
|
||||
*
|
||||
* @param response HTTP response
|
||||
* @param fileToCache file to extract content type
|
||||
*/
|
||||
/**
|
||||
* 设置日期和过期时间
|
||||
*
|
||||
* @param lastModify 上一次修改时间
|
||||
* @param httpCacheSeconds 缓存时间,单位秒
|
||||
*/
|
||||
public void setDateAndCache(long lastModify, int httpCacheSeconds) {
|
||||
SimpleDateFormat formatter = new SimpleDateFormat(DateUtil.HTTP_DATETIME_PATTERN, Locale.US);
|
||||
formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||
|
||||
// Date header
|
||||
Calendar time = new GregorianCalendar();
|
||||
setHeader(HttpHeaderNames.DATE.toString(), formatter.format(time.getTime()));
|
||||
|
||||
// Add cache headers
|
||||
time.add(Calendar.SECOND, httpCacheSeconds);
|
||||
|
||||
setHeader(HttpHeaderNames.EXPIRES.toString(), formatter.format(time.getTime()));
|
||||
setHeader(HttpHeaderNames.CACHE_CONTROL.toString(), "private, max-age=" + httpCacheSeconds);
|
||||
setHeader(HttpHeaderNames.LAST_MODIFIED.toString(), formatter.format(DateUtil.date(lastModify)));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------------------- build HttpResponse start
|
||||
/**
|
||||
* 转换为Netty所用Response<br>
|
||||
* 不包括content,一般用于返回文件类型的响应
|
||||
*
|
||||
* @return DefaultHttpResponse
|
||||
*/
|
||||
private DefaultHttpResponse toDefaultHttpResponse() {
|
||||
final DefaultHttpResponse defaultHttpResponse = new DefaultHttpResponse(httpVersion, status);
|
||||
|
||||
// headers
|
||||
final HttpHeaders httpHeaders = defaultHttpResponse.headers().add(headers);
|
||||
|
||||
// Cookies
|
||||
for (Cookie cookie : cookies) {
|
||||
httpHeaders.add(HttpHeaderNames.SET_COOKIE.toString(), ServerCookieEncoder.LAX.encode(cookie));
|
||||
}
|
||||
|
||||
return defaultHttpResponse;
|
||||
}
|
||||
|
||||
/**
|
||||
* 转换为Netty所用Response<br>
|
||||
* 用于返回一般类型响应(文本)
|
||||
*
|
||||
* @return FullHttpResponse
|
||||
*/
|
||||
private FullHttpResponse toFullHttpResponse() {
|
||||
final ByteBuf byteBuf = (ByteBuf)content;
|
||||
final FullHttpResponse fullHttpResponse = new DefaultFullHttpResponse(httpVersion, status, byteBuf);
|
||||
|
||||
// headers
|
||||
final HttpHeaders httpHeaders = fullHttpResponse.headers().add(headers);
|
||||
if ("application/octet-stream".equals(contentType)) {
|
||||
httpHeaders.set(HttpHeaderNames.CONTENT_TYPE.toString(), contentType);
|
||||
} else {
|
||||
httpHeaders.set(HttpHeaderNames.CONTENT_TYPE.toString(), StrUtil.format("{};charset={}", contentType, charset));
|
||||
httpHeaders.set(HttpHeaderNames.CONTENT_ENCODING.toString(), charset);
|
||||
}
|
||||
|
||||
httpHeaders.set(HttpHeaderNames.CONTENT_LENGTH.toString(), byteBuf.readableBytes());
|
||||
|
||||
// Cookies
|
||||
for (Cookie cookie : cookies) {
|
||||
httpHeaders.add(HttpHeaderNames.SET_COOKIE.toString(), ServerCookieEncoder.LAX.encode(cookie));
|
||||
}
|
||||
|
||||
return fullHttpResponse;
|
||||
}
|
||||
// -------------------------------------------------------------------------------------- build HttpResponse end
|
||||
|
||||
// -------------------------------------------------------------------------------------- send start
|
||||
/**
|
||||
* 发送响应到客户端<br>
|
||||
*
|
||||
* @return ChannelFuture
|
||||
* @throws IOException
|
||||
*/
|
||||
public ChannelFuture send() {
|
||||
ChannelFuture channelFuture;
|
||||
if(content instanceof File){
|
||||
//文件
|
||||
File file = (File)content;
|
||||
try {
|
||||
channelFuture = sendFile(file);
|
||||
} catch (IOException e) {
|
||||
Logger.error(StrUtil.format("Send {} error!", file), e.toString());
|
||||
channelFuture = sendError(HttpResponseStatus.FORBIDDEN, "");
|
||||
}
|
||||
}else{
|
||||
//普通文本
|
||||
channelFuture = sendFull();
|
||||
}
|
||||
|
||||
this.isSent = true;
|
||||
return channelFuture;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return 是否已经出发发送请求,内部使用<br>
|
||||
*/
|
||||
protected boolean isSent(){
|
||||
return this.isSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送响应到客户端
|
||||
*
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
private ChannelFuture sendFull() {
|
||||
if (request != null && request.isKeepAlive()) {
|
||||
setKeepAlive();
|
||||
return ctx.writeAndFlush(this.toFullHttpResponse());
|
||||
} else {
|
||||
return sendAndCloseFull();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送给到客户端并关闭ChannelHandlerContext
|
||||
*
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
private ChannelFuture sendAndCloseFull() {
|
||||
return ctx.writeAndFlush(this.toFullHttpResponse()).addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送文件
|
||||
*
|
||||
* @param file 文件
|
||||
* @return ChannelFuture
|
||||
* @throws IOException
|
||||
*/
|
||||
private ChannelFuture sendFile(File file) throws IOException {
|
||||
final RandomAccessFile raf = new RandomAccessFile(file, "r");
|
||||
|
||||
// 内容长度
|
||||
long fileLength = raf.length();
|
||||
this.setContentLength(fileLength);
|
||||
|
||||
//文件类型
|
||||
String contentType = HttpUtil.getMimeType(file.getName());
|
||||
if(StrUtil.isBlank(contentType)){
|
||||
//无法识别默认使用数据流
|
||||
contentType = "application/octet-stream";
|
||||
}
|
||||
this.setContentType(contentType);
|
||||
|
||||
ctx.write(this.toDefaultHttpResponse());
|
||||
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise())
|
||||
.addListener(FileProgressiveFutureListener.build(raf));
|
||||
|
||||
return sendEmptyLast();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送结尾标记,表示发送结束
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
private ChannelFuture sendEmptyLast(){
|
||||
final ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
|
||||
if (false == request.isKeepAlive()) {
|
||||
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
|
||||
}
|
||||
|
||||
return lastContentFuture;
|
||||
}
|
||||
// -------------------------------------------------------------------------------------- send end
|
||||
|
||||
// ---------------------------------------------------------------------------- special response start
|
||||
|
||||
/**
|
||||
* 302 重定向
|
||||
*
|
||||
* @param uri 重定向到的URI
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
public ChannelFuture sendRedirect(String uri) {
|
||||
return this.setStatus(HttpResponseStatus.FOUND).setHeader(HttpHeaderNames.LOCATION.toString(), uri).send();
|
||||
}
|
||||
|
||||
/**
|
||||
* 304 文件未修改
|
||||
*
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
public ChannelFuture sendNotModified() {
|
||||
return this.setStatus(HttpResponseStatus.NOT_MODIFIED).setHeader(HttpHeaderNames.DATE.toString(), DateUtil.formatHttpDate(DateUtil.date())).send();
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送错误消息
|
||||
*
|
||||
* @param status 错误状态码
|
||||
* @param msg 消息内容
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
public ChannelFuture sendError(HttpResponseStatus status, String msg) {
|
||||
if (ctx.channel().isActive()) {
|
||||
return this.setStatus(status).setContent(msg).send();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送404 Not Found
|
||||
*
|
||||
* @param msg 消息内容
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
public ChannelFuture sendNotFound(String msg) {
|
||||
return sendError(HttpResponseStatus.NOT_FOUND, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送500 Internal Server Error
|
||||
*
|
||||
* @param msg 消息内容
|
||||
* @return ChannelFuture
|
||||
*/
|
||||
public ChannelFuture sendServerError(String msg) {
|
||||
return sendError(HttpResponseStatus.INTERNAL_SERVER_ERROR, msg);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------- special response end
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
sb.append("headers:\r\n ");
|
||||
for ( Entry<String, String> entry : headers.entries()) {
|
||||
sb.append(" ").append(entry.getKey()).append(": ").append(entry.getValue()).append("\r\n");
|
||||
}
|
||||
sb.append("content: ").append(StrUtil.str(content, CharsetUtil.UTF_8));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------- static method start
|
||||
/**
|
||||
* 构建Response对象
|
||||
*
|
||||
* @param ctx ChannelHandlerContext
|
||||
* @param request 请求对象
|
||||
* @return Response对象
|
||||
*/
|
||||
protected static Response build(ChannelHandlerContext ctx, Request request) {
|
||||
return new Response(ctx, request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建Response对象,Request对象为空,将无法获得某些信息<br>
|
||||
* 1. 无法使用长连接
|
||||
*
|
||||
* @param ctx ChannelHandlerContext
|
||||
* @return Response对象
|
||||
*/
|
||||
protected static Response build(ChannelHandlerContext ctx) {
|
||||
return new Response(ctx, null);
|
||||
}
|
||||
// ---------------------------------------------------------------------------- static method end
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
package com.xiaoleilu.loServer.listener;
|
||||
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
import com.xiaoleilu.hutool.io.IoUtil;
|
||||
import com.xiaoleilu.hutool.log.Log;
|
||||
import com.xiaoleilu.hutool.log.StaticLog;
|
||||
|
||||
import io.netty.channel.ChannelProgressiveFuture;
|
||||
import io.netty.channel.ChannelProgressiveFutureListener;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* 文件进度指示监听
|
||||
* @author Looly
|
||||
*
|
||||
*/
|
||||
public class FileProgressiveFutureListener implements ChannelProgressiveFutureListener{
|
||||
private static final org.slf4j.Logger Logger = LoggerFactory.getLogger(FileProgressiveFutureListener.class);
|
||||
|
||||
private RandomAccessFile raf;
|
||||
|
||||
public FileProgressiveFutureListener(RandomAccessFile raf) {
|
||||
this.raf = raf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
|
||||
Logger.debug("Transfer progress: {} / {}", progress, total);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void operationComplete(ChannelProgressiveFuture future) {
|
||||
IoUtil.close(raf);
|
||||
Logger.debug("Transfer complete.");
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建文件进度指示监听
|
||||
* @param raf RandomAccessFile
|
||||
* @return 文件进度指示监听
|
||||
*/
|
||||
public static FileProgressiveFutureListener build(RandomAccessFile raf){
|
||||
return new FileProgressiveFutureListener(raf);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class FriendData implements Serializable {
|
||||
private String userId;
|
||||
private String friendUid;
|
||||
private int state;
|
||||
private long timestamp;
|
||||
|
||||
|
||||
public FriendData(String userId, String friendUid, int state, long timestamp) {
|
||||
this.userId = userId;
|
||||
this.friendUid = friendUid;
|
||||
this.state = state;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public FriendData() {
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getFriendUid() {
|
||||
return friendUid;
|
||||
}
|
||||
|
||||
public void setFriendUid(String friendUid) {
|
||||
this.friendUid = friendUid;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class Conversation {
|
||||
private int type;
|
||||
private String target;
|
||||
private int line;
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
public void setTarget(String target) {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public void setLine(int line) {
|
||||
this.line = line;
|
||||
}
|
||||
}
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.protobuf.ByteString;
|
||||
import io.moquette.BrokerConstants;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class GroupNotificationBinaryContent {
|
||||
//operator
|
||||
private String o;
|
||||
|
||||
//name
|
||||
private String n;
|
||||
|
||||
//members
|
||||
private List<String> ms;
|
||||
|
||||
//members
|
||||
private String m;
|
||||
|
||||
public GroupNotificationBinaryContent(String o, String n, String m) {
|
||||
this.o = o;
|
||||
this.n = n;
|
||||
this.m = m;
|
||||
}
|
||||
|
||||
public GroupNotificationBinaryContent(String operator, String name, List<String> members) {
|
||||
this.o = operator;
|
||||
this.n = name;
|
||||
this.ms = members;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getO() {
|
||||
return o;
|
||||
}
|
||||
|
||||
public void setO(String o) {
|
||||
this.o = o;
|
||||
}
|
||||
|
||||
public String getN() {
|
||||
return n;
|
||||
}
|
||||
|
||||
public void setN(String n) {
|
||||
this.n = n;
|
||||
}
|
||||
|
||||
public List<String> getMs() {
|
||||
return ms;
|
||||
}
|
||||
|
||||
public void setMs(List<String> ms) {
|
||||
this.ms = ms;
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getGroupNotifyContent(int groupContentType) {
|
||||
return WFCMessage.MessageContent.newBuilder().setType(groupContentType).setData(ByteString.copyFromUtf8(new Gson().toJson(this))).build();
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getAddGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_ADD_GROUP_MEMBER);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getCreateGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_CREATE_GROUP);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getDismissGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_DISMISS_GROUP);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getKickokfMemberGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_KICKOF_GROUP_MEMBER);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getQuitGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_QUIT_GROUP);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getTransferGroupNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_TRANSFER_GROUP_OWNER);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getChangeGroupNameNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_CHANGE_GROUP_NAME);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getChangeGroupPortraitNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_CHANGE_GROUP_PORTRAIT);
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent getModifyGroupMemberAliasNotifyContent() {
|
||||
return getGroupNotifyContent(BrokerConstants.MESSAGE_CONTENT_TYPE_MODIFY_GROUP_ALIAS);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputAddGroupMember extends InputGroupBase {
|
||||
private String group_id;
|
||||
private List<PojoGroupMember> members;
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
}
|
||||
|
||||
public void setGroup_id(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
|
||||
public List<PojoGroupMember> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public void setMembers(List<PojoGroupMember> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.AddGroupMemberRequest toProtoGroupRequest() {
|
||||
WFCMessage.AddGroupMemberRequest.Builder addGroupBuilder = WFCMessage.AddGroupMemberRequest.newBuilder();
|
||||
addGroupBuilder.setGroupId(group_id);
|
||||
for (PojoGroupMember pojoGroupMember : getMembers()) {
|
||||
WFCMessage.GroupMember.Builder groupMemberBuilder = WFCMessage.GroupMember.newBuilder().setMemberId(pojoGroupMember.getMember_id());
|
||||
if (!StringUtil.isNullOrEmpty(pojoGroupMember.getAlias())) {
|
||||
groupMemberBuilder.setAlias(pojoGroupMember.getAlias());
|
||||
}
|
||||
groupMemberBuilder.setType(pojoGroupMember.getType());
|
||||
addGroupBuilder.addAddedMember(groupMemberBuilder);
|
||||
}
|
||||
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
addGroupBuilder.addToLine(line);
|
||||
}
|
||||
|
||||
addGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());
|
||||
return addGroupBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class InputCreateChatroom {
|
||||
private String chatroomId;
|
||||
private String title;
|
||||
private String desc;
|
||||
private String portrait;
|
||||
private String extra;
|
||||
private Integer state;
|
||||
|
||||
public WFCMessage.ChatroomInfo toChatroomInfo() {
|
||||
WFCMessage.ChatroomInfo.Builder builder = WFCMessage.ChatroomInfo.newBuilder().setTitle(title);
|
||||
if (!StringUtil.isNullOrEmpty(desc)) {
|
||||
builder.setDesc(desc);
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(portrait)) {
|
||||
builder.setPortrait(portrait);
|
||||
}
|
||||
|
||||
long current = System.currentTimeMillis();
|
||||
builder.setCreateDt(current).setUpdateDt(current).setMemberCount(0);
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(extra)) {
|
||||
builder.setExtra(extra);
|
||||
}
|
||||
|
||||
if (state == null || state == 0) {
|
||||
builder.setState(ProtoConstants.ChatroomState.Chatroom_State_Normal);
|
||||
} else if(state == 1) {
|
||||
builder.setState(ProtoConstants.ChatroomState.Chatroom_State_NotStart);
|
||||
} else {
|
||||
builder.setState(ProtoConstants.ChatroomState.Chatroom_State_End);
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
public InputCreateChatroom() {
|
||||
}
|
||||
|
||||
public Integer getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(Integer state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public String getChatroomId() {
|
||||
return chatroomId;
|
||||
}
|
||||
|
||||
public void setChatroomId(String chatroomId) {
|
||||
this.chatroomId = chatroomId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputCreateGroup extends InputGroupBase {
|
||||
private PojoGroup group;
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.CreateGroupRequest toProtoGroupRequest() {
|
||||
WFCMessage.Group.Builder groupBuilder = WFCMessage.Group.newBuilder();
|
||||
WFCMessage.GroupInfo.Builder groupInfoBuilder = WFCMessage.GroupInfo.newBuilder();
|
||||
if (!StringUtil.isNullOrEmpty(group.getGroup_info().target_id)) {
|
||||
groupInfoBuilder.setTargetId(group.getGroup_info().getTarget_id());
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(group.getGroup_info().name)) {
|
||||
groupInfoBuilder.setName(group.getGroup_info().getName());
|
||||
}
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(group.getGroup_info().portrait)) {
|
||||
groupInfoBuilder.setPortrait(group.getGroup_info().getPortrait());
|
||||
}
|
||||
if (!StringUtil.isNullOrEmpty(group.getGroup_info().owner)) {
|
||||
groupInfoBuilder.setOwner(group.getGroup_info().getOwner());
|
||||
}
|
||||
|
||||
groupInfoBuilder.setType(group.getGroup_info().getType());
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(group.getGroup_info().extra)) {
|
||||
groupInfoBuilder.setExtra(group.getGroup_info().getExtra());
|
||||
}
|
||||
|
||||
|
||||
groupBuilder.setGroupInfo(groupInfoBuilder);
|
||||
for (PojoGroupMember pojoGroupMember : group.getMembers()) {
|
||||
WFCMessage.GroupMember.Builder groupMemberBuilder = WFCMessage.GroupMember.newBuilder().setMemberId(pojoGroupMember.getMember_id());
|
||||
if (!StringUtil.isNullOrEmpty(pojoGroupMember.getAlias())) {
|
||||
groupMemberBuilder.setAlias(pojoGroupMember.getAlias());
|
||||
}
|
||||
groupMemberBuilder.setType(pojoGroupMember.getType());
|
||||
groupBuilder.addMembers(groupMemberBuilder);
|
||||
}
|
||||
|
||||
WFCMessage.CreateGroupRequest.Builder createGroupReqBuilder = WFCMessage.CreateGroupRequest.newBuilder();
|
||||
createGroupReqBuilder.setGroup(groupBuilder);
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
createGroupReqBuilder.addToLine(line);
|
||||
}
|
||||
|
||||
createGroupReqBuilder.setNotifyContent(notify_message.toProtoMessageContent());
|
||||
return createGroupReqBuilder.build();
|
||||
}
|
||||
|
||||
public PojoGroup getGroup() {
|
||||
return group;
|
||||
}
|
||||
|
||||
public void setGroup(PojoGroup group) {
|
||||
this.group = group;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class InputCreateRobot {
|
||||
private String userId;
|
||||
private String name;
|
||||
private String password;
|
||||
private String displayName;
|
||||
private String portrait;
|
||||
private int gender;
|
||||
private String mobile;
|
||||
private String email;
|
||||
private String address;
|
||||
private String company;
|
||||
private String social;
|
||||
private String extra;
|
||||
private long updateDt;
|
||||
|
||||
|
||||
private String owner;
|
||||
private String secret;
|
||||
private String callback;
|
||||
private String robotExtra;
|
||||
|
||||
public String getSocial() {
|
||||
return social;
|
||||
}
|
||||
|
||||
public void setSocial(String social) {
|
||||
this.social = social;
|
||||
}
|
||||
|
||||
public WFCMessage.Robot toRobot() {
|
||||
WFCMessage.Robot.Builder builder = WFCMessage.Robot.newBuilder();
|
||||
if (!StringUtil.isNullOrEmpty(userId))
|
||||
builder.setUid(userId);
|
||||
if (!StringUtil.isNullOrEmpty(owner))
|
||||
builder.setOwner(owner);
|
||||
if (!StringUtil.isNullOrEmpty(secret))
|
||||
builder.setSecret(secret);
|
||||
if (!StringUtil.isNullOrEmpty(callback))
|
||||
builder.setCallback(callback);
|
||||
if (!StringUtil.isNullOrEmpty(robotExtra))
|
||||
builder.setExtra(robotExtra);
|
||||
builder.setState(0);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public WFCMessage.User toUser() {
|
||||
WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()
|
||||
.setUid(userId);
|
||||
if (name != null)
|
||||
newUserBuilder.setName(name);
|
||||
if (displayName != null)
|
||||
newUserBuilder.setDisplayName(displayName);
|
||||
if (getPortrait() != null)
|
||||
newUserBuilder.setPortrait(getPortrait());
|
||||
if (getEmail() != null)
|
||||
newUserBuilder.setEmail(getEmail());
|
||||
if (getAddress() != null)
|
||||
newUserBuilder.setAddress(getAddress());
|
||||
if (getCompany() != null)
|
||||
newUserBuilder.setCompany(getCompany());
|
||||
if (getSocial() != null)
|
||||
newUserBuilder.setSocial(getSocial());
|
||||
|
||||
if (getMobile() != null)
|
||||
newUserBuilder.setMobile(getMobile());
|
||||
if (getExtra() != null)
|
||||
newUserBuilder.setExtra(getExtra());
|
||||
newUserBuilder.setType(ProtoConstants.UserType.UserType_Robot);
|
||||
newUserBuilder.setGender(gender);
|
||||
|
||||
newUserBuilder.setUpdateDt(System.currentTimeMillis());
|
||||
return newUserBuilder.build();
|
||||
}
|
||||
|
||||
public long getUpdateDt() {
|
||||
return updateDt;
|
||||
}
|
||||
|
||||
public void setUpdateDt(long updateDt) {
|
||||
this.updateDt = updateDt;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
public int getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(int gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public String getCallback() {
|
||||
return callback;
|
||||
}
|
||||
|
||||
public void setCallback(String callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public String getRobotExtra() {
|
||||
return robotExtra;
|
||||
}
|
||||
|
||||
public void setRobotExtra(String robotExtra) {
|
||||
this.robotExtra = robotExtra;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
|
||||
public class InputCreateUser {
|
||||
private String userId;
|
||||
private String name;
|
||||
private String password;
|
||||
private String displayName;
|
||||
private String portrait;
|
||||
private int gender;
|
||||
private String mobile;
|
||||
private String email;
|
||||
private String address;
|
||||
private String company;
|
||||
private String social;
|
||||
private String extra;
|
||||
private long updateDt;
|
||||
|
||||
public static InputCreateUser fromPbUser(WFCMessage.User pbUser) {
|
||||
InputCreateUser inputCreateUser = new InputCreateUser();
|
||||
inputCreateUser.userId = pbUser.getUid();
|
||||
inputCreateUser.name = pbUser.getName();
|
||||
inputCreateUser.displayName = pbUser.getDisplayName();
|
||||
inputCreateUser.portrait = pbUser.getPortrait();
|
||||
inputCreateUser.gender = pbUser.getGender();
|
||||
inputCreateUser.mobile = pbUser.getMobile();
|
||||
inputCreateUser.email = pbUser.getEmail();
|
||||
inputCreateUser.address = pbUser.getAddress();
|
||||
inputCreateUser.company = pbUser.getCompany();
|
||||
inputCreateUser.social = pbUser.getSocial();
|
||||
inputCreateUser.extra = pbUser.getExtra();
|
||||
inputCreateUser.updateDt = pbUser.getUpdateDt();
|
||||
return inputCreateUser;
|
||||
}
|
||||
|
||||
public String getSocial() {
|
||||
return social;
|
||||
}
|
||||
|
||||
public void setSocial(String social) {
|
||||
this.social = social;
|
||||
}
|
||||
|
||||
public WFCMessage.User toUser() {
|
||||
WFCMessage.User.Builder newUserBuilder = WFCMessage.User.newBuilder()
|
||||
.setUid(userId);
|
||||
if (name != null)
|
||||
newUserBuilder.setName(name);
|
||||
if (displayName != null)
|
||||
newUserBuilder.setDisplayName(displayName);
|
||||
if (getPortrait() != null)
|
||||
newUserBuilder.setPortrait(getPortrait());
|
||||
if (getEmail() != null)
|
||||
newUserBuilder.setEmail(getEmail());
|
||||
if (getAddress() != null)
|
||||
newUserBuilder.setAddress(getAddress());
|
||||
if (getCompany() != null)
|
||||
newUserBuilder.setCompany(getCompany());
|
||||
if (getSocial() != null)
|
||||
newUserBuilder.setSocial(getSocial());
|
||||
|
||||
if (getMobile() != null)
|
||||
newUserBuilder.setMobile(getMobile());
|
||||
if (getExtra() != null)
|
||||
newUserBuilder.setExtra(getExtra());
|
||||
newUserBuilder.setGender(gender);
|
||||
|
||||
newUserBuilder.setUpdateDt(System.currentTimeMillis());
|
||||
return newUserBuilder.build();
|
||||
}
|
||||
|
||||
public long getUpdateDt() {
|
||||
return updateDt;
|
||||
}
|
||||
|
||||
public void setUpdateDt(long updateDt) {
|
||||
this.updateDt = updateDt;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public void setDisplayName(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getCompany() {
|
||||
return company;
|
||||
}
|
||||
|
||||
public void setCompany(String company) {
|
||||
this.company = company;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
|
||||
public int getGender() {
|
||||
return gender;
|
||||
}
|
||||
|
||||
public void setGender(int gender) {
|
||||
this.gender = gender;
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
public class InputDestoryChatroom {
|
||||
private String chatroomId;
|
||||
|
||||
public InputDestoryChatroom() {
|
||||
}
|
||||
|
||||
public String getChatroomId() {
|
||||
return chatroomId;
|
||||
}
|
||||
|
||||
public void setChatroomId(String chatroomId) {
|
||||
this.chatroomId = chatroomId;
|
||||
}
|
||||
}
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputDismissGroupMember extends InputGroupBase {
|
||||
private String group_id;
|
||||
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
}
|
||||
|
||||
public void setGroup_id(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.DismissGroupRequest toProtoGroupRequest() {
|
||||
WFCMessage.DismissGroupRequest.Builder dismissGroupBuilder = WFCMessage.DismissGroupRequest.newBuilder();
|
||||
dismissGroupBuilder.setGroupId(group_id);
|
||||
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
dismissGroupBuilder.addToLine(line);
|
||||
}
|
||||
|
||||
dismissGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());
|
||||
return dismissGroupBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class InputGetUserInfo {
|
||||
private String userId;
|
||||
private String name;
|
||||
private String mobile;
|
||||
|
||||
public InputGetUserInfo(String userId, String name) {
|
||||
this.userId = userId;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputGroupBase {
|
||||
public String operator;
|
||||
public List<Integer> to_lines;
|
||||
public MessagePayload notify_message;
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public List<Integer> getTo_lines() {
|
||||
return to_lines;
|
||||
}
|
||||
|
||||
public void setTo_lines(List<Integer> to_lines) {
|
||||
this.to_lines = to_lines;
|
||||
}
|
||||
|
||||
public MessagePayload getNotify_message() {
|
||||
return notify_message;
|
||||
}
|
||||
|
||||
public void setNotify_message(MessagePayload notify_message) {
|
||||
this.notify_message = notify_message;
|
||||
}
|
||||
}
|
||||
+55
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputKickoffGroupMember extends InputGroupBase {
|
||||
private String group_id;
|
||||
private List<String> members;
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
}
|
||||
|
||||
public void setGroup_id(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
|
||||
public List<String> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public void setMembers(List<String> members) {
|
||||
this.members = members;
|
||||
}
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.RemoveGroupMemberRequest toProtoGroupRequest() {
|
||||
WFCMessage.RemoveGroupMemberRequest.Builder removedGroupBuilder = WFCMessage.RemoveGroupMemberRequest.newBuilder();
|
||||
removedGroupBuilder.setGroupId(group_id);
|
||||
removedGroupBuilder.addAllRemovedMember(members);
|
||||
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
removedGroupBuilder.addToLine(line);
|
||||
}
|
||||
|
||||
removedGroupBuilder.setNotifyContent(notify_message.toProtoMessageContent());
|
||||
return removedGroupBuilder.build();
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class InputOutputSensitiveWords {
|
||||
private List<String> words;
|
||||
|
||||
public List<String> getWords() {
|
||||
return words;
|
||||
}
|
||||
|
||||
public void setWords(List<String> words) {
|
||||
this.words = words;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
public class InputOutputUserBlockStatus {
|
||||
private String userId;
|
||||
private int status;
|
||||
|
||||
public InputOutputUserBlockStatus(String userId, int status) {
|
||||
this.userId = userId;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class InputTransferGroup extends InputGroupBase {
|
||||
private String group_id;
|
||||
private String new_owner;
|
||||
|
||||
|
||||
public boolean isValide() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.TransferGroupRequest toProtoGroupRequest() {
|
||||
WFCMessage.TransferGroupRequest.Builder groupBuilder = WFCMessage.TransferGroupRequest.newBuilder();
|
||||
|
||||
groupBuilder.setGroupId(group_id);
|
||||
groupBuilder.setNewOwner(new_owner);
|
||||
for (Integer line : to_lines
|
||||
) {
|
||||
groupBuilder.addToLine(line);
|
||||
}
|
||||
|
||||
groupBuilder.setNotifyContent(notify_message.toProtoMessageContent());
|
||||
return groupBuilder.build();
|
||||
}
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
}
|
||||
|
||||
public void setGroup_id(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
|
||||
public String getNew_owner() {
|
||||
return new_owner;
|
||||
}
|
||||
|
||||
public void setNew_owner(String new_owner) {
|
||||
this.new_owner = new_owner;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
public class InputUserLogin {
|
||||
private String name;
|
||||
private String password;
|
||||
private String clientId;
|
||||
|
||||
public String getClientId() {
|
||||
return clientId;
|
||||
}
|
||||
|
||||
public void setClientId(String clientId) {
|
||||
this.clientId = clientId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.hazelcast.util.StringUtil;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Base64;
|
||||
import java.util.List;
|
||||
|
||||
public class MessagePayload {
|
||||
private int type;
|
||||
private String searchableContent;
|
||||
private String pushContent;
|
||||
private String content;
|
||||
private String base64edData;
|
||||
private int mediaType;
|
||||
private String remoteMediaUrl;
|
||||
private int persistFlag;
|
||||
private int expireDuration;
|
||||
private int mentionedType;
|
||||
private List<String> mentionedTarget;
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getSearchableContent() {
|
||||
return searchableContent;
|
||||
}
|
||||
|
||||
public void setSearchableContent(String searchableContent) {
|
||||
this.searchableContent = searchableContent;
|
||||
}
|
||||
|
||||
public String getPushContent() {
|
||||
return pushContent;
|
||||
}
|
||||
|
||||
public void setPushContent(String pushContent) {
|
||||
this.pushContent = pushContent;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public String getBase64edData() {
|
||||
return base64edData;
|
||||
}
|
||||
|
||||
public void setBase64edData(String base64edData) {
|
||||
this.base64edData = base64edData;
|
||||
}
|
||||
|
||||
public int getMediaType() {
|
||||
return mediaType;
|
||||
}
|
||||
|
||||
public void setMediaType(int mediaType) {
|
||||
this.mediaType = mediaType;
|
||||
}
|
||||
|
||||
public String getRemoteMediaUrl() {
|
||||
return remoteMediaUrl;
|
||||
}
|
||||
|
||||
public void setRemoteMediaUrl(String remoteMediaUrl) {
|
||||
this.remoteMediaUrl = remoteMediaUrl;
|
||||
}
|
||||
|
||||
public int getPersistFlag() {
|
||||
return persistFlag;
|
||||
}
|
||||
|
||||
public void setPersistFlag(int persistFlag) {
|
||||
this.persistFlag = persistFlag;
|
||||
}
|
||||
|
||||
public int getExpireDuration() {
|
||||
return expireDuration;
|
||||
}
|
||||
|
||||
public void setExpireDuration(int expireDuration) {
|
||||
this.expireDuration = expireDuration;
|
||||
}
|
||||
|
||||
public int getMentionedType() {
|
||||
return mentionedType;
|
||||
}
|
||||
|
||||
public void setMentionedType(int mentionedType) {
|
||||
this.mentionedType = mentionedType;
|
||||
}
|
||||
|
||||
public List<String> getMentionedTarget() {
|
||||
return mentionedTarget;
|
||||
}
|
||||
|
||||
public void setMentionedTarget(List<String> mentionedTarget) {
|
||||
this.mentionedTarget = mentionedTarget;
|
||||
}
|
||||
|
||||
public WFCMessage.MessageContent toProtoMessageContent() {
|
||||
WFCMessage.MessageContent.Builder builder = WFCMessage.MessageContent.newBuilder()
|
||||
.setType(type)
|
||||
.setMediaType(mediaType)
|
||||
.setPersistFlag(persistFlag)
|
||||
.setExpireDuration(expireDuration)
|
||||
.setMentionedType(mentionedType);
|
||||
|
||||
if (!StringUtil.isNullOrEmpty(searchableContent))
|
||||
builder.setSearchableContent(searchableContent);
|
||||
if (!StringUtil.isNullOrEmpty(pushContent))
|
||||
builder.setPushContent(pushContent);
|
||||
if (!StringUtil.isNullOrEmpty(searchableContent))
|
||||
builder.setContent(searchableContent);
|
||||
if (!StringUtil.isNullOrEmpty(base64edData))
|
||||
builder.setData(ByteString.copyFrom(Base64.getDecoder().decode(base64edData)));
|
||||
if (!StringUtil.isNullOrEmpty(remoteMediaUrl))
|
||||
builder.setRemoteMediaUrl(remoteMediaUrl);
|
||||
if (mentionedTarget != null && mentionedTarget.size() > 0)
|
||||
builder.addAllMentionedTarget(mentionedTarget);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
public static MessagePayload fromProtoMessageContent(WFCMessage.MessageContent protoContent) {
|
||||
if (protoContent == null)
|
||||
return null;
|
||||
|
||||
MessagePayload payload = new MessagePayload();
|
||||
payload.type = protoContent.getType();
|
||||
payload.searchableContent = protoContent.getSearchableContent();
|
||||
payload.pushContent = protoContent.getPushContent();
|
||||
payload.content = protoContent.getContent();
|
||||
if (protoContent.getData() != null && protoContent.getData().size() > 0)
|
||||
payload.base64edData = Base64.getEncoder().encodeToString(protoContent.getData().toByteArray());
|
||||
payload.mediaType = protoContent.getMediaType();
|
||||
payload.remoteMediaUrl = protoContent.getRemoteMediaUrl();
|
||||
payload.persistFlag = protoContent.getPersistFlag();
|
||||
payload.expireDuration = protoContent.getExpireDuration();
|
||||
payload.mentionedType = protoContent.getMentionedType();
|
||||
payload.mentionedTarget = new ArrayList<>();
|
||||
payload.mentionedTarget.addAll(protoContent.getMentionedTargetList());
|
||||
return payload;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class OutputCheckUserOnline {
|
||||
private int status; //0 online, 1 have session offline, 2 no session
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
public class OutputCreateChatroom {
|
||||
private String chatroomId;
|
||||
|
||||
public OutputCreateChatroom() {
|
||||
}
|
||||
|
||||
public OutputCreateChatroom(String chatroomId) {
|
||||
this.chatroomId = chatroomId;
|
||||
}
|
||||
|
||||
public String getChatroomId() {
|
||||
return chatroomId;
|
||||
}
|
||||
|
||||
public void setChatroomId(String chatroomId) {
|
||||
this.chatroomId = chatroomId;
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OutputCreateGroupResult {
|
||||
private String group_id;
|
||||
|
||||
public OutputCreateGroupResult(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
|
||||
public String getGroup_id() {
|
||||
return group_id;
|
||||
}
|
||||
|
||||
public void setGroup_id(String group_id) {
|
||||
this.group_id = group_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class OutputCreateRobot {
|
||||
private String userId;
|
||||
private String secret;
|
||||
|
||||
public OutputCreateRobot(String userId, String secret) {
|
||||
this.userId = userId;
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class OutputCreateUser {
|
||||
private String userId;
|
||||
private String name;
|
||||
|
||||
public OutputCreateUser(String userId, String name) {
|
||||
this.userId = userId;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class OutputGetChatroomInfo {
|
||||
private String chatroomId;
|
||||
private String title;
|
||||
private String desc;
|
||||
private String portrait;
|
||||
private String extra;
|
||||
private int memberCount;
|
||||
private long createDt;
|
||||
private long updateDt;
|
||||
|
||||
public OutputGetChatroomInfo(String chatroomId, int memberCount, WFCMessage.ChatroomInfo chatroomInfo) {
|
||||
this.chatroomId = chatroomId;
|
||||
this.title = chatroomInfo.getTitle();
|
||||
this.desc = chatroomInfo.getDesc();
|
||||
this.portrait = chatroomInfo.getPortrait();
|
||||
this.memberCount = memberCount;
|
||||
this.createDt = chatroomInfo.getCreateDt();
|
||||
this.updateDt = chatroomInfo.getUpdateDt();
|
||||
}
|
||||
|
||||
public OutputGetChatroomInfo() {
|
||||
}
|
||||
|
||||
public int getMemberCount() {
|
||||
return memberCount;
|
||||
}
|
||||
|
||||
public void setMemberCount(int memberCount) {
|
||||
this.memberCount = memberCount;
|
||||
}
|
||||
|
||||
public long getCreateDt() {
|
||||
return createDt;
|
||||
}
|
||||
|
||||
public void setCreateDt(long createDt) {
|
||||
this.createDt = createDt;
|
||||
}
|
||||
|
||||
public long getUpdateDt() {
|
||||
return updateDt;
|
||||
}
|
||||
|
||||
public void setUpdateDt(long updateDt) {
|
||||
this.updateDt = updateDt;
|
||||
}
|
||||
|
||||
public String getChatroomId() {
|
||||
return chatroomId;
|
||||
}
|
||||
|
||||
public void setChatroomId(String chatroomId) {
|
||||
this.chatroomId = chatroomId;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getDesc() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public void setDesc(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OutputLoginData {
|
||||
private String userId;
|
||||
private String token;
|
||||
|
||||
public OutputLoginData(String userId, String token) {
|
||||
this.userId = userId;
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
}
|
||||
Executable
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class OutputNotifyChannelSubscribeStatus {
|
||||
private String userId;
|
||||
private String channelId;
|
||||
private int status;
|
||||
|
||||
public OutputNotifyChannelSubscribeStatus(String userId, String channelId, boolean subscirbed) {
|
||||
this.userId = userId;
|
||||
this.channelId = channelId;
|
||||
this.status = subscirbed ? 1 : 0;
|
||||
}
|
||||
|
||||
public String getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
public void setUserId(String userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
public String getChannelId() {
|
||||
return channelId;
|
||||
}
|
||||
|
||||
public void setChannelId(String channelId) {
|
||||
this.channelId = channelId;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class OutputRouteData { ;
|
||||
private List<String> serverIPs;
|
||||
private int longPort;
|
||||
private int shortPort;
|
||||
private String secret;
|
||||
|
||||
public OutputRouteData(List<String> serverIPs, int longPort, int shortPort, String secret) {
|
||||
this.serverIPs = serverIPs;
|
||||
this.longPort = longPort;
|
||||
this.shortPort = shortPort;
|
||||
this.secret = secret;
|
||||
}
|
||||
|
||||
public int getLongPort() {
|
||||
return longPort;
|
||||
}
|
||||
|
||||
public void setLongPort(int longPort) {
|
||||
this.longPort = longPort;
|
||||
}
|
||||
|
||||
public int getShortPort() {
|
||||
return shortPort;
|
||||
}
|
||||
|
||||
public void setShortPort(int shortPort) {
|
||||
this.shortPort = shortPort;
|
||||
}
|
||||
|
||||
public List<String> getServerIPs() {
|
||||
return serverIPs;
|
||||
}
|
||||
|
||||
public void setServerIPs(List<String> serverIPs) {
|
||||
this.serverIPs = serverIPs;
|
||||
}
|
||||
|
||||
public String getSecret() {
|
||||
return secret;
|
||||
}
|
||||
|
||||
public void setSecret(String secret) {
|
||||
this.secret = secret;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class OutputUserStatus {
|
||||
private int status;
|
||||
|
||||
public OutputUserStatus() {
|
||||
}
|
||||
|
||||
public OutputUserStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public int getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(int status) {
|
||||
this.status = status;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PojoGroup {
|
||||
private PojoGroupInfo group_info;
|
||||
private List<PojoGroupMember> members;
|
||||
|
||||
public PojoGroupInfo getGroup_info() {
|
||||
return group_info;
|
||||
}
|
||||
|
||||
public void setGroup_info(PojoGroupInfo group_info) {
|
||||
this.group_info = group_info;
|
||||
}
|
||||
|
||||
public List<PojoGroupMember> getMembers() {
|
||||
return members;
|
||||
}
|
||||
|
||||
public void setMembers(List<PojoGroupMember> members) {
|
||||
this.members = members;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class PojoGroupInfo {
|
||||
String target_id;
|
||||
String name;
|
||||
String portrait;
|
||||
String owner;
|
||||
int type;
|
||||
String extra;
|
||||
|
||||
public String getTarget_id() {
|
||||
return target_id;
|
||||
}
|
||||
|
||||
public void setTarget_id(String target_id) {
|
||||
this.target_id = target_id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getPortrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
public void setPortrait(String portrait) {
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getExtra() {
|
||||
return extra;
|
||||
}
|
||||
|
||||
public void setExtra(String extra) {
|
||||
this.extra = extra;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
public class PojoGroupMember {
|
||||
String member_id;
|
||||
String alias;
|
||||
int type;
|
||||
|
||||
public String getMember_id() {
|
||||
return member_id;
|
||||
}
|
||||
|
||||
public void setMember_id(String member_id) {
|
||||
this.member_id = member_id;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class RecallMessageData {
|
||||
private String operator;
|
||||
private long messageUid;
|
||||
|
||||
public String getOperator() {
|
||||
return operator;
|
||||
}
|
||||
|
||||
public void setOperator(String operator) {
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
public long getMessageUid() {
|
||||
return messageUid;
|
||||
}
|
||||
|
||||
public void setMessageUid(long messageUid) {
|
||||
this.messageUid = messageUid;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import cn.wildfirechat.proto.ProtoConstants;
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class SendMessageData {
|
||||
private String sender;
|
||||
private Conversation conv;
|
||||
private MessagePayload payload;
|
||||
|
||||
public String getSender() {
|
||||
return sender;
|
||||
}
|
||||
|
||||
public void setSender(String sender) {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public Conversation getConv() {
|
||||
return conv;
|
||||
}
|
||||
|
||||
public void setConv(Conversation conv) {
|
||||
this.conv = conv;
|
||||
}
|
||||
|
||||
public MessagePayload getPayload() {
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(MessagePayload payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public static boolean isValide(SendMessageData sendMessageData) {
|
||||
if(sendMessageData == null ||
|
||||
sendMessageData.getConv() == null ||
|
||||
sendMessageData.getConv().getType() < 0 ||
|
||||
sendMessageData.getConv().getType() > 6 ||
|
||||
StringUtil.isNullOrEmpty(sendMessageData.getConv().getTarget()) ||
|
||||
StringUtil.isNullOrEmpty(sendMessageData.getSender()) ||
|
||||
sendMessageData.getPayload() == null) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public WFCMessage.Message toProtoMessage() {
|
||||
return WFCMessage.Message.newBuilder().setFromUser(sender)
|
||||
.setConversation(WFCMessage.Conversation.newBuilder().setType(conv.getType()).setTarget(conv.getTarget()).setLine(conv.getLine()))
|
||||
.setContent(payload.toProtoMessageContent())
|
||||
.build();
|
||||
}
|
||||
|
||||
public static SendMessageData fromProtoMessage(WFCMessage.Message protoMessage) {
|
||||
SendMessageData data = new SendMessageData();
|
||||
data.sender = protoMessage.getFromUser();
|
||||
data.conv = new Conversation();
|
||||
data.conv.setTarget(protoMessage.getConversation().getTarget());
|
||||
data.conv.setType(protoMessage.getConversation().getType());
|
||||
data.conv.setLine(protoMessage.getConversation().getLine());
|
||||
data.payload = MessagePayload.fromProtoMessageContent(protoMessage.getContent());
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package com.xiaoleilu.loServer.pojos;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
import io.netty.util.internal.StringUtil;
|
||||
|
||||
public class SendMessageResult {
|
||||
private long messageUid;
|
||||
private long timestamp;
|
||||
|
||||
public SendMessageResult() {
|
||||
}
|
||||
|
||||
public SendMessageResult(long messageUid, long timestamp) {
|
||||
this.messageUid = messageUid;
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
|
||||
public long getMessageUid() {
|
||||
return messageUid;
|
||||
}
|
||||
|
||||
public void setMessageUid(long messageUid) {
|
||||
this.messageUid = messageUid;
|
||||
}
|
||||
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
public void setTimestamp(long timestamp) {
|
||||
this.timestamp = timestamp;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user