wildfire chat server source initial submit

This commit is contained in:
heavyrain2012
2019-03-16 17:04:23 +08:00
parent e59217bd10
commit cab3ca0916
1466 changed files with 528862 additions and 15919 deletions
@@ -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
View File
@@ -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();
}
}
@@ -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));
}
}
}
}
@@ -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);
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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);
};
}
});
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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));
}
}
}
}
@@ -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;
}
}
@@ -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));
}
}
}
}
@@ -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;
}
}
@@ -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";
}
@@ -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();
}
@@ -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
}
@@ -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;
}
}
@@ -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);
}
}
}
@@ -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 + ")");
}
}
@@ -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);
}
}
}
@@ -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
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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();
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}
@@ -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;
}
}