wildfire chat server source initial submit
This commit is contained in:
+253
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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 win.liyufan.im;
|
||||
|
||||
|
||||
import java.beans.PropertyVetoException;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.FileReader;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.hazelcast.util.StringUtil;
|
||||
import com.mchange.v2.c3p0.ComboPooledDataSource;
|
||||
import io.moquette.BrokerConstants;
|
||||
import io.moquette.server.config.IConfig;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.Connection;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class DBUtil {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(DBUtil.class);
|
||||
private static ComboPooledDataSource comboPooledDataSource = null;
|
||||
private static ConcurrentHashMap<Long, String>map = new ConcurrentHashMap<>();
|
||||
private static ThreadLocal<Connection> transactionConnection = new ThreadLocal<Connection>() {
|
||||
@Override
|
||||
protected Connection initialValue() {
|
||||
super.initialValue();
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public static boolean IsEmbedDB = false;
|
||||
|
||||
public static void init(IConfig config) {
|
||||
String embedDB = config.getProperty(BrokerConstants.EMBED_DB_PROPERTY_NAME);
|
||||
if (embedDB != null && embedDB.equals("1")) {
|
||||
IsEmbedDB = true;
|
||||
LOG.info("Use h2 database");
|
||||
} else {
|
||||
IsEmbedDB = false;
|
||||
LOG.info("Use mysql database");
|
||||
}
|
||||
|
||||
|
||||
if (comboPooledDataSource == null) {
|
||||
if (IsEmbedDB) {
|
||||
comboPooledDataSource = new ComboPooledDataSource();
|
||||
|
||||
comboPooledDataSource.setJdbcUrl( "jdbc:h2:./h2db/wfchat;AUTO_SERVER=TRUE;MODE=MySQL" );
|
||||
comboPooledDataSource.setUser("SA");
|
||||
comboPooledDataSource.setPassword("SA");
|
||||
comboPooledDataSource.setMinPoolSize(5);
|
||||
comboPooledDataSource.setAcquireIncrement(5);
|
||||
comboPooledDataSource.setMaxPoolSize(20);
|
||||
|
||||
comboPooledDataSource.setIdleConnectionTestPeriod(60 * 5);
|
||||
comboPooledDataSource.setMinPoolSize(3);
|
||||
comboPooledDataSource.setInitialPoolSize(3);
|
||||
|
||||
try {
|
||||
comboPooledDataSource.setDriverClass( "org.h2.Driver" ); //loads the jdbc driver
|
||||
} catch (PropertyVetoException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
|
||||
ResultSet rs = null;
|
||||
Connection connection = null;
|
||||
try {
|
||||
connection = comboPooledDataSource.getConnection();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
Statement stmt = null;
|
||||
try {
|
||||
connection = DBUtil.getConnection();
|
||||
rs = connection.getMetaData().getTables(null, null, "t_user_setting", null );
|
||||
if (!rs.next()) {
|
||||
List<String> creatsqls = getCreateSql();
|
||||
for (String createsql : creatsqls) {
|
||||
if (StringUtil.isNullOrEmpty(createsql)) {
|
||||
break;
|
||||
}
|
||||
stmt = connection.createStatement();
|
||||
if (0 != stmt.executeLargeUpdate(createsql)) {
|
||||
LOG.error("创建表失败! {}", createsql);
|
||||
// System.exit(-1);
|
||||
}
|
||||
try {
|
||||
stmt.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
} finally {
|
||||
DBUtil.closeDB(connection, null, rs);
|
||||
}
|
||||
} else {
|
||||
comboPooledDataSource = new ComboPooledDataSource("mysql");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static List<String> getCreateSql() {
|
||||
List<String> out = new ArrayList<>();
|
||||
try{
|
||||
BufferedReader br = new BufferedReader(new FileReader("h2/create_table.sql"));//构造一个BufferedReader类来读取文件
|
||||
String s = null;
|
||||
StringBuilder result = new StringBuilder();
|
||||
while((s = br.readLine())!=null) {
|
||||
result.append(s);
|
||||
if (s.contains(";")) {
|
||||
out.add(result.toString());
|
||||
result = new StringBuilder();
|
||||
}
|
||||
}
|
||||
br.close();
|
||||
}catch(Exception e){
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
//从数据源中获取数据库的连接
|
||||
public static Connection getConnection() throws SQLException {
|
||||
long threadId = Thread.currentThread().getId();
|
||||
|
||||
if (map.get(threadId) != null) {
|
||||
LOG.error("error here!!!! DB connection not close correctly");
|
||||
}
|
||||
map.put(threadId, Thread.currentThread().getStackTrace().toString());
|
||||
Connection connection = transactionConnection.get();
|
||||
if (connection != null) {
|
||||
LOG.debug("Thread {} get db connection {}", threadId, connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
connection = comboPooledDataSource.getConnection();
|
||||
LOG.debug("Thread {} get db connection {}", threadId, connection);
|
||||
return connection;
|
||||
}
|
||||
|
||||
public static void beginTransaction() {
|
||||
try {
|
||||
Connection connection = getConnection();
|
||||
connection.setAutoCommit(false);
|
||||
transactionConnection.set(connection);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void commit() {
|
||||
try {
|
||||
Connection connection = transactionConnection.get();
|
||||
if (connection != null) {
|
||||
connection.commit();
|
||||
connection.setAutoCommit(true);
|
||||
transactionConnection.remove();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void roolback() {
|
||||
try {
|
||||
Connection connection = transactionConnection.get();
|
||||
if (connection != null) {
|
||||
connection.rollback();
|
||||
connection.setAutoCommit(true);
|
||||
transactionConnection.remove();
|
||||
};
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
|
||||
//释放资源,将数据库连接还给数据库连接池
|
||||
public static void closeDB(Connection conn,PreparedStatement ps,ResultSet rs) {
|
||||
LOG.debug("Thread {} release db connection {}", Thread.currentThread().getId(), conn);
|
||||
try {
|
||||
if (rs!=null) {
|
||||
rs.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (ps!=null) {
|
||||
ps.close();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (conn!=null && transactionConnection.get() != conn) {
|
||||
conn.close();
|
||||
map.remove(Thread.currentThread().getId());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
//释放资源,将数据库连接还给数据库连接池
|
||||
public static void closeDB(Connection conn, PreparedStatement ps) {
|
||||
LOG.debug("Thread {} release db connection {}", Thread.currentThread().getId(), conn);
|
||||
try {
|
||||
if (ps!=null) {
|
||||
ps.close();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
|
||||
try {
|
||||
if (conn!=null && transactionConnection.get() != conn) {
|
||||
conn.close();
|
||||
map.remove(Thread.currentThread().getId());
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* This file is part of the Wildfire Chat package.
|
||||
* (c) Heavyrain2012 <[email protected]>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
package win.liyufan.im;
|
||||
|
||||
public enum ErrorCode {
|
||||
//General error
|
||||
ERROR_CODE_SUCCESS(0, "success"),
|
||||
ERROR_CODE_SECRECT_KEY_MISMATCH(1, "secrect key mismatch"),
|
||||
ERROR_CODE_INVALID_DATA(2, "invalid data"),
|
||||
ERROR_CODE_NODE_NOT_EXIST(3, "node not exist"),
|
||||
ERROR_CODE_SERVER_ERROR(4, "server error"),
|
||||
ERROR_CODE_NOT_MODIFIED(5, "not modified"),
|
||||
|
||||
|
||||
//Auth error
|
||||
ERROR_CODE_TOKEN_ERROR(6, "token error"),
|
||||
ERROR_CODE_USER_FORBIDDEN(8, "user forbidden"),
|
||||
|
||||
//Message error
|
||||
ERROR_CODE_NOT_IN_GROUP(9, "not in group"),
|
||||
ERROR_CODE_INVALID_MESSAGE(10, "invalid message"),
|
||||
|
||||
//Group error
|
||||
ERROR_CODE_GROUP_ALREADY_EXIST(11, "group aleady exist"),
|
||||
|
||||
|
||||
//user error
|
||||
ERROR_CODE_PASSWORD_INCORRECT(15, "password incorrect"),
|
||||
|
||||
//user error
|
||||
ERROR_CODE_FRIEND_ALREADY_REQUEST(16, "already send request"),
|
||||
ERROR_CODE_FRIEND_REQUEST_BLOCKED(18, "friend request blocked"),
|
||||
ERROR_CODE_FRIEND_REQUEST_OVERTIME(19, "friend request overtime"),
|
||||
|
||||
ERROR_CODE_NOT_IN_CHATROOM(20, "not in chatroom"),
|
||||
|
||||
ERROR_CODE_NOT_IN_CHANNEL(21, "not in channel"),
|
||||
|
||||
ERROR_CODE_SENSITIVE_MATCHED(242, "sensitive matched"),
|
||||
ERROR_CODE_SIGN_EXPIRED(243, "sign expired"),
|
||||
ERROR_CODE_AUTH_FAILURE(244, "auth failure"),
|
||||
ERROR_CODE_CLIENT_COUNT_OUT_OF_LIMIT(245, "client count out of limit"),
|
||||
ERROR_CODE_IN_BLACK_LIST(246, "user in balck list"),
|
||||
ERROR_CODE_FORBIDDEN_SEND_MSG(247, "forbidden send msg globally"),
|
||||
ERROR_CODE_NOT_RIGHT(248, "no right to operate"),
|
||||
ERROR_CODE_TIMEOUT(249, "timeout"),
|
||||
ERROR_CODE_OVER_FREQUENCY(250, "over frequency"),
|
||||
INVALID_PARAMETER(251, "Invalid parameter"),
|
||||
ERROR_CODE_NOT_EXIST(253, "not exist"),
|
||||
ERROR_CODE_NOT_IMPLEMENT(254, "not implement"),
|
||||
|
||||
|
||||
ERROR_CODE_ASYNC_HANDLER(255, "异步执行,服务器内部逻辑需要此代码,为正常情况,不能返回客户端"),;
|
||||
|
||||
public int code;
|
||||
public String msg;
|
||||
|
||||
ErrorCode(int code, String msg) {
|
||||
this.code = code;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public static ErrorCode fromCode(int code) {
|
||||
for (ErrorCode errorCode : ErrorCode.values()) {
|
||||
if(errorCode.code == code) {
|
||||
return errorCode;
|
||||
}
|
||||
}
|
||||
return ERROR_CODE_SERVER_ERROR;
|
||||
}
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* 频率限制计数器,由于线程并发问题,并不一定严格准确,但总体可用
|
||||
*/
|
||||
public class FrequencyLimistCounter {
|
||||
|
||||
private final Map<String, Integer> CACHE_MAP = new HashMap<>();
|
||||
private final Map<String, Long> CACHE_TIME_MAP = new HashMap<>();
|
||||
|
||||
private long CACHE_HOLD_TIME = 5 * 1000;
|
||||
|
||||
private int FREQUENCY_LIMIT = 100;
|
||||
|
||||
private final SpinLock mLock = new SpinLock();
|
||||
|
||||
|
||||
private long lastFullScanTime = System.currentTimeMillis();
|
||||
//2个小时全部扫描一次
|
||||
private static final long fullScanDuration = 2*60*60*1000;
|
||||
|
||||
public FrequencyLimistCounter(int limitTimeSec, int limitCount) {
|
||||
this.CACHE_HOLD_TIME = limitTimeSec * 1000;
|
||||
this.FREQUENCY_LIMIT = limitCount;
|
||||
}
|
||||
|
||||
public FrequencyLimistCounter() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 增加对象计数并返回是否超频
|
||||
* @param cacheName
|
||||
* @return ture 超频; false 不超频
|
||||
*/
|
||||
public boolean increaseAndCheck(String cacheName) {
|
||||
mLock.lock();
|
||||
try {
|
||||
tryFullScan();
|
||||
Long cacheHoldTime = CACHE_TIME_MAP.get(cacheName);
|
||||
|
||||
if (cacheHoldTime != null && cacheHoldTime < System.currentTimeMillis()) {
|
||||
CACHE_MAP.remove(cacheName);
|
||||
CACHE_TIME_MAP.remove(cacheName);
|
||||
}
|
||||
|
||||
Integer count = CACHE_MAP.get(cacheName);
|
||||
if (count != null) {
|
||||
CACHE_MAP.put(cacheName, ++count);
|
||||
} else {
|
||||
count = 0;
|
||||
CACHE_MAP.put(cacheName, ++count);
|
||||
CACHE_TIME_MAP.put(cacheName, (System.currentTimeMillis() + CACHE_HOLD_TIME));//缓存失效时间
|
||||
}
|
||||
if (count >= FREQUENCY_LIMIT) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
} finally {
|
||||
mLock.unLock();
|
||||
}
|
||||
}
|
||||
|
||||
//去掉超时的数据,如果在一个低频使用的系统中,会残留大量超时无用的信息
|
||||
private void tryFullScan() {
|
||||
if (System.currentTimeMillis() - lastFullScanTime > fullScanDuration) {
|
||||
lastFullScanTime = System.currentTimeMillis();
|
||||
for (Map.Entry<String, Long> entry : CACHE_TIME_MAP.entrySet()
|
||||
) {
|
||||
if (entry.getValue() < lastFullScanTime) {
|
||||
CACHE_MAP.remove(entry.getKey());
|
||||
CACHE_TIME_MAP.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void main(String[] args) {
|
||||
FrequencyLimistCounter counter = new FrequencyLimistCounter(5, 100);
|
||||
String name = "test";
|
||||
|
||||
for (int i = 0; i < 50; i++) {
|
||||
if(counter.increaseAndCheck(name)) {
|
||||
System.out.println("test failure 1");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(3000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
for (int i = 0; i < 49; i++) {
|
||||
if(counter.increaseAndCheck(name)) {
|
||||
System.out.println("test failure 2");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
if(!counter.increaseAndCheck(name)) {
|
||||
System.out.println("test failure 3");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(5*1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 99; i++) {
|
||||
if(counter.increaseAndCheck(name)) {
|
||||
System.out.println("test failure 4");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(5*1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
for (int i = 0; i < 99; i++) {
|
||||
if(counter.increaseAndCheck(name)) {
|
||||
System.out.println("test failure 5");
|
||||
System.exit(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 win.liyufan.im;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
public class GitRepositoryState {
|
||||
public final String tags;
|
||||
public final String branch;
|
||||
public final String dirty;
|
||||
public final String remoteOriginUrl;
|
||||
|
||||
public final String commitId;
|
||||
public final String commitIdAbbrev;
|
||||
public final String describe;
|
||||
public final String describeShort;
|
||||
public final String commitUserName;
|
||||
public final String commitUserEmail;
|
||||
public final String commitMessageFull;
|
||||
public final String commitMessageShort;
|
||||
public final String commitTime;
|
||||
public final String closestTagName;
|
||||
public final String closestTagCommitCount;
|
||||
|
||||
public final String buildUserName;
|
||||
public final String buildUserEmail;
|
||||
public final String buildTime;
|
||||
public final String buildHost;
|
||||
public final String buildVersion;
|
||||
|
||||
private GitRepositoryState(Properties properties) {
|
||||
this.tags = String.valueOf(properties.get("git.tags"));
|
||||
this.branch = String.valueOf(properties.get("git.branch"));
|
||||
this.dirty = String.valueOf(properties.get("git.dirty"));
|
||||
this.remoteOriginUrl = String.valueOf(properties.get("git.remote.origin.url"));
|
||||
|
||||
this.commitId = String.valueOf(properties.get("git.commit.id.full")); // OR properties.get("git.commit.id") depending on your configuration
|
||||
this.commitIdAbbrev = String.valueOf(properties.get("git.commit.id.abbrev"));
|
||||
this.describe = String.valueOf(properties.get("git.commit.id.describe"));
|
||||
this.describeShort = String.valueOf(properties.get("git.commit.id.describe-short"));
|
||||
this.commitUserName = String.valueOf(properties.get("git.commit.user.name"));
|
||||
this.commitUserEmail = String.valueOf(properties.get("git.commit.user.email"));
|
||||
this.commitMessageFull = String.valueOf(properties.get("git.commit.message.full"));
|
||||
this.commitMessageShort = String.valueOf(properties.get("git.commit.message.short"));
|
||||
this.commitTime = String.valueOf(properties.get("git.commit.time"));
|
||||
this.closestTagName = String.valueOf(properties.get("git.closest.tag.name"));
|
||||
this.closestTagCommitCount = String.valueOf(properties.get("git.closest.tag.commit.count"));
|
||||
|
||||
this.buildUserName = String.valueOf(properties.get("git.build.user.name"));
|
||||
this.buildUserEmail = String.valueOf(properties.get("git.build.user.email"));
|
||||
this.buildTime = String.valueOf(properties.get("git.build.time"));
|
||||
this.buildHost = String.valueOf(properties.get("git.build.host"));
|
||||
this.buildVersion = String.valueOf(properties.get("git.build.version"));
|
||||
}
|
||||
|
||||
public static GitRepositoryState getGitRepositoryState() throws IOException {
|
||||
Properties properties = new Properties();
|
||||
properties.load(new FileInputStream("config/git.properties"));
|
||||
// properties.load(GitRepositoryState.class.getClassLoader().getResourceAsStream("config/git.properties"));
|
||||
GitRepositoryState gitRepositoryState = new GitRepositoryState(properties);
|
||||
return gitRepositoryState;
|
||||
}
|
||||
}
|
||||
@@ -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 win.liyufan.im;
|
||||
|
||||
import io.netty.util.internal.StringUtil;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.params.CoreConnectionPNames;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
|
||||
public class HttpUtils {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(HttpUtils.class);
|
||||
|
||||
public static boolean httpJsonPost(String url, String jsonStr){
|
||||
boolean isSuccess = false;
|
||||
|
||||
LOG.info("POST to {} with data {}", url, jsonStr);
|
||||
if (StringUtil.isNullOrEmpty(url)) {
|
||||
LOG.error("http post failure with empty url");
|
||||
return false;
|
||||
}
|
||||
|
||||
HttpPost post = null;
|
||||
try {
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
// // 设置超时时间
|
||||
// httpClient.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 2000);
|
||||
// httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);
|
||||
|
||||
post = new HttpPost(url);
|
||||
// 构造消息头
|
||||
post.setHeader("Content-type", "application/json; charset=utf-8");
|
||||
post.setHeader("Connection", "Keep-Alive");
|
||||
|
||||
// 构建消息实体
|
||||
StringEntity entity = new StringEntity(jsonStr, Charset.forName("UTF-8"));
|
||||
entity.setContentEncoding("UTF-8");
|
||||
// 发送Json格式的数据请求
|
||||
entity.setContentType("application/json");
|
||||
post.setEntity(entity);
|
||||
|
||||
HttpResponse response = httpClient.execute(post);
|
||||
|
||||
// 检验返回码
|
||||
int statusCode = response.getStatusLine().getStatusCode();
|
||||
if(statusCode != HttpStatus.SC_OK){
|
||||
LOG.info("请求出错: "+statusCode);
|
||||
isSuccess = false;
|
||||
}else{
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(response.getEntity()
|
||||
.getContent(),"utf-8"));
|
||||
StringBuffer sb = new StringBuffer("");
|
||||
String line = "";
|
||||
String NL = System.getProperty("line.separator");
|
||||
while ((line = in.readLine()) != null) {
|
||||
sb.append(line + NL);
|
||||
}
|
||||
|
||||
in.close();
|
||||
|
||||
String content = sb.toString();
|
||||
LOG.info("http request response content: {}", content);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
Utility.printExecption(LOG, e);
|
||||
isSuccess = false;
|
||||
}finally{
|
||||
if(post != null){
|
||||
post.releaseConnection();
|
||||
}
|
||||
}
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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 win.liyufan.im;
|
||||
|
||||
public class IDUtils {
|
||||
private static char getChar(int number) {
|
||||
if (number < 0 || number >= 64) {
|
||||
number = number % 64;
|
||||
}
|
||||
if (number < 26) {
|
||||
return (char)('A' + number);
|
||||
} else if(number < 52) {
|
||||
return (char)('a' + number - 26);
|
||||
} else if(number < 62) {
|
||||
return (char)('0' + number - 52);
|
||||
} else if(number == 62) {
|
||||
return '_';
|
||||
}
|
||||
return '-';
|
||||
}
|
||||
|
||||
private static int getNumber(char ch) {
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z') {
|
||||
return ch - 'A';
|
||||
} else if(ch >= 'a' && ch <= 'z') {
|
||||
return ch - 'a' + 26;
|
||||
} else if(ch >= '0' && ch <= '9') {
|
||||
return ch - '0' + 52;
|
||||
} else if(ch == '_') {
|
||||
return 62;
|
||||
}
|
||||
return 63;
|
||||
}
|
||||
|
||||
public static String toUid(int id) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int rand0 = 0;
|
||||
int rand3 = 0;
|
||||
int rand6 = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0 || i == 3 || i == 6) {
|
||||
int rand = (int)(Math.random()*64+0.5);
|
||||
sb.append(getChar(rand));
|
||||
if (i == 0) {
|
||||
rand0 = rand;
|
||||
} else if (i == 3) {
|
||||
rand3 = rand;
|
||||
} else {
|
||||
rand6 = rand;
|
||||
}
|
||||
} else {
|
||||
if (i < 5) {
|
||||
sb.append(getChar((id + rand0) % 64));
|
||||
} else if(i == 5) {
|
||||
sb.append(getChar((id + rand3) % 64));
|
||||
} else {
|
||||
sb.append(getChar((id + rand6) % 64));
|
||||
}
|
||||
id = id / 64;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static int fromUid(String uid) {
|
||||
int id = 0;
|
||||
int rand0 = 0;
|
||||
int rand3 = 0;
|
||||
int rand6 = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (i == 0 || i == 3 || i == 6) {
|
||||
int rand = getNumber(uid.charAt(i));
|
||||
if (i == 0) {
|
||||
rand0 = rand;
|
||||
} else if (i == 3) {
|
||||
rand3 = rand;
|
||||
} else {
|
||||
rand6 = rand;
|
||||
}
|
||||
} else {
|
||||
int c = getNumber(uid.charAt(i));
|
||||
|
||||
if (i < 5) {
|
||||
c = (c+64-rand0)%64;
|
||||
} else if(i == 5) {
|
||||
c = (c+64-rand3)%64;
|
||||
} else {
|
||||
c = (c+64-rand6)%64;
|
||||
}
|
||||
if (i < 3)
|
||||
id = id + (c << (i-1)*6);
|
||||
else if(i < 6)
|
||||
id = id + (c << (i-2)*6);
|
||||
else
|
||||
id = id + (c << (i-3)*6);
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
for (int i = 0; i < 100000000; i++) {
|
||||
String uid = toUid(i);
|
||||
System.out.println(i + ", " + uid + ", " + fromUid(uid));
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -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 win.liyufan.im;
|
||||
|
||||
public interface IMTopic {
|
||||
String SendMessageTopic = "MS";
|
||||
String RecallMessageTopic = "MR";
|
||||
String PullMessageTopic = "MP";
|
||||
String NotifyMessageTopic = "MN";
|
||||
String NotifyRecallMessageTopic = "RMN";
|
||||
|
||||
String GetUserSettingTopic = "UG";
|
||||
String PutUserSettingTopic = "UP";
|
||||
String NotifyUserSettingTopic = "UN";
|
||||
|
||||
String CreateGroupTopic = "GC";
|
||||
String AddGroupMemberTopic = "GAM";
|
||||
String KickoffGroupMemberTopic = "GKM";
|
||||
String QuitGroupTopic = "GQ";
|
||||
String DismissGroupTopic = "GD";
|
||||
String ModifyGroupInfoTopic = "GMI";
|
||||
String ModifyGroupAliasTopic = "GMA";
|
||||
String GetGroupInfoTopic = "GPGI";
|
||||
String GetGroupMemberTopic = "GPGM";
|
||||
String TransferGroupTopic = "GTG";
|
||||
|
||||
|
||||
String GetUserInfoTopic = "UPUI";
|
||||
String ModifyMyInfoTopic = "MMI";
|
||||
|
||||
String GetQiniuUploadTokenTopic = "GQNUT";
|
||||
|
||||
String AddFriendRequestTopic = "FAR";
|
||||
String HandleFriendRequestTopic = "FHR";
|
||||
String FriendRequestPullTopic = "FRP";
|
||||
String NotifyFriendRequestTopic = "FRN";
|
||||
String RriendRequestUnreadSyncTopic = "FRUS";
|
||||
|
||||
String DeleteFriendTopic = "FDL";
|
||||
String FriendPullTopic = "FP";
|
||||
String NotifyFriendTopic = "FN";
|
||||
String BlackListUserTopic = "BLU";
|
||||
|
||||
String UploadDeviceTokenTopic = "UDT";
|
||||
|
||||
String UserSearchTopic = "US";
|
||||
|
||||
String JoinChatroomTopic = "CRJ";
|
||||
String QuitChatroomTopic = "CRQ";
|
||||
String GetChatroomInfoTopic = "CRI";
|
||||
String GetChatroomMemberTopic = "CRMI";
|
||||
|
||||
String RouteTopic = "ROUTE";
|
||||
|
||||
String CreateChannelTopic = "CHC";
|
||||
String ModifyChannelInfoTopic = "CHMI";
|
||||
String TransferChannelInfoTopic = "CHT";
|
||||
String DestoryChannelInfoTopic = "CHD";
|
||||
String ChannelSearchTopic = "CHS";
|
||||
String ChannelListenTopic = "CHL";
|
||||
String ChannelPullTopic = "CHP";
|
||||
|
||||
String GetTokenTopic = "GETTOKEN";
|
||||
}
|
||||
+70
@@ -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 win.liyufan.im;
|
||||
|
||||
import cn.wildfirechat.proto.WFCMessage;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
||||
public class MessageBundle implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -8959293027687263752L;
|
||||
private String fromUser;
|
||||
private String fromClientId;
|
||||
private int type;
|
||||
private int line;
|
||||
private String targetId;
|
||||
private WFCMessage.Message message;
|
||||
private long messageId;
|
||||
|
||||
public MessageBundle() {
|
||||
}
|
||||
|
||||
public MessageBundle(long messageId, String fromUser, String fromClientId, WFCMessage.Message message) {
|
||||
super();
|
||||
this.fromUser = fromUser;
|
||||
this.fromClientId = fromClientId;
|
||||
this.type = message.getConversation().getType();
|
||||
this.targetId = message.getConversation().getTarget();
|
||||
this.line = message.getConversation().getLine();
|
||||
this.message = message;
|
||||
this.messageId = messageId;
|
||||
}
|
||||
|
||||
public int getLine() {
|
||||
return line;
|
||||
}
|
||||
|
||||
public long getMessageId() {
|
||||
return messageId;
|
||||
}
|
||||
|
||||
public String getFromUser() {
|
||||
return fromUser;
|
||||
}
|
||||
public String getFromClientId() {
|
||||
return fromClientId;
|
||||
}
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
public String getTargetId() {
|
||||
return targetId;
|
||||
}
|
||||
public WFCMessage.Message getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(WFCMessage.Message message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -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 win.liyufan.im;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class MessageShardingUtil {
|
||||
private static SpinLock mLock = new SpinLock();
|
||||
private static int rotateId = 0;
|
||||
private static int nodeId = 0;
|
||||
|
||||
private static int rotateIdWidth = 15;
|
||||
private static int rotateIdMask = 0x7FFF;
|
||||
|
||||
private static int nodeIdWidth = 6;
|
||||
private static int nodeIdMask = 0x3F;
|
||||
|
||||
private static final long T201801010000 = 1514736000000L;
|
||||
|
||||
public static void setNodeId(int nodeId) {
|
||||
MessageShardingUtil.nodeId = nodeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* ID = timestamp(43) + nodeId(6) + rotateId(15)
|
||||
* 所以时间限制是到2157/5/15(2的42次幂代表的时间 + (2018-1970))。节点数限制是小于64,每台服务器每毫秒最多发送32768条消息
|
||||
* @return
|
||||
*/
|
||||
public static long generateId() {
|
||||
mLock.lock();
|
||||
rotateId = (rotateId + 1)&rotateIdMask;
|
||||
mLock.unLock();
|
||||
|
||||
long id = System.currentTimeMillis() - T201801010000;
|
||||
|
||||
|
||||
id <<= nodeIdWidth;
|
||||
id += (nodeId & nodeIdMask);
|
||||
|
||||
id <<= rotateIdWidth;
|
||||
id += rotateId;
|
||||
return id;
|
||||
}
|
||||
|
||||
public static String getMessageTable(long mid) {
|
||||
if (DBUtil.IsEmbedDB) {
|
||||
return "t_messages";
|
||||
}
|
||||
|
||||
mid >>= (nodeIdWidth + rotateIdWidth);
|
||||
Date date = new Date(mid + T201801010000);
|
||||
int month = date.getMonth();
|
||||
int year = date.getYear();
|
||||
year %= 3;
|
||||
return "t_messages_" + (year * 12 + month);
|
||||
}
|
||||
}
|
||||
+21
@@ -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 win.liyufan.im;
|
||||
|
||||
public interface MyInfoType {
|
||||
int Modify_DisplayName = 0;
|
||||
int Modify_Portrait = 1;
|
||||
int Modify_Gender = 2;
|
||||
int Modify_Mobile = 3;
|
||||
int Modify_Email = 4;
|
||||
int Modify_Address = 5;
|
||||
int Modify_Company = 6;
|
||||
int Modify_Social = 7;
|
||||
int Modify_Extra = 8;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 漏桶算法
|
||||
* capacity * 1000是为了更精确, 漏水的小洞更小^~^
|
||||
*/
|
||||
public class RateLimiter {
|
||||
private static final int DEFAULT_LIMIT_TIME_SECOND = 5;
|
||||
private static final int DEFAULT_LIMIT_COUNT = 100;
|
||||
private static final long expire = 2 * 60 * 60 * 1000;
|
||||
private double rate = (double) DEFAULT_LIMIT_COUNT / (DEFAULT_LIMIT_TIME_SECOND);
|
||||
private long capacity = DEFAULT_LIMIT_COUNT * 1000;
|
||||
private long lastCleanTime;
|
||||
private Map<String, Long> requestCountMap = new HashMap<>();
|
||||
private Map<String, Long> requestTimeMap = new HashMap<>();
|
||||
|
||||
private SpinLock lock = new SpinLock();
|
||||
|
||||
public RateLimiter() {
|
||||
|
||||
}
|
||||
|
||||
public RateLimiter(int limitTimeSecond, int limitCount) {
|
||||
if (limitTimeSecond <= 0 || limitCount <= 0) {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
this.capacity = limitCount * 1000;
|
||||
this.rate = (double) limitCount / limitTimeSecond;
|
||||
}
|
||||
|
||||
/**
|
||||
* 漏桶算法,https://en.wikipedia.org/wiki/Leaky_bucket
|
||||
*/
|
||||
public boolean isGranted(String userId) {
|
||||
try {
|
||||
lock.lock();
|
||||
long current = System.currentTimeMillis();
|
||||
cleanUp(current);
|
||||
Long lastRequestTime = requestTimeMap.get(userId);
|
||||
long count = 0;
|
||||
if (lastRequestTime == null) {
|
||||
count += 1000;
|
||||
requestTimeMap.put(userId, current);
|
||||
requestCountMap.put(userId, count);
|
||||
return true;
|
||||
} else {
|
||||
count = requestCountMap.get(userId);
|
||||
lastRequestTime = requestTimeMap.get(userId);
|
||||
count -= (current - lastRequestTime) * rate;
|
||||
count = count > 0 ? count : 0;
|
||||
requestTimeMap.put(userId, current);
|
||||
if (count < capacity) {
|
||||
count += 1000;
|
||||
requestCountMap.put(userId, count);
|
||||
return true;
|
||||
} else {
|
||||
requestCountMap.put(userId, count);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
lock.unLock();
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanUp(long current) {
|
||||
if (current - lastCleanTime > expire) {
|
||||
for (Iterator<Map.Entry<String, Long>> it = requestTimeMap.entrySet().iterator(); it.hasNext();) {
|
||||
Map.Entry<String, Long> entry = it.next();
|
||||
if (entry.getValue() < current - expire) {
|
||||
it.remove();
|
||||
requestCountMap.remove(entry.getKey());
|
||||
}
|
||||
}
|
||||
lastCleanTime = current;
|
||||
}
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
RateLimiter limiter = new RateLimiter(1, 10);
|
||||
long start = System.currentTimeMillis();
|
||||
for (int i = 0; i < 53; i++) {
|
||||
if (!limiter.isGranted("test")) {
|
||||
System.out.println("1 too frequency " + i);
|
||||
}
|
||||
}
|
||||
Thread.sleep(1 * 1000);
|
||||
System.out.println("sleep 1 s");
|
||||
for (int i = 0; i < 53; i++) {
|
||||
if (!limiter.isGranted("test")) {
|
||||
System.out.println("2 too frequency " + i);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
System.out.println("sleep 5 s");
|
||||
for (int i = 0; i < 53; i++) {
|
||||
if (!limiter.isGranted("test")) {
|
||||
System.out.println("3 too frequency " + i);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.sleep(5 * 1000);
|
||||
System.out.println("sleep 5 s");
|
||||
long second = System.currentTimeMillis();
|
||||
for (int i = 0; i < 100; i++) {
|
||||
if (!limiter.isGranted("test")) {
|
||||
System.out.println("4 too frequency " + i);
|
||||
}
|
||||
Thread.sleep(50);
|
||||
}
|
||||
System.out.println("second: " + (System.currentTimeMillis() - second));
|
||||
System.out.println("end: " + (System.currentTimeMillis() - start));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SensitiveFilter {
|
||||
public enum MatchType {
|
||||
MIN_MATCH("最小匹配规则"),MAX_MATCH("最大匹配规则");
|
||||
|
||||
String desc;
|
||||
MatchType(String desc) {
|
||||
this.desc = desc;
|
||||
}
|
||||
}
|
||||
|
||||
private Map<Object,Object> sensitiveWordsMap;
|
||||
|
||||
private static final String END_FLAG="end";
|
||||
|
||||
public static void main(String[] args) {
|
||||
Set<String> sensitiveWords=new HashSet<>();
|
||||
sensitiveWords.add("你是傻逼");
|
||||
sensitiveWords.add("你是傻逼啊");
|
||||
sensitiveWords.add("你是坏蛋");
|
||||
sensitiveWords.add("你个大笨蛋");
|
||||
sensitiveWords.add("我去年买了个表");
|
||||
sensitiveWords.add("shit");
|
||||
|
||||
SensitiveFilter textFilter=new SensitiveFilter(sensitiveWords);
|
||||
String text="你你你你是傻逼啊你,说你呢,你个大笨蛋。";
|
||||
System.out.println(textFilter.getSensitiveWords(text,MatchType.MAX_MATCH));
|
||||
for (int i = 0; i < 100; i++) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.out.println(textFilter.getSensitiveWords(text,MatchType.MAX_MATCH));
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000 * 100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isContainSensitiveWord(String text){
|
||||
Set<String> sensitiveWords = getSensitiveWords(text, MatchType.MIN_MATCH);
|
||||
if(sensitiveWords!=null&&sensitiveWords.size()>0){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public Set<String> getSensitiveWords(String text,MatchType matchType){
|
||||
Set<String> sensitiveWords=new HashSet<>();
|
||||
if(text==null||text.trim().length()==0){
|
||||
return sensitiveWords;
|
||||
}
|
||||
|
||||
for(int i=0;i<text.length();i++){
|
||||
int sensitiveWordLength = getSensitiveWordLength(text, i, matchType);
|
||||
if(sensitiveWordLength>0){
|
||||
String sensitiveWord = text.substring(i, i + sensitiveWordLength);
|
||||
sensitiveWords.add(sensitiveWord);
|
||||
if(matchType==MatchType.MIN_MATCH){
|
||||
break;
|
||||
}
|
||||
i=i+sensitiveWordLength-1;
|
||||
}
|
||||
}
|
||||
return sensitiveWords;
|
||||
}
|
||||
|
||||
public int getSensitiveWordLength(String text,int startIndex,MatchType matchType){
|
||||
if(text==null||text.trim().length()==0){
|
||||
throw new IllegalArgumentException("The input text must not be empty.");
|
||||
}
|
||||
char currentChar;
|
||||
Map<Object,Object> currentMap=sensitiveWordsMap;
|
||||
int wordLength=0;
|
||||
boolean endFlag=false;
|
||||
for(int i=startIndex;i<text.length();i++){
|
||||
currentChar=text.charAt(i);
|
||||
Map<Object,Object> subMap=(Map<Object,Object>) currentMap.get(currentChar);
|
||||
if(subMap==null){
|
||||
break;
|
||||
}else {
|
||||
wordLength++;
|
||||
if(subMap.containsKey(END_FLAG)){
|
||||
endFlag=true;
|
||||
if(matchType==MatchType.MIN_MATCH){
|
||||
break;
|
||||
}else {
|
||||
currentMap=subMap;
|
||||
}
|
||||
}else {
|
||||
currentMap=subMap;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!endFlag){
|
||||
wordLength=0;
|
||||
}
|
||||
return wordLength;
|
||||
}
|
||||
|
||||
|
||||
public SensitiveFilter(Set<String> sensitiveWords){
|
||||
sensitiveWordsMap=new ConcurrentHashMap<>(sensitiveWords.size());
|
||||
if(sensitiveWords==null||sensitiveWords.isEmpty()){
|
||||
//throw new IllegalArgumentException("Senditive words must not be empty!");
|
||||
return;
|
||||
}
|
||||
|
||||
String currentWord;
|
||||
Map<Object,Object> currentMap;
|
||||
Map<Object,Object> subMap;
|
||||
Iterator<String> iterator = sensitiveWords.iterator();
|
||||
while (iterator.hasNext()){
|
||||
currentWord=iterator.next();
|
||||
if(currentWord==null||currentWord.trim().length()<2){ //敏感词长度必须大于等于2
|
||||
continue;
|
||||
}
|
||||
currentMap=sensitiveWordsMap;
|
||||
for(int i=0;i<currentWord.length();i++){
|
||||
char c=currentWord.charAt(i);
|
||||
subMap=(Map<Object, Object>) currentMap.get(c);
|
||||
if(subMap==null){
|
||||
subMap=new HashMap<>();
|
||||
currentMap.put(c,subMap);
|
||||
currentMap=subMap;
|
||||
}else {
|
||||
currentMap= subMap;
|
||||
}
|
||||
if(i==currentWord.length()-1){
|
||||
//如果是最后一个字符,则put一个结束标志,这里只需要保存key就行了,value为null可以节省空间。
|
||||
//如果不是最后一个字符,则不需要存这个结束标志,同样也是为了节省空间。
|
||||
currentMap.put(END_FLAG,null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class SpinLock {
|
||||
//java中原子(CAS)操作
|
||||
AtomicReference<Thread> owner = new AtomicReference<>();//持有自旋锁的线程对象
|
||||
private int count;
|
||||
public void lock() {
|
||||
Thread cur = Thread.currentThread();
|
||||
//lock函数将owner设置为当前线程,并且预测原来的值为空。unlock函数将owner设置为null,并且预测值为当前线程。当有第二个线程调用lock操作时由于owner值不为空,导致循环
|
||||
|
||||
//一直被执行,直至第一个线程调用unlock函数将owner设置为null,第二个线程才能进入临界区。
|
||||
while (!owner.compareAndSet(null, cur)){
|
||||
}
|
||||
}
|
||||
public void unLock() {
|
||||
Thread cur = Thread.currentThread();
|
||||
owner.compareAndSet(cur, null);
|
||||
}
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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 win.liyufan.im;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class UUIDGenerator {
|
||||
|
||||
public static String getUUID() {
|
||||
UUID uuid = UUID.randomUUID();
|
||||
String str = uuid.toString();
|
||||
|
||||
str = str.replace("-", "");
|
||||
return str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package win.liyufan.im;
|
||||
|
||||
public interface UserSettingScope {
|
||||
int kUserSettingConversationSilent = 1;
|
||||
int kUserSettingGlobalSilent = 2;
|
||||
int kUserSettingConversationTop = 3;
|
||||
|
||||
int kUserSettingHiddenNotificationDetail = 4;
|
||||
int kUserSettinGroupHideNickname = 5;
|
||||
int kUserSettingFavouriteGroup = 6;
|
||||
int kUserSettingConversationSync = 7;
|
||||
int kUserSettingMyChannels = 8;
|
||||
int kUserSettingListenedChannels = 9;
|
||||
|
||||
int kUserSettingCustomBegin = 1000;
|
||||
}
|
||||
@@ -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 win.liyufan.im;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.net.*;
|
||||
import java.util.Enumeration;
|
||||
|
||||
public class Utility {
|
||||
public static InetAddress getLocalAddress(){
|
||||
try {
|
||||
Enumeration<NetworkInterface> b = NetworkInterface.getNetworkInterfaces();
|
||||
while( b.hasMoreElements()){
|
||||
for ( InterfaceAddress f : b.nextElement().getInterfaceAddresses())
|
||||
if ( f.getAddress().isSiteLocalAddress())
|
||||
return f.getAddress();
|
||||
}
|
||||
} catch (SocketException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void printExecption(Logger LOG, Exception e) {
|
||||
String message = "";
|
||||
|
||||
for(StackTraceElement stackTraceElement : e.getStackTrace()) {
|
||||
message = message + System.lineSeparator() + stackTraceElement.toString();
|
||||
}
|
||||
LOG.error("Exception: {}", e.getMessage());
|
||||
LOG.error(message);
|
||||
}
|
||||
|
||||
public static String getMacAddress() throws UnknownHostException,
|
||||
SocketException {
|
||||
InetAddress ipAddress = InetAddress.getLocalHost();
|
||||
NetworkInterface networkInterface = NetworkInterface
|
||||
.getByInetAddress(ipAddress);
|
||||
byte[] macAddressBytes = networkInterface.getHardwareAddress();
|
||||
StringBuilder macAddressBuilder = new StringBuilder();
|
||||
|
||||
for (int macAddressByteIndex = 0; macAddressByteIndex < macAddressBytes.length; macAddressByteIndex++) {
|
||||
String macAddressHexByte = String.format("%02X",
|
||||
macAddressBytes[macAddressByteIndex]);
|
||||
macAddressBuilder.append(macAddressHexByte);
|
||||
|
||||
if (macAddressByteIndex != macAddressBytes.length - 1)
|
||||
{
|
||||
macAddressBuilder.append(":");
|
||||
}
|
||||
}
|
||||
|
||||
return macAddressBuilder.toString();
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package win.liyufan.im.extended.mqttmessage;
|
||||
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.handler.codec.mqtt.MqttFixedHeader;
|
||||
import io.netty.handler.codec.mqtt.MqttMessage;
|
||||
import io.netty.handler.codec.mqtt.MqttMessageIdVariableHeader;
|
||||
|
||||
public class ModifiedMqttPubAckMessage extends MqttMessage {
|
||||
public ModifiedMqttPubAckMessage(MqttFixedHeader mqttFixedHeader, MqttMessageIdVariableHeader variableHeader, ByteBuf payload) {
|
||||
super(mqttFixedHeader, variableHeader, payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MqttMessageIdVariableHeader variableHeader() {
|
||||
return (MqttMessageIdVariableHeader) super.variableHeader();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user